/src/tinyobjloader/tiny_obj_c_impl.inc
Line | Count | Source |
1 | | /* |
2 | | * tiny_obj_c_impl.inc -- per-precision OBJ parser + scene teardown. |
3 | | * |
4 | | * Included twice from tiny_obj_c.c with (TOBJ_REAL, TOBJ_SUF) = (float, _f) |
5 | | * and (double, _d). Every file-scope name is suffixed via TOBJ_T() so the two |
6 | | * inclusions do not collide in the single translation unit. Do not include |
7 | | * directly. |
8 | | */ |
9 | | |
10 | | /* ----------------------------------------------------------------------- */ |
11 | | /* builder */ |
12 | | /* ----------------------------------------------------------------------- */ |
13 | | |
14 | | typedef struct TOBJ_T(tobj_builder) { |
15 | | const tobj_allocator *alloc; |
16 | | tobj_arena *arena; |
17 | | tobj_diag *diag; |
18 | | const tobj_load_config *cfg; |
19 | | tobj_caps caps; |
20 | | tobj_result err; |
21 | | size_t line; /* 1-based current line for diagnostics */ |
22 | | |
23 | | bool triangulate; |
24 | | |
25 | | /* attrib temp vectors (reals / structs) */ |
26 | | tobj_vec av; /* vertices xyz */ |
27 | | tobj_vec avw; /* vertex weights (lazy) */ |
28 | | tobj_vec avn; /* normals xyz */ |
29 | | tobj_vec avt; /* texcoords uv */ |
30 | | tobj_vec avtw; /* texcoord w (lazy) */ |
31 | | tobj_vec acol; /* colors rgb (lazy) */ |
32 | | bool color_seen; |
33 | | |
34 | | /* materials + name->id map (filled by the .mtl parser) */ |
35 | | tobj_vec materials; /* TOBJ_T(tobj_material) */ |
36 | | tobj_vec matmap_key; /* const char* (interned) */ |
37 | | tobj_vec matmap_id; /* int */ |
38 | | tobj_vec mat_unknown; /* tobj_pending_kv */ |
39 | | |
40 | | /* finalized shapes */ |
41 | | tobj_vec shapes; /* TOBJ_T(tobj_shape) */ |
42 | | |
43 | | /* current shape accumulation */ |
44 | | const char *cur_name; |
45 | | bool cur_has_prims; |
46 | | tobj_vec m_idx; /* tobj_index */ |
47 | | tobj_vec m_fv; /* unsigned face-vertex counts */ |
48 | | tobj_vec m_mid; /* int material ids */ |
49 | | tobj_vec m_sg; /* unsigned smoothing ids */ |
50 | | tobj_vec l_idx; /* tobj_index */ |
51 | | tobj_vec l_cnt; /* int per-line counts */ |
52 | | tobj_vec p_idx; /* tobj_index */ |
53 | | |
54 | | /* per-face scratch (reused) */ |
55 | | tobj_vec corners; /* tobj_index */ |
56 | | tobj_vec ringpos; /* TOBJ_REAL */ |
57 | | tobj_vec tris; /* uint32_t */ |
58 | | tobj_vec tscratch; /* uint8_t */ |
59 | | |
60 | | /* free-form geometry (only used when cfg->parse_freeform) */ |
61 | | tobj_vec ff_vp; /* reals (global parameter vertices) */ |
62 | | int ff_vp_comps; |
63 | | bool ff_present; /* any free-form element in current shape */ |
64 | | bool ff_active; /* between curv/curv2/surf and end */ |
65 | | int ff_kind; /* 1=curv 2=curv2 3=surf */ |
66 | | tobj_cstype ff_cstype; |
67 | | bool ff_rational; |
68 | | int ff_degu, ff_degv; |
69 | | TOBJ_REAL ff_u0, ff_u1, ff_s0, ff_s1, ff_t0, ff_t1; |
70 | | tobj_vec ff_cp_int; /* int control points (curv: v idx, curv2: vp idx) */ |
71 | | tobj_vec ff_cp_idx; /* tobj_index control points (surf) */ |
72 | | tobj_vec ff_knu; /* reals (parm u) */ |
73 | | tobj_vec ff_knv; /* reals (parm v) */ |
74 | | tobj_vec ff_trim; /* TOBJ_T(tobj_trim_loop) */ |
75 | | tobj_vec ff_hole; |
76 | | tobj_vec ff_scrv; |
77 | | tobj_vec sh_curves; /* TOBJ_T(tobj_curve) */ |
78 | | tobj_vec sh_curves2; /* TOBJ_T(tobj_curve2) */ |
79 | | tobj_vec sh_surfaces; /* TOBJ_T(tobj_surface) */ |
80 | | |
81 | | /* parser state */ |
82 | | int cur_material; |
83 | | unsigned cur_smooth; |
84 | | |
85 | | /* multithreading pass 2: vertices already parsed; indices resolve against |
86 | | * running counts instead of the (already full) attrib arrays */ |
87 | | bool prefilled; |
88 | | size_t run_numv, run_numvt, run_numvn, run_numvp; |
89 | | } TOBJ_T(tobj_builder); |
90 | | |
91 | | /* Counts used for index fixup: running counts in MT pass 2, else live counts. */ |
92 | 36.2M | static size_t TOBJ_T(cnt_v)(TOBJ_T(tobj_builder) * b) { |
93 | 36.2M | return b->prefilled ? b->run_numv : b->av.count / 3u; |
94 | 36.2M | } Line | Count | Source | 92 | 36.2M | static size_t TOBJ_T(cnt_v)(TOBJ_T(tobj_builder) * b) { | 93 | 36.2M | return b->prefilled ? b->run_numv : b->av.count / 3u; | 94 | 36.2M | } |
Unexecuted instantiation: tiny_obj_c.c:cnt_v_d |
95 | 36.2M | static size_t TOBJ_T(cnt_vt)(TOBJ_T(tobj_builder) * b) { |
96 | 36.2M | return b->prefilled ? b->run_numvt : b->avt.count / 2u; |
97 | 36.2M | } Line | Count | Source | 95 | 36.2M | static size_t TOBJ_T(cnt_vt)(TOBJ_T(tobj_builder) * b) { | 96 | 36.2M | return b->prefilled ? b->run_numvt : b->avt.count / 2u; | 97 | 36.2M | } |
Unexecuted instantiation: tiny_obj_c.c:cnt_vt_d |
98 | 36.2M | static size_t TOBJ_T(cnt_vn)(TOBJ_T(tobj_builder) * b) { |
99 | 36.2M | return b->prefilled ? b->run_numvn : b->avn.count / 3u; |
100 | 36.2M | } Line | Count | Source | 98 | 36.2M | static size_t TOBJ_T(cnt_vn)(TOBJ_T(tobj_builder) * b) { | 99 | 36.2M | return b->prefilled ? b->run_numvn : b->avn.count / 3u; | 100 | 36.2M | } |
Unexecuted instantiation: tiny_obj_c.c:cnt_vn_d |
101 | | |
102 | 0 | static bool TOBJ_T(b_fail)(TOBJ_T(tobj_builder) * b, tobj_result e) { |
103 | 0 | if (b->err == TOBJ_OK) b->err = e; |
104 | 0 | return false; |
105 | 0 | } Unexecuted instantiation: tiny_obj_c.c:b_fail_f Unexecuted instantiation: tiny_obj_c.c:b_fail_d |
106 | | |
107 | 42.9M | static void TOBJ_T(b_warn)(TOBJ_T(tobj_builder) * b, const char *msg) { |
108 | 42.9M | tobj_diag_append(b->diag, b->alloc, TOBJ_SEV_WARNING, b->line, msg); |
109 | 42.9M | } Line | Count | Source | 107 | 42.9M | static void TOBJ_T(b_warn)(TOBJ_T(tobj_builder) * b, const char *msg) { | 108 | 42.9M | tobj_diag_append(b->diag, b->alloc, TOBJ_SEV_WARNING, b->line, msg); | 109 | 42.9M | } |
Unexecuted instantiation: tiny_obj_c.c:b_warn_d |
110 | | |
111 | | /* ----------------------------------------------------------------------- */ |
112 | | /* index fixup (1-based -> 0-based, negative -> relative) */ |
113 | | /* ----------------------------------------------------------------------- */ |
114 | | |
115 | 2.44M | static bool TOBJ_T(fix_index)(int idx, size_t n, int *out) { |
116 | 2.44M | if (idx > 0) { |
117 | 2.39M | *out = idx - 1; |
118 | 2.39M | return true; |
119 | 2.39M | } |
120 | 51.2k | if (idx == 0) { |
121 | 10.0k | *out = -1; |
122 | 10.0k | return false; /* zero index: invalid per spec */ |
123 | 10.0k | } |
124 | 41.1k | long long r = (long long)n + idx; |
125 | 41.1k | if (r < 0) { |
126 | 17.1k | *out = -1; |
127 | 17.1k | return false; |
128 | 17.1k | } |
129 | 24.0k | *out = (int)r; |
130 | 24.0k | return true; |
131 | 41.1k | } Line | Count | Source | 115 | 2.44M | static bool TOBJ_T(fix_index)(int idx, size_t n, int *out) { | 116 | 2.44M | if (idx > 0) { | 117 | 2.39M | *out = idx - 1; | 118 | 2.39M | return true; | 119 | 2.39M | } | 120 | 51.2k | if (idx == 0) { | 121 | 10.0k | *out = -1; | 122 | 10.0k | return false; /* zero index: invalid per spec */ | 123 | 10.0k | } | 124 | 41.1k | long long r = (long long)n + idx; | 125 | 41.1k | if (r < 0) { | 126 | 17.1k | *out = -1; | 127 | 17.1k | return false; | 128 | 17.1k | } | 129 | 24.0k | *out = (int)r; | 130 | | return true; | 131 | 41.1k | } |
Unexecuted instantiation: tiny_obj_c.c:fix_index_d |
132 | | |
133 | | /* Parse one corner "v[/[vt][/vn]]" against explicit counts. Returns true if a |
134 | | * (possibly relative) vertex index was parsed and is in range. */ |
135 | | static bool TOBJ_T(parse_corner_n)(const char *tok, size_t len, size_t numv, |
136 | | size_t numvt, size_t numvn, |
137 | 36.2M | tobj_index *out) { |
138 | 36.2M | out->vertex_index = -1; |
139 | 36.2M | out->normal_index = -1; |
140 | 36.2M | out->texcoord_index = -1; |
141 | | |
142 | 36.2M | tobj_cursor c; |
143 | 36.2M | tobj_cur_init(&c, tok, len); |
144 | 36.2M | int vi; |
145 | 36.2M | if (!tobj_scan_int(&c.p, c.end, &vi)) return false; |
146 | 36.2M | bool ok = TOBJ_T(fix_index)(vi, numv, &out->vertex_index); |
147 | 2.38M | if (c.p < c.end && *c.p == '/') { |
148 | 1.46M | c.p++; |
149 | 1.46M | if (c.p < c.end && *c.p != '/') { |
150 | 64.9k | int ti; |
151 | 64.9k | if (tobj_scan_int(&c.p, c.end, &ti)) |
152 | 49.5k | TOBJ_T(fix_index)(ti, numvt, &out->texcoord_index); |
153 | 64.9k | } |
154 | 1.46M | if (c.p < c.end && *c.p == '/') { |
155 | 1.39M | c.p++; |
156 | 1.39M | int ni; |
157 | 1.39M | if (tobj_scan_int(&c.p, c.end, &ni)) |
158 | 13.9k | TOBJ_T(fix_index)(ni, numvn, &out->normal_index); |
159 | 1.39M | } |
160 | 1.46M | } |
161 | 2.38M | return ok; |
162 | 36.2M | } tiny_obj_c.c:parse_corner_n_f Line | Count | Source | 137 | 36.2M | tobj_index *out) { | 138 | 36.2M | out->vertex_index = -1; | 139 | 36.2M | out->normal_index = -1; | 140 | 36.2M | out->texcoord_index = -1; | 141 | | | 142 | 36.2M | tobj_cursor c; | 143 | 36.2M | tobj_cur_init(&c, tok, len); | 144 | 36.2M | int vi; | 145 | 36.2M | if (!tobj_scan_int(&c.p, c.end, &vi)) return false; | 146 | 36.2M | bool ok = TOBJ_T(fix_index)(vi, numv, &out->vertex_index); | 147 | 2.38M | if (c.p < c.end && *c.p == '/') { | 148 | 1.46M | c.p++; | 149 | 1.46M | if (c.p < c.end && *c.p != '/') { | 150 | 64.9k | int ti; | 151 | 64.9k | if (tobj_scan_int(&c.p, c.end, &ti)) | 152 | 49.5k | TOBJ_T(fix_index)(ti, numvt, &out->texcoord_index); | 153 | 64.9k | } | 154 | 1.46M | if (c.p < c.end && *c.p == '/') { | 155 | 1.39M | c.p++; | 156 | 1.39M | int ni; | 157 | 1.39M | if (tobj_scan_int(&c.p, c.end, &ni)) | 158 | 13.9k | TOBJ_T(fix_index)(ni, numvn, &out->normal_index); | 159 | 1.39M | } | 160 | 1.46M | } | 161 | 2.38M | return ok; | 162 | 36.2M | } |
Unexecuted instantiation: tiny_obj_c.c:parse_corner_n_d |
163 | | |
164 | | /* Parse one face/line/point corner using the builder's current counts. */ |
165 | | static void TOBJ_T(parse_corner)(TOBJ_T(tobj_builder) * b, const char *tok, |
166 | 36.2M | size_t len, tobj_index *out) { |
167 | 36.2M | bool ok = TOBJ_T(parse_corner_n)(tok, len, TOBJ_T(cnt_v)(b), |
168 | 36.2M | TOBJ_T(cnt_vt)(b), TOBJ_T(cnt_vn)(b), out); |
169 | 36.2M | if (!ok && out->vertex_index < 0) |
170 | 33.8M | TOBJ_T(b_warn)(b, "tinyobjc: invalid vertex index in face\n"); |
171 | 36.2M | } tiny_obj_c.c:parse_corner_f Line | Count | Source | 166 | 36.2M | size_t len, tobj_index *out) { | 167 | 36.2M | bool ok = TOBJ_T(parse_corner_n)(tok, len, TOBJ_T(cnt_v)(b), | 168 | 36.2M | TOBJ_T(cnt_vt)(b), TOBJ_T(cnt_vn)(b), out); | 169 | 36.2M | if (!ok && out->vertex_index < 0) | 170 | 33.8M | TOBJ_T(b_warn)(b, "tinyobjc: invalid vertex index in face\n"); | 171 | 36.2M | } |
Unexecuted instantiation: tiny_obj_c.c:parse_corner_d |
172 | | |
173 | | /* ----------------------------------------------------------------------- */ |
174 | | /* optional parallel-array helpers (lazy with backfill) */ |
175 | | /* ----------------------------------------------------------------------- */ |
176 | | |
177 | | static bool TOBJ_T(opt_push)(tobj_vec *v, size_t comps, size_t vidx, |
178 | | const TOBJ_REAL *vals, const TOBJ_REAL *deflt, |
179 | 20.0M | bool present, const tobj_allocator *a) { |
180 | 20.0M | if (!present && v->count == 0) return true; /* stay empty */ |
181 | | /* backfill defaults up to vidx entries */ |
182 | 15.4M | while (v->count / comps < vidx) { |
183 | 8.27M | if (!tobj_vec_append(v, deflt, comps, a)) return false; |
184 | 8.27M | } |
185 | 7.13M | const TOBJ_REAL *src = present ? vals : deflt; |
186 | 7.13M | return tobj_vec_append(v, src, comps, a); |
187 | 7.13M | } Line | Count | Source | 179 | 20.0M | bool present, const tobj_allocator *a) { | 180 | 20.0M | if (!present && v->count == 0) return true; /* stay empty */ | 181 | | /* backfill defaults up to vidx entries */ | 182 | 15.4M | while (v->count / comps < vidx) { | 183 | 8.27M | if (!tobj_vec_append(v, deflt, comps, a)) return false; | 184 | 8.27M | } | 185 | 7.13M | const TOBJ_REAL *src = present ? vals : deflt; | 186 | 7.13M | return tobj_vec_append(v, src, comps, a); | 187 | 7.13M | } |
Unexecuted instantiation: tiny_obj_c.c:opt_push_d |
188 | | |
189 | | /* ----------------------------------------------------------------------- */ |
190 | | /* directive handlers */ |
191 | | /* ----------------------------------------------------------------------- */ |
192 | | |
193 | 9.00M | static bool TOBJ_T(handle_v)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { |
194 | 9.00M | double nums[8]; |
195 | 9.00M | int n = 0; |
196 | 9.10M | while (n < 8) { |
197 | 9.10M | double d; |
198 | 9.10M | const char *save = c->p; |
199 | 9.10M | if (!tobj_scan_double(&c->p, c->end, &d)) { |
200 | 9.00M | c->p = save; |
201 | 9.00M | break; |
202 | 9.00M | } |
203 | 103k | nums[n++] = d; |
204 | 103k | } |
205 | 9.00M | if (n < 3) { |
206 | 8.99M | TOBJ_T(b_warn)(b, "tinyobjc: 'v' with fewer than 3 components\n"); |
207 | 35.9M | while (n < 3) nums[n++] = 0.0; |
208 | 8.99M | } |
209 | 9.00M | if (b->av.count / 3u >= b->caps.vertices) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); |
210 | 9.00M | size_t vidx = b->av.count / 3u; |
211 | 9.00M | TOBJ_REAL xyz[3] = {(TOBJ_REAL)nums[0], (TOBJ_REAL)nums[1], (TOBJ_REAL)nums[2]}; |
212 | 9.00M | if (!tobj_vec_append(&b->av, xyz, 3, b->alloc)) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
213 | | |
214 | | /* weight: only the 4-number form carries a vertex weight */ |
215 | 9.00M | bool has_w = (n == 4); |
216 | 9.00M | TOBJ_REAL w = has_w ? (TOBJ_REAL)nums[3] : (TOBJ_REAL)1; |
217 | 9.00M | TOBJ_REAL wdef = (TOBJ_REAL)1; |
218 | 9.00M | if (!TOBJ_T(opt_push)(&b->avw, 1, vidx, &w, &wdef, has_w, b->alloc)) |
219 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
220 | | |
221 | | /* color: the 6/7-number form carries r g b */ |
222 | 9.00M | if (b->cfg->store_vertex_colors) { |
223 | 9.00M | bool has_c = (n >= 6); |
224 | 9.00M | TOBJ_REAL rgb[3]; |
225 | 9.00M | rgb[0] = has_c ? (TOBJ_REAL)nums[3] : (TOBJ_REAL)1; |
226 | 9.00M | rgb[1] = has_c ? (TOBJ_REAL)nums[4] : (TOBJ_REAL)1; |
227 | 9.00M | rgb[2] = has_c ? (TOBJ_REAL)nums[5] : (TOBJ_REAL)1; |
228 | 9.00M | TOBJ_REAL white[3] = {(TOBJ_REAL)1, (TOBJ_REAL)1, (TOBJ_REAL)1}; |
229 | 9.00M | if (has_c) b->color_seen = true; |
230 | 9.00M | if (!TOBJ_T(opt_push)(&b->acol, 3, vidx, rgb, white, has_c, b->alloc)) |
231 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
232 | 9.00M | } |
233 | 9.00M | return true; |
234 | 9.00M | } Line | Count | Source | 193 | 9.00M | static bool TOBJ_T(handle_v)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { | 194 | 9.00M | double nums[8]; | 195 | 9.00M | int n = 0; | 196 | 9.10M | while (n < 8) { | 197 | 9.10M | double d; | 198 | 9.10M | const char *save = c->p; | 199 | 9.10M | if (!tobj_scan_double(&c->p, c->end, &d)) { | 200 | 9.00M | c->p = save; | 201 | 9.00M | break; | 202 | 9.00M | } | 203 | 103k | nums[n++] = d; | 204 | 103k | } | 205 | 9.00M | if (n < 3) { | 206 | 8.99M | TOBJ_T(b_warn)(b, "tinyobjc: 'v' with fewer than 3 components\n"); | 207 | 35.9M | while (n < 3) nums[n++] = 0.0; | 208 | 8.99M | } | 209 | 9.00M | if (b->av.count / 3u >= b->caps.vertices) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); | 210 | 9.00M | size_t vidx = b->av.count / 3u; | 211 | 9.00M | TOBJ_REAL xyz[3] = {(TOBJ_REAL)nums[0], (TOBJ_REAL)nums[1], (TOBJ_REAL)nums[2]}; | 212 | 9.00M | if (!tobj_vec_append(&b->av, xyz, 3, b->alloc)) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 213 | | | 214 | | /* weight: only the 4-number form carries a vertex weight */ | 215 | 9.00M | bool has_w = (n == 4); | 216 | 9.00M | TOBJ_REAL w = has_w ? (TOBJ_REAL)nums[3] : (TOBJ_REAL)1; | 217 | 9.00M | TOBJ_REAL wdef = (TOBJ_REAL)1; | 218 | 9.00M | if (!TOBJ_T(opt_push)(&b->avw, 1, vidx, &w, &wdef, has_w, b->alloc)) | 219 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 220 | | | 221 | | /* color: the 6/7-number form carries r g b */ | 222 | 9.00M | if (b->cfg->store_vertex_colors) { | 223 | 9.00M | bool has_c = (n >= 6); | 224 | 9.00M | TOBJ_REAL rgb[3]; | 225 | 9.00M | rgb[0] = has_c ? (TOBJ_REAL)nums[3] : (TOBJ_REAL)1; | 226 | 9.00M | rgb[1] = has_c ? (TOBJ_REAL)nums[4] : (TOBJ_REAL)1; | 227 | 9.00M | rgb[2] = has_c ? (TOBJ_REAL)nums[5] : (TOBJ_REAL)1; | 228 | 9.00M | TOBJ_REAL white[3] = {(TOBJ_REAL)1, (TOBJ_REAL)1, (TOBJ_REAL)1}; | 229 | 9.00M | if (has_c) b->color_seen = true; | 230 | 9.00M | if (!TOBJ_T(opt_push)(&b->acol, 3, vidx, rgb, white, has_c, b->alloc)) | 231 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 232 | 9.00M | } | 233 | 9.00M | return true; | 234 | 9.00M | } |
Unexecuted instantiation: tiny_obj_c.c:handle_v_d |
235 | | |
236 | 1.72M | static bool TOBJ_T(handle_vn)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { |
237 | 1.72M | TOBJ_REAL xyz[3] = {0, 0, 0}; |
238 | 1.72M | double d; |
239 | 6.91M | for (int i = 0; i < 3; i++) |
240 | 5.18M | if (tobj_scan_double(&c->p, c->end, &d)) xyz[i] = (TOBJ_REAL)d; |
241 | 1.72M | if (!tobj_vec_append(&b->avn, xyz, 3, b->alloc)) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
242 | 1.72M | return true; |
243 | 1.72M | } Line | Count | Source | 236 | 1.72M | static bool TOBJ_T(handle_vn)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { | 237 | 1.72M | TOBJ_REAL xyz[3] = {0, 0, 0}; | 238 | 1.72M | double d; | 239 | 6.91M | for (int i = 0; i < 3; i++) | 240 | 5.18M | if (tobj_scan_double(&c->p, c->end, &d)) xyz[i] = (TOBJ_REAL)d; | 241 | 1.72M | if (!tobj_vec_append(&b->avn, xyz, 3, b->alloc)) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 242 | 1.72M | return true; | 243 | 1.72M | } |
Unexecuted instantiation: tiny_obj_c.c:handle_vn_d |
244 | | |
245 | 2.04M | static bool TOBJ_T(handle_vt)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { |
246 | 2.04M | double d; |
247 | 2.04M | TOBJ_REAL uv[2] = {0, 0}; |
248 | 2.04M | int n = 0; |
249 | 2.23M | for (; n < 2; n++) { |
250 | 2.17M | if (!tobj_scan_double(&c->p, c->end, &d)) break; |
251 | 191k | uv[n] = (TOBJ_REAL)d; |
252 | 191k | } |
253 | 2.04M | size_t tidx = b->avt.count / 2u; |
254 | 2.04M | if (!tobj_vec_append(&b->avt, uv, 2, b->alloc)) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
255 | 2.04M | bool has_w = tobj_scan_double(&c->p, c->end, &d); |
256 | 2.04M | TOBJ_REAL w = has_w ? (TOBJ_REAL)d : (TOBJ_REAL)0; |
257 | 2.04M | TOBJ_REAL wdef = (TOBJ_REAL)0; |
258 | 2.04M | if (!TOBJ_T(opt_push)(&b->avtw, 1, tidx, &w, &wdef, has_w, b->alloc)) |
259 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
260 | 2.04M | return true; |
261 | 2.04M | } Line | Count | Source | 245 | 2.04M | static bool TOBJ_T(handle_vt)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { | 246 | 2.04M | double d; | 247 | 2.04M | TOBJ_REAL uv[2] = {0, 0}; | 248 | 2.04M | int n = 0; | 249 | 2.23M | for (; n < 2; n++) { | 250 | 2.17M | if (!tobj_scan_double(&c->p, c->end, &d)) break; | 251 | 191k | uv[n] = (TOBJ_REAL)d; | 252 | 191k | } | 253 | 2.04M | size_t tidx = b->avt.count / 2u; | 254 | 2.04M | if (!tobj_vec_append(&b->avt, uv, 2, b->alloc)) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 255 | 2.04M | bool has_w = tobj_scan_double(&c->p, c->end, &d); | 256 | 2.04M | TOBJ_REAL w = has_w ? (TOBJ_REAL)d : (TOBJ_REAL)0; | 257 | 2.04M | TOBJ_REAL wdef = (TOBJ_REAL)0; | 258 | 2.04M | if (!TOBJ_T(opt_push)(&b->avtw, 1, tidx, &w, &wdef, has_w, b->alloc)) | 259 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 260 | 2.04M | return true; | 261 | 2.04M | } |
Unexecuted instantiation: tiny_obj_c.c:handle_vt_d |
262 | | |
263 | | /* Append triangulated/raw face corners to the current shape mesh. */ |
264 | 54.0k | static bool TOBJ_T(emit_face)(TOBJ_T(tobj_builder) * b, size_t arity) { |
265 | 54.0k | const tobj_index *corners = (const tobj_index *)b->corners.data; |
266 | 54.0k | bool do_tri = b->triangulate && arity > 3u; |
267 | | |
268 | 54.0k | if (!do_tri) { |
269 | 7.24k | if (b->m_idx.count + arity > b->caps.indices) |
270 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); |
271 | 7.24k | if (!tobj_vec_append(&b->m_idx, corners, arity, b->alloc)) |
272 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
273 | 7.24k | unsigned fv = (unsigned)tobj_size_to_int(arity); |
274 | 7.24k | if (!tobj_vec_append(&b->m_fv, &fv, 1, b->alloc) || |
275 | 7.24k | !tobj_vec_append(&b->m_mid, &b->cur_material, 1, b->alloc) || |
276 | 7.24k | !tobj_vec_append(&b->m_sg, &b->cur_smooth, 1, b->alloc)) |
277 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
278 | 7.24k | b->cur_has_prims = true; |
279 | 7.24k | return true; |
280 | 7.24k | } |
281 | | |
282 | | /* triangulate */ |
283 | 46.8k | size_t numv = TOBJ_T(cnt_v)(b); |
284 | 46.8k | bool pos_ok = true; |
285 | 2.28M | for (size_t k = 0; k < arity; k++) { |
286 | 2.24M | int vi = corners[k].vertex_index; |
287 | 2.24M | if (vi < 0 || (size_t)vi >= numv) { |
288 | 10.1k | pos_ok = false; |
289 | 10.1k | break; |
290 | 10.1k | } |
291 | 2.24M | } |
292 | | |
293 | 46.8k | uint32_t ntri = (uint32_t)(arity - 2u); |
294 | 46.8k | b->tris.count = 0; |
295 | 46.8k | if (!tobj_vec_reserve(&b->tris, (size_t)ntri * 3u, b->alloc)) |
296 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
297 | 46.8k | uint32_t *tri = (uint32_t *)b->tris.data; |
298 | | |
299 | 46.8k | if (pos_ok) { |
300 | 36.6k | b->ringpos.count = 0; |
301 | 36.6k | if (!tobj_vec_reserve(&b->ringpos, arity * 3u, b->alloc)) |
302 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
303 | 36.6k | TOBJ_REAL *rp = (TOBJ_REAL *)b->ringpos.data; |
304 | 36.6k | const TOBJ_REAL *vsrc = (const TOBJ_REAL *)b->av.data; |
305 | 2.24M | for (size_t k = 0; k < arity; k++) { |
306 | 2.20M | size_t vi = (size_t)corners[k].vertex_index; |
307 | 2.20M | rp[3 * k + 0] = vsrc[3 * vi + 0]; |
308 | 2.20M | rp[3 * k + 1] = vsrc[3 * vi + 1]; |
309 | 2.20M | rp[3 * k + 2] = vsrc[3 * vi + 2]; |
310 | 2.20M | } |
311 | 36.6k | size_t need_scratch = tobj_tess_scratch_size((uint32_t)arity); |
312 | 36.6k | if (!tobj_vec_reserve(&b->tscratch, need_scratch, b->alloc)) |
313 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
314 | | |
315 | 36.6k | TOBJ_T(tobj_tess_desc) desc; |
316 | 36.6k | tobj_memset(&desc, 0, sizeof desc); |
317 | 36.6k | desc.points = rp; |
318 | 36.6k | desc.n = (uint32_t)arity; |
319 | 36.6k | desc.out_indices = tri; |
320 | 36.6k | desc.out_cap = ntri * 3u; |
321 | 36.6k | desc.scratch = b->tscratch.data; |
322 | 36.6k | desc.scratch_size = need_scratch; |
323 | 36.6k | tobj_tess_result res; |
324 | 36.6k | TOBJ_T(tobj_tess_polygon)(&desc, &res); |
325 | 36.6k | ntri = res.num_triangles; |
326 | 36.6k | if (res.status == TOBJ_TESS_DEGENERATE_BESTEFFORT) |
327 | 28.3k | TOBJ_T(b_warn)(b, "tinyobjc: degenerate polygon triangulated best-effort\n"); |
328 | 36.6k | } else { |
329 | 10.1k | TOBJ_T(b_warn)(b, "tinyobjc: face with invalid vertex index; fan fallback\n"); |
330 | 22.1M | for (uint32_t t = 0; t < ntri; t++) { |
331 | 22.1M | tri[3 * t + 0] = 0; |
332 | 22.1M | tri[3 * t + 1] = t + 1; |
333 | 22.1M | tri[3 * t + 2] = t + 2; |
334 | 22.1M | } |
335 | 10.1k | } |
336 | | |
337 | 46.8k | if (b->m_idx.count + (size_t)ntri * 3u > b->caps.indices) |
338 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); |
339 | 24.2M | for (uint32_t t = 0; t < ntri; t++) { |
340 | 24.1M | tobj_index tidx[3]; |
341 | 24.1M | tidx[0] = corners[tri[3 * t + 0]]; |
342 | 24.1M | tidx[1] = corners[tri[3 * t + 1]]; |
343 | 24.1M | tidx[2] = corners[tri[3 * t + 2]]; |
344 | 24.1M | unsigned fv = 3; |
345 | 24.1M | if (!tobj_vec_append(&b->m_idx, tidx, 3, b->alloc) || |
346 | 24.1M | !tobj_vec_append(&b->m_fv, &fv, 1, b->alloc) || |
347 | 24.1M | !tobj_vec_append(&b->m_mid, &b->cur_material, 1, b->alloc) || |
348 | 24.1M | !tobj_vec_append(&b->m_sg, &b->cur_smooth, 1, b->alloc)) |
349 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
350 | 24.1M | } |
351 | 46.8k | b->cur_has_prims = true; |
352 | 46.8k | return true; |
353 | 46.8k | } Line | Count | Source | 264 | 54.0k | static bool TOBJ_T(emit_face)(TOBJ_T(tobj_builder) * b, size_t arity) { | 265 | 54.0k | const tobj_index *corners = (const tobj_index *)b->corners.data; | 266 | 54.0k | bool do_tri = b->triangulate && arity > 3u; | 267 | | | 268 | 54.0k | if (!do_tri) { | 269 | 7.24k | if (b->m_idx.count + arity > b->caps.indices) | 270 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); | 271 | 7.24k | if (!tobj_vec_append(&b->m_idx, corners, arity, b->alloc)) | 272 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 273 | 7.24k | unsigned fv = (unsigned)tobj_size_to_int(arity); | 274 | 7.24k | if (!tobj_vec_append(&b->m_fv, &fv, 1, b->alloc) || | 275 | 7.24k | !tobj_vec_append(&b->m_mid, &b->cur_material, 1, b->alloc) || | 276 | 7.24k | !tobj_vec_append(&b->m_sg, &b->cur_smooth, 1, b->alloc)) | 277 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 278 | 7.24k | b->cur_has_prims = true; | 279 | 7.24k | return true; | 280 | 7.24k | } | 281 | | | 282 | | /* triangulate */ | 283 | 46.8k | size_t numv = TOBJ_T(cnt_v)(b); | 284 | 46.8k | bool pos_ok = true; | 285 | 2.28M | for (size_t k = 0; k < arity; k++) { | 286 | 2.24M | int vi = corners[k].vertex_index; | 287 | 2.24M | if (vi < 0 || (size_t)vi >= numv) { | 288 | 10.1k | pos_ok = false; | 289 | 10.1k | break; | 290 | 10.1k | } | 291 | 2.24M | } | 292 | | | 293 | 46.8k | uint32_t ntri = (uint32_t)(arity - 2u); | 294 | 46.8k | b->tris.count = 0; | 295 | 46.8k | if (!tobj_vec_reserve(&b->tris, (size_t)ntri * 3u, b->alloc)) | 296 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 297 | 46.8k | uint32_t *tri = (uint32_t *)b->tris.data; | 298 | | | 299 | 46.8k | if (pos_ok) { | 300 | 36.6k | b->ringpos.count = 0; | 301 | 36.6k | if (!tobj_vec_reserve(&b->ringpos, arity * 3u, b->alloc)) | 302 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 303 | 36.6k | TOBJ_REAL *rp = (TOBJ_REAL *)b->ringpos.data; | 304 | 36.6k | const TOBJ_REAL *vsrc = (const TOBJ_REAL *)b->av.data; | 305 | 2.24M | for (size_t k = 0; k < arity; k++) { | 306 | 2.20M | size_t vi = (size_t)corners[k].vertex_index; | 307 | 2.20M | rp[3 * k + 0] = vsrc[3 * vi + 0]; | 308 | 2.20M | rp[3 * k + 1] = vsrc[3 * vi + 1]; | 309 | 2.20M | rp[3 * k + 2] = vsrc[3 * vi + 2]; | 310 | 2.20M | } | 311 | 36.6k | size_t need_scratch = tobj_tess_scratch_size((uint32_t)arity); | 312 | 36.6k | if (!tobj_vec_reserve(&b->tscratch, need_scratch, b->alloc)) | 313 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 314 | | | 315 | 36.6k | TOBJ_T(tobj_tess_desc) desc; | 316 | 36.6k | tobj_memset(&desc, 0, sizeof desc); | 317 | 36.6k | desc.points = rp; | 318 | 36.6k | desc.n = (uint32_t)arity; | 319 | 36.6k | desc.out_indices = tri; | 320 | 36.6k | desc.out_cap = ntri * 3u; | 321 | 36.6k | desc.scratch = b->tscratch.data; | 322 | 36.6k | desc.scratch_size = need_scratch; | 323 | 36.6k | tobj_tess_result res; | 324 | 36.6k | TOBJ_T(tobj_tess_polygon)(&desc, &res); | 325 | 36.6k | ntri = res.num_triangles; | 326 | 36.6k | if (res.status == TOBJ_TESS_DEGENERATE_BESTEFFORT) | 327 | 28.3k | TOBJ_T(b_warn)(b, "tinyobjc: degenerate polygon triangulated best-effort\n"); | 328 | 36.6k | } else { | 329 | 10.1k | TOBJ_T(b_warn)(b, "tinyobjc: face with invalid vertex index; fan fallback\n"); | 330 | 22.1M | for (uint32_t t = 0; t < ntri; t++) { | 331 | 22.1M | tri[3 * t + 0] = 0; | 332 | 22.1M | tri[3 * t + 1] = t + 1; | 333 | 22.1M | tri[3 * t + 2] = t + 2; | 334 | 22.1M | } | 335 | 10.1k | } | 336 | | | 337 | 46.8k | if (b->m_idx.count + (size_t)ntri * 3u > b->caps.indices) | 338 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); | 339 | 24.2M | for (uint32_t t = 0; t < ntri; t++) { | 340 | 24.1M | tobj_index tidx[3]; | 341 | 24.1M | tidx[0] = corners[tri[3 * t + 0]]; | 342 | 24.1M | tidx[1] = corners[tri[3 * t + 1]]; | 343 | 24.1M | tidx[2] = corners[tri[3 * t + 2]]; | 344 | 24.1M | unsigned fv = 3; | 345 | 24.1M | if (!tobj_vec_append(&b->m_idx, tidx, 3, b->alloc) || | 346 | 24.1M | !tobj_vec_append(&b->m_fv, &fv, 1, b->alloc) || | 347 | 24.1M | !tobj_vec_append(&b->m_mid, &b->cur_material, 1, b->alloc) || | 348 | 24.1M | !tobj_vec_append(&b->m_sg, &b->cur_smooth, 1, b->alloc)) | 349 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 350 | 24.1M | } | 351 | 46.8k | b->cur_has_prims = true; | 352 | | return true; | 353 | 46.8k | } |
Unexecuted instantiation: tiny_obj_c.c:emit_face_d |
354 | | |
355 | 74.5k | static bool TOBJ_T(handle_f)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { |
356 | 74.5k | b->corners.count = 0; |
357 | 74.5k | const char *tok; |
358 | 74.5k | size_t tlen; |
359 | 74.5k | size_t arity = 0; |
360 | 24.5M | while (tobj_next_token(c, &tok, &tlen)) { |
361 | 24.4M | if (arity >= b->caps.arity) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); |
362 | 24.4M | tobj_index *slot = (tobj_index *)tobj_vec_push(&b->corners, b->alloc); |
363 | 24.4M | if (!slot) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
364 | 24.4M | TOBJ_T(parse_corner)(b, tok, tlen, slot); |
365 | 24.4M | arity++; |
366 | 24.4M | } |
367 | 74.5k | if (arity < 3) { |
368 | 20.5k | TOBJ_T(b_warn)(b, "tinyobjc: degenerate face (<3 vertices)\n"); |
369 | 20.5k | return true; |
370 | 20.5k | } |
371 | 54.0k | if (b->m_fv.count >= b->caps.faces) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); |
372 | 54.0k | return TOBJ_T(emit_face)(b, arity); |
373 | 54.0k | } Line | Count | Source | 355 | 74.5k | static bool TOBJ_T(handle_f)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { | 356 | 74.5k | b->corners.count = 0; | 357 | 74.5k | const char *tok; | 358 | 74.5k | size_t tlen; | 359 | 74.5k | size_t arity = 0; | 360 | 24.5M | while (tobj_next_token(c, &tok, &tlen)) { | 361 | 24.4M | if (arity >= b->caps.arity) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); | 362 | 24.4M | tobj_index *slot = (tobj_index *)tobj_vec_push(&b->corners, b->alloc); | 363 | 24.4M | if (!slot) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 364 | 24.4M | TOBJ_T(parse_corner)(b, tok, tlen, slot); | 365 | 24.4M | arity++; | 366 | 24.4M | } | 367 | 74.5k | if (arity < 3) { | 368 | 20.5k | TOBJ_T(b_warn)(b, "tinyobjc: degenerate face (<3 vertices)\n"); | 369 | 20.5k | return true; | 370 | 20.5k | } | 371 | 54.0k | if (b->m_fv.count >= b->caps.faces) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); | 372 | 54.0k | return TOBJ_T(emit_face)(b, arity); | 373 | 54.0k | } |
Unexecuted instantiation: tiny_obj_c.c:handle_f_d |
374 | | |
375 | 484k | static bool TOBJ_T(handle_l)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { |
376 | 484k | const char *tok; |
377 | 484k | size_t tlen; |
378 | 484k | size_t cnt = 0; |
379 | 484k | size_t start = b->l_idx.count; |
380 | 7.50M | while (tobj_next_token(c, &tok, &tlen)) { |
381 | 7.01M | if (cnt >= b->caps.arity) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); |
382 | 7.01M | tobj_index idx; |
383 | 7.01M | TOBJ_T(parse_corner)(b, tok, tlen, &idx); |
384 | 7.01M | if (!tobj_vec_append(&b->l_idx, &idx, 1, b->alloc)) |
385 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
386 | 7.01M | cnt++; |
387 | 7.01M | } |
388 | 484k | if (cnt < 2) { |
389 | 11.0k | b->l_idx.count = start; /* roll back */ |
390 | 11.0k | TOBJ_T(b_warn)(b, "tinyobjc: degenerate line (<2 vertices)\n"); |
391 | 11.0k | return true; |
392 | 11.0k | } |
393 | 473k | int icnt = tobj_size_to_int(cnt); |
394 | 473k | if (!tobj_vec_append(&b->l_cnt, &icnt, 1, b->alloc)) |
395 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
396 | 473k | b->cur_has_prims = true; |
397 | 473k | return true; |
398 | 473k | } Line | Count | Source | 375 | 484k | static bool TOBJ_T(handle_l)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { | 376 | 484k | const char *tok; | 377 | 484k | size_t tlen; | 378 | 484k | size_t cnt = 0; | 379 | 484k | size_t start = b->l_idx.count; | 380 | 7.50M | while (tobj_next_token(c, &tok, &tlen)) { | 381 | 7.01M | if (cnt >= b->caps.arity) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); | 382 | 7.01M | tobj_index idx; | 383 | 7.01M | TOBJ_T(parse_corner)(b, tok, tlen, &idx); | 384 | 7.01M | if (!tobj_vec_append(&b->l_idx, &idx, 1, b->alloc)) | 385 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 386 | 7.01M | cnt++; | 387 | 7.01M | } | 388 | 484k | if (cnt < 2) { | 389 | 11.0k | b->l_idx.count = start; /* roll back */ | 390 | 11.0k | TOBJ_T(b_warn)(b, "tinyobjc: degenerate line (<2 vertices)\n"); | 391 | 11.0k | return true; | 392 | 11.0k | } | 393 | 473k | int icnt = tobj_size_to_int(cnt); | 394 | 473k | if (!tobj_vec_append(&b->l_cnt, &icnt, 1, b->alloc)) | 395 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 396 | 473k | b->cur_has_prims = true; | 397 | | return true; | 398 | 473k | } |
Unexecuted instantiation: tiny_obj_c.c:handle_l_d |
399 | | |
400 | 338k | static bool TOBJ_T(handle_p)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { |
401 | 338k | const char *tok; |
402 | 338k | size_t tlen; |
403 | 5.11M | while (tobj_next_token(c, &tok, &tlen)) { |
404 | 4.77M | tobj_index idx; |
405 | 4.77M | TOBJ_T(parse_corner)(b, tok, tlen, &idx); |
406 | 4.77M | if (!tobj_vec_append(&b->p_idx, &idx, 1, b->alloc)) |
407 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
408 | 4.77M | b->cur_has_prims = true; |
409 | 4.77M | } |
410 | 338k | return true; |
411 | 338k | } Line | Count | Source | 400 | 338k | static bool TOBJ_T(handle_p)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { | 401 | 338k | const char *tok; | 402 | 338k | size_t tlen; | 403 | 5.11M | while (tobj_next_token(c, &tok, &tlen)) { | 404 | 4.77M | tobj_index idx; | 405 | 4.77M | TOBJ_T(parse_corner)(b, tok, tlen, &idx); | 406 | 4.77M | if (!tobj_vec_append(&b->p_idx, &idx, 1, b->alloc)) | 407 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 408 | 4.77M | b->cur_has_prims = true; | 409 | 4.77M | } | 410 | 338k | return true; | 411 | 338k | } |
Unexecuted instantiation: tiny_obj_c.c:handle_p_d |
412 | | |
413 | | /* ----------------------------------------------------------------------- */ |
414 | | /* shape finalize */ |
415 | | /* ----------------------------------------------------------------------- */ |
416 | | |
417 | | #define TOBJ_FIN(dst_ptr, dst_cnt, vec, T) \ |
418 | 2.32M | do { \ |
419 | 2.32M | (dst_cnt) = (vec).count; \ |
420 | 2.32M | (dst_ptr) = (T *)tobj_vec_finalize(&(vec), b->arena, 16); \ |
421 | 2.32M | if ((vec).count && !(dst_ptr)) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); \ |
422 | 2.32M | (vec).count = 0; \ |
423 | 2.32M | } while (0) |
424 | | |
425 | | static bool TOBJ_T(ff_finalize_elem)(TOBJ_T(tobj_builder) * b); /* fwd */ |
426 | | |
427 | 383k | static bool TOBJ_T(finalize_shape)(TOBJ_T(tobj_builder) * b) { |
428 | 383k | if (b->ff_active && !TOBJ_T(ff_finalize_elem)(b)) return false; |
429 | 383k | bool has_ff = b->sh_curves.count || b->sh_curves2.count || |
430 | 383k | b->sh_surfaces.count; |
431 | 383k | if (!b->cur_has_prims && b->m_fv.count == 0 && b->l_cnt.count == 0 && |
432 | 51.4k | b->p_idx.count == 0 && !has_ff) { |
433 | | /* nothing to emit, but keep the name for the next group */ |
434 | 51.4k | return true; |
435 | 51.4k | } |
436 | 331k | if (b->shapes.count >= b->caps.shapes) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); |
437 | | |
438 | 331k | TOBJ_T(tobj_shape) sh; |
439 | 331k | tobj_memset(&sh, 0, sizeof sh); |
440 | 331k | sh.name = b->cur_name ? b->cur_name : tobj_intern(b->arena, "", 0); |
441 | 331k | if (!sh.name) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
442 | | |
443 | 331k | size_t nf; |
444 | 331k | TOBJ_FIN(sh.mesh.indices, sh.mesh.num_indices, b->m_idx, tobj_index); |
445 | 331k | TOBJ_FIN(sh.mesh.num_face_vertices, nf, b->m_fv, unsigned); |
446 | 331k | sh.mesh.num_faces = nf; |
447 | 331k | TOBJ_FIN(sh.mesh.material_ids, nf, b->m_mid, int); |
448 | 331k | TOBJ_FIN(sh.mesh.smoothing_group_ids, nf, b->m_sg, unsigned); |
449 | | |
450 | 331k | TOBJ_FIN(sh.lines.indices, sh.lines.num_indices, b->l_idx, tobj_index); |
451 | 331k | TOBJ_FIN(sh.lines.num_line_vertices, sh.lines.num_lines, b->l_cnt, int); |
452 | | |
453 | 331k | TOBJ_FIN(sh.points.indices, sh.points.num_indices, b->p_idx, tobj_index); |
454 | | |
455 | | /* free-form geometry, if any accumulated for this shape */ |
456 | 331k | if (b->sh_curves.count || b->sh_curves2.count || b->sh_surfaces.count) { |
457 | 0 | TOBJ_T(tobj_freeform) *ff = (TOBJ_T(tobj_freeform) *)tobj_arena_alloc( |
458 | 0 | b->arena, sizeof(*ff), 16); |
459 | 0 | if (!ff) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
460 | 0 | tobj_memset(ff, 0, sizeof *ff); |
461 | 0 | ff->vp.components = b->ff_vp_comps; |
462 | 0 | ff->vp.uvw.count = b->ff_vp.count; |
463 | 0 | ff->vp.uvw.ptr = (TOBJ_REAL *)tobj_arena_dup( |
464 | 0 | b->arena, b->ff_vp.data, b->ff_vp.count * sizeof(TOBJ_REAL), 16); |
465 | 0 | if (b->ff_vp.count && !ff->vp.uvw.ptr) |
466 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
467 | 0 | TOBJ_FIN(ff->curves, ff->num_curves, b->sh_curves, TOBJ_T(tobj_curve)); |
468 | 0 | TOBJ_FIN(ff->curves2, ff->num_curves2, b->sh_curves2, TOBJ_T(tobj_curve2)); |
469 | 0 | TOBJ_FIN(ff->surfaces, ff->num_surfaces, b->sh_surfaces, |
470 | 0 | TOBJ_T(tobj_surface)); |
471 | 0 | sh.freeform = ff; |
472 | 0 | } |
473 | | |
474 | 331k | TOBJ_T(tobj_shape) *slot = (TOBJ_T(tobj_shape) *)tobj_vec_push(&b->shapes, b->alloc); |
475 | 331k | if (!slot) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
476 | 331k | *slot = sh; |
477 | 331k | b->cur_has_prims = false; |
478 | 331k | return true; |
479 | 331k | } tiny_obj_c.c:finalize_shape_f Line | Count | Source | 427 | 383k | static bool TOBJ_T(finalize_shape)(TOBJ_T(tobj_builder) * b) { | 428 | 383k | if (b->ff_active && !TOBJ_T(ff_finalize_elem)(b)) return false; | 429 | 383k | bool has_ff = b->sh_curves.count || b->sh_curves2.count || | 430 | 383k | b->sh_surfaces.count; | 431 | 383k | if (!b->cur_has_prims && b->m_fv.count == 0 && b->l_cnt.count == 0 && | 432 | 51.4k | b->p_idx.count == 0 && !has_ff) { | 433 | | /* nothing to emit, but keep the name for the next group */ | 434 | 51.4k | return true; | 435 | 51.4k | } | 436 | 331k | if (b->shapes.count >= b->caps.shapes) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); | 437 | | | 438 | 331k | TOBJ_T(tobj_shape) sh; | 439 | 331k | tobj_memset(&sh, 0, sizeof sh); | 440 | 331k | sh.name = b->cur_name ? b->cur_name : tobj_intern(b->arena, "", 0); | 441 | 331k | if (!sh.name) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 442 | | | 443 | 331k | size_t nf; | 444 | 331k | TOBJ_FIN(sh.mesh.indices, sh.mesh.num_indices, b->m_idx, tobj_index); | 445 | 331k | TOBJ_FIN(sh.mesh.num_face_vertices, nf, b->m_fv, unsigned); | 446 | 331k | sh.mesh.num_faces = nf; | 447 | 331k | TOBJ_FIN(sh.mesh.material_ids, nf, b->m_mid, int); | 448 | 331k | TOBJ_FIN(sh.mesh.smoothing_group_ids, nf, b->m_sg, unsigned); | 449 | | | 450 | 331k | TOBJ_FIN(sh.lines.indices, sh.lines.num_indices, b->l_idx, tobj_index); | 451 | 331k | TOBJ_FIN(sh.lines.num_line_vertices, sh.lines.num_lines, b->l_cnt, int); | 452 | | | 453 | 331k | TOBJ_FIN(sh.points.indices, sh.points.num_indices, b->p_idx, tobj_index); | 454 | | | 455 | | /* free-form geometry, if any accumulated for this shape */ | 456 | 331k | if (b->sh_curves.count || b->sh_curves2.count || b->sh_surfaces.count) { | 457 | 0 | TOBJ_T(tobj_freeform) *ff = (TOBJ_T(tobj_freeform) *)tobj_arena_alloc( | 458 | 0 | b->arena, sizeof(*ff), 16); | 459 | 0 | if (!ff) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 460 | 0 | tobj_memset(ff, 0, sizeof *ff); | 461 | 0 | ff->vp.components = b->ff_vp_comps; | 462 | 0 | ff->vp.uvw.count = b->ff_vp.count; | 463 | 0 | ff->vp.uvw.ptr = (TOBJ_REAL *)tobj_arena_dup( | 464 | 0 | b->arena, b->ff_vp.data, b->ff_vp.count * sizeof(TOBJ_REAL), 16); | 465 | 0 | if (b->ff_vp.count && !ff->vp.uvw.ptr) | 466 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 467 | 0 | TOBJ_FIN(ff->curves, ff->num_curves, b->sh_curves, TOBJ_T(tobj_curve)); | 468 | 0 | TOBJ_FIN(ff->curves2, ff->num_curves2, b->sh_curves2, TOBJ_T(tobj_curve2)); | 469 | 0 | TOBJ_FIN(ff->surfaces, ff->num_surfaces, b->sh_surfaces, | 470 | 0 | TOBJ_T(tobj_surface)); | 471 | 0 | sh.freeform = ff; | 472 | 0 | } | 473 | | | 474 | 331k | TOBJ_T(tobj_shape) *slot = (TOBJ_T(tobj_shape) *)tobj_vec_push(&b->shapes, b->alloc); | 475 | 331k | if (!slot) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 476 | 331k | *slot = sh; | 477 | 331k | b->cur_has_prims = false; | 478 | | return true; | 479 | 331k | } |
Unexecuted instantiation: tiny_obj_c.c:finalize_shape_d |
480 | | |
481 | | /* Start a new shape group with the given (interned) name. */ |
482 | 379k | static bool TOBJ_T(new_group)(TOBJ_T(tobj_builder) * b, const char *name) { |
483 | 379k | if (!TOBJ_T(finalize_shape)(b)) return false; |
484 | 379k | b->cur_name = name; |
485 | 379k | return true; |
486 | 379k | } Line | Count | Source | 482 | 379k | static bool TOBJ_T(new_group)(TOBJ_T(tobj_builder) * b, const char *name) { | 483 | 379k | if (!TOBJ_T(finalize_shape)(b)) return false; | 484 | 379k | b->cur_name = name; | 485 | | return true; | 486 | 379k | } |
Unexecuted instantiation: tiny_obj_c.c:new_group_d |
487 | | |
488 | | /* ----------------------------------------------------------------------- */ |
489 | | /* material support */ |
490 | | /* ----------------------------------------------------------------------- */ |
491 | | |
492 | 0 | static void TOBJ_T(texopt_init)(TOBJ_T(tobj_texture_option) * t, tobj_arena *ar) { |
493 | 0 | tobj_memset(t, 0, sizeof *t); |
494 | 0 | t->type = TOBJ_TEXTURE_TYPE_NONE; |
495 | 0 | t->sharpness = (TOBJ_REAL)1; |
496 | 0 | t->brightness = (TOBJ_REAL)0; |
497 | 0 | t->contrast = (TOBJ_REAL)1; |
498 | 0 | t->scale[0] = t->scale[1] = t->scale[2] = (TOBJ_REAL)1; |
499 | 0 | t->texture_resolution = -1; |
500 | 0 | t->clamp = false; |
501 | 0 | t->blendu = true; |
502 | 0 | t->blendv = true; |
503 | 0 | t->imfchan = 'm'; |
504 | 0 | t->bump_multiplier = (TOBJ_REAL)1; |
505 | 0 | t->colorspace = tobj_intern(ar, "", 0); |
506 | 0 | } Unexecuted instantiation: tiny_obj_c.c:texopt_init_f Unexecuted instantiation: tiny_obj_c.c:texopt_init_d |
507 | | |
508 | 0 | static void TOBJ_T(material_init)(TOBJ_T(tobj_material) * m, tobj_arena *ar) { |
509 | 0 | tobj_memset(m, 0, sizeof *m); |
510 | 0 | m->shininess = (TOBJ_REAL)1; |
511 | 0 | m->ior = (TOBJ_REAL)1; |
512 | 0 | m->dissolve = (TOBJ_REAL)1; |
513 | 0 | m->illum = 0; |
514 | 0 | const char *empty = tobj_intern(ar, "", 0); |
515 | 0 | m->name = empty; |
516 | 0 | m->ambient_texname = m->diffuse_texname = m->specular_texname = empty; |
517 | 0 | m->specular_highlight_texname = m->bump_texname = m->displacement_texname = empty; |
518 | 0 | m->alpha_texname = m->reflection_texname = empty; |
519 | 0 | m->roughness_texname = m->metallic_texname = m->sheen_texname = empty; |
520 | 0 | m->emissive_texname = m->normal_texname = empty; |
521 | 0 | TOBJ_T(texopt_init)(&m->ambient_texopt, ar); |
522 | 0 | TOBJ_T(texopt_init)(&m->diffuse_texopt, ar); |
523 | 0 | TOBJ_T(texopt_init)(&m->specular_texopt, ar); |
524 | 0 | TOBJ_T(texopt_init)(&m->specular_highlight_texopt, ar); |
525 | 0 | TOBJ_T(texopt_init)(&m->bump_texopt, ar); |
526 | 0 | TOBJ_T(texopt_init)(&m->displacement_texopt, ar); |
527 | 0 | TOBJ_T(texopt_init)(&m->alpha_texopt, ar); |
528 | 0 | TOBJ_T(texopt_init)(&m->reflection_texopt, ar); |
529 | 0 | TOBJ_T(texopt_init)(&m->roughness_texopt, ar); |
530 | 0 | TOBJ_T(texopt_init)(&m->metallic_texopt, ar); |
531 | 0 | TOBJ_T(texopt_init)(&m->sheen_texopt, ar); |
532 | 0 | TOBJ_T(texopt_init)(&m->emissive_texopt, ar); |
533 | 0 | TOBJ_T(texopt_init)(&m->normal_texopt, ar); |
534 | 0 | } Unexecuted instantiation: tiny_obj_c.c:material_init_f Unexecuted instantiation: tiny_obj_c.c:material_init_d |
535 | | |
536 | | static int TOBJ_T(mat_find)(TOBJ_T(tobj_builder) * b, const char *name, |
537 | 581 | size_t len) { |
538 | 581 | const char **keys = (const char **)b->matmap_key.data; |
539 | 581 | const int *ids = (const int *)b->matmap_id.data; |
540 | 581 | for (size_t i = 0; i < b->matmap_key.count; i++) { |
541 | 0 | if (tobj_slice_eq(name, len, keys[i])) return ids[i]; |
542 | 0 | } |
543 | 581 | return -1; |
544 | 581 | } Line | Count | Source | 537 | 581 | size_t len) { | 538 | 581 | const char **keys = (const char **)b->matmap_key.data; | 539 | 581 | const int *ids = (const int *)b->matmap_id.data; | 540 | 581 | for (size_t i = 0; i < b->matmap_key.count; i++) { | 541 | 0 | if (tobj_slice_eq(name, len, keys[i])) return ids[i]; | 542 | 0 | } | 543 | 581 | return -1; | 544 | 581 | } |
Unexecuted instantiation: tiny_obj_c.c:mat_find_d |
545 | | |
546 | | /* Read up to `n` reals from the cursor into dst (missing left untouched). */ |
547 | 0 | static void TOBJ_T(read_reals)(tobj_cursor *c, TOBJ_REAL *dst, int n) { |
548 | 0 | double d; |
549 | 0 | for (int i = 0; i < n; i++) { |
550 | 0 | if (!tobj_scan_double(&c->p, c->end, &d)) break; |
551 | 0 | dst[i] = (TOBJ_REAL)d; |
552 | 0 | } |
553 | 0 | } Unexecuted instantiation: tiny_obj_c.c:read_reals_f Unexecuted instantiation: tiny_obj_c.c:read_reals_d |
554 | | |
555 | | /* Trim leading/trailing spaces of the cursor remainder and intern it. */ |
556 | 379k | static const char *TOBJ_T(intern_rest)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { |
557 | 379k | const char *p = c->p, *e = c->end; |
558 | 393k | while (p < e && tobj_is_space(*p)) p++; |
559 | 380k | while (e > p && tobj_is_space(e[-1])) e--; |
560 | 379k | return tobj_intern(b->arena, p, (size_t)(e - p)); |
561 | 379k | } tiny_obj_c.c:intern_rest_f Line | Count | Source | 556 | 379k | static const char *TOBJ_T(intern_rest)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { | 557 | 379k | const char *p = c->p, *e = c->end; | 558 | 393k | while (p < e && tobj_is_space(*p)) p++; | 559 | 380k | while (e > p && tobj_is_space(e[-1])) e--; | 560 | 379k | return tobj_intern(b->arena, p, (size_t)(e - p)); | 561 | 379k | } |
Unexecuted instantiation: tiny_obj_c.c:intern_rest_d |
562 | | |
563 | 0 | static bool TOBJ_T(tok_onoff)(const char *t, size_t l, bool *out) { |
564 | 0 | if (tobj_slice_eq(t, l, "on")) { |
565 | 0 | *out = true; |
566 | 0 | return true; |
567 | 0 | } |
568 | 0 | if (tobj_slice_eq(t, l, "off")) { |
569 | 0 | *out = false; |
570 | 0 | return true; |
571 | 0 | } |
572 | 0 | return false; |
573 | 0 | } Unexecuted instantiation: tiny_obj_c.c:tok_onoff_f Unexecuted instantiation: tiny_obj_c.c:tok_onoff_d |
574 | | |
575 | | /* Parse "[-options ...] filename" into texopt (+ interned name). Mirrors the |
576 | | * C++ ParseTextureNameAndOption. The cursor is consumed up to the filename. */ |
577 | | static const char *TOBJ_T(parse_texopt)(TOBJ_T(tobj_builder) * b, tobj_cursor *c, |
578 | 0 | TOBJ_T(tobj_texture_option) * opt) { |
579 | 0 | const char *tok; |
580 | 0 | size_t tl; |
581 | 0 | for (;;) { |
582 | 0 | const char *save = c->p; |
583 | 0 | if (!tobj_next_token(c, &tok, &tl)) { |
584 | 0 | c->p = save; |
585 | 0 | break; |
586 | 0 | } |
587 | 0 | if (tl == 0 || tok[0] != '-') { |
588 | 0 | c->p = save; /* not an option: filename begins here */ |
589 | 0 | break; |
590 | 0 | } |
591 | 0 | if (tobj_slice_eq(tok, tl, "-blendu")) { |
592 | 0 | const char *v; |
593 | 0 | size_t vl; |
594 | 0 | if (tobj_next_token(c, &v, &vl)) TOBJ_T(tok_onoff)(v, vl, &opt->blendu); |
595 | 0 | } else if (tobj_slice_eq(tok, tl, "-blendv")) { |
596 | 0 | const char *v; |
597 | 0 | size_t vl; |
598 | 0 | if (tobj_next_token(c, &v, &vl)) TOBJ_T(tok_onoff)(v, vl, &opt->blendv); |
599 | 0 | } else if (tobj_slice_eq(tok, tl, "-clamp")) { |
600 | 0 | const char *v; |
601 | 0 | size_t vl; |
602 | 0 | if (tobj_next_token(c, &v, &vl)) TOBJ_T(tok_onoff)(v, vl, &opt->clamp); |
603 | 0 | } else if (tobj_slice_eq(tok, tl, "-bm")) { |
604 | 0 | TOBJ_T(read_reals)(c, &opt->bump_multiplier, 1); |
605 | 0 | } else if (tobj_slice_eq(tok, tl, "-boost")) { |
606 | 0 | TOBJ_T(read_reals)(c, &opt->sharpness, 1); |
607 | 0 | } else if (tobj_slice_eq(tok, tl, "-o")) { |
608 | 0 | TOBJ_T(read_reals)(c, opt->origin_offset, 3); |
609 | 0 | } else if (tobj_slice_eq(tok, tl, "-s")) { |
610 | 0 | TOBJ_T(read_reals)(c, opt->scale, 3); |
611 | 0 | } else if (tobj_slice_eq(tok, tl, "-t")) { |
612 | 0 | TOBJ_T(read_reals)(c, opt->turbulence, 3); |
613 | 0 | } else if (tobj_slice_eq(tok, tl, "-mm")) { |
614 | 0 | TOBJ_T(read_reals)(c, &opt->brightness, 1); |
615 | 0 | TOBJ_T(read_reals)(c, &opt->contrast, 1); |
616 | 0 | } else if (tobj_slice_eq(tok, tl, "-texres")) { |
617 | 0 | int v = -1; |
618 | 0 | tobj_scan_int(&c->p, c->end, &v); |
619 | 0 | opt->texture_resolution = v; |
620 | 0 | } else if (tobj_slice_eq(tok, tl, "-imfchan")) { |
621 | 0 | const char *v; |
622 | 0 | size_t vl; |
623 | 0 | if (tobj_next_token(c, &v, &vl) && vl >= 1) opt->imfchan = v[0]; |
624 | 0 | } else if (tobj_slice_eq(tok, tl, "-type")) { |
625 | 0 | const char *v; |
626 | 0 | size_t vl; |
627 | 0 | if (tobj_next_token(c, &v, &vl)) { |
628 | 0 | if (tobj_slice_eq(v, vl, "sphere")) |
629 | 0 | opt->type = TOBJ_TEXTURE_TYPE_SPHERE; |
630 | 0 | else if (tobj_slice_eq(v, vl, "cube_top")) |
631 | 0 | opt->type = TOBJ_TEXTURE_TYPE_CUBE_TOP; |
632 | 0 | else if (tobj_slice_eq(v, vl, "cube_bottom")) |
633 | 0 | opt->type = TOBJ_TEXTURE_TYPE_CUBE_BOTTOM; |
634 | 0 | else if (tobj_slice_eq(v, vl, "cube_front")) |
635 | 0 | opt->type = TOBJ_TEXTURE_TYPE_CUBE_FRONT; |
636 | 0 | else if (tobj_slice_eq(v, vl, "cube_back")) |
637 | 0 | opt->type = TOBJ_TEXTURE_TYPE_CUBE_BACK; |
638 | 0 | else if (tobj_slice_eq(v, vl, "cube_left")) |
639 | 0 | opt->type = TOBJ_TEXTURE_TYPE_CUBE_LEFT; |
640 | 0 | else if (tobj_slice_eq(v, vl, "cube_right")) |
641 | 0 | opt->type = TOBJ_TEXTURE_TYPE_CUBE_RIGHT; |
642 | 0 | } |
643 | 0 | } else if (tobj_slice_eq(tok, tl, "-colorspace")) { |
644 | 0 | const char *v; |
645 | 0 | size_t vl; |
646 | 0 | if (tobj_next_token(c, &v, &vl)) |
647 | 0 | opt->colorspace = tobj_intern(b->arena, v, vl); |
648 | 0 | } else { |
649 | | /* unknown option flag: skip just the flag token */ |
650 | 0 | } |
651 | 0 | } |
652 | 0 | return TOBJ_T(intern_rest)(b, c); |
653 | 0 | } Unexecuted instantiation: tiny_obj_c.c:parse_texopt_f Unexecuted instantiation: tiny_obj_c.c:parse_texopt_d |
654 | | |
655 | | /* Record an unrecognized "key value" .mtl line for material `mi`. */ |
656 | | static bool TOBJ_T(push_unknown)(TOBJ_T(tobj_builder) * b, size_t mi, |
657 | | const char *key, size_t keylen, |
658 | 0 | tobj_cursor *c) { |
659 | 0 | tobj_pending_kv *kv = (tobj_pending_kv *)tobj_vec_push(&b->mat_unknown, b->alloc); |
660 | 0 | if (!kv) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
661 | 0 | kv->mat_index = mi; |
662 | 0 | kv->key = tobj_intern(b->arena, key, keylen); |
663 | 0 | kv->value = TOBJ_T(intern_rest)(b, c); |
664 | 0 | if (!kv->key || !kv->value) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
665 | 0 | return true; |
666 | 0 | } Unexecuted instantiation: tiny_obj_c.c:push_unknown_f Unexecuted instantiation: tiny_obj_c.c:push_unknown_d |
667 | | |
668 | | /* If map_Kd was given but Kd was not, default diffuse to 0.6 (C++ parity). */ |
669 | 0 | static void TOBJ_T(apply_kd_default)(TOBJ_T(tobj_material) * m, bool kd_seen) { |
670 | 0 | if (!kd_seen && m->diffuse_texname && m->diffuse_texname[0] != '\0') { |
671 | 0 | m->diffuse[0] = m->diffuse[1] = m->diffuse[2] = (TOBJ_REAL)0.6; |
672 | 0 | } |
673 | 0 | } Unexecuted instantiation: tiny_obj_c.c:apply_kd_default_f Unexecuted instantiation: tiny_obj_c.c:apply_kd_default_d |
674 | | |
675 | | /* Full .mtl parser. */ |
676 | | static bool TOBJ_T(parse_mtl_buffer)(TOBJ_T(tobj_builder) * b, |
677 | 0 | const uint8_t *data, size_t len) { |
678 | 0 | tobj_vec lines; |
679 | 0 | tobj_vec_init(&lines, sizeof(tobj_line)); |
680 | 0 | if (!tobj_build_line_index(data, len, &lines, b->alloc)) { |
681 | 0 | tobj_vec_free(&lines, b->alloc); |
682 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
683 | 0 | } |
684 | 0 | const char *base = (const char *)data; |
685 | 0 | int cur = -1; |
686 | 0 | bool kd_seen = false; |
687 | 0 | for (size_t i = 0; i < lines.count && b->err == TOBJ_OK; i++) { |
688 | 0 | tobj_line *ln = (tobj_line *)tobj_vec_at(&lines, i); |
689 | 0 | if (ln->len > b->caps.line_bytes) continue; |
690 | 0 | tobj_cursor c; |
691 | 0 | tobj_cur_init(&c, base + ln->pos, ln->len); |
692 | 0 | const char *tok; |
693 | 0 | size_t tl; |
694 | 0 | if (!tobj_next_token(&c, &tok, &tl)) continue; |
695 | 0 | if (tl && tok[0] == '#') continue; |
696 | | |
697 | 0 | if (tobj_slice_eq(tok, tl, "newmtl")) { |
698 | 0 | if (cur >= 0) |
699 | 0 | TOBJ_T(apply_kd_default)( |
700 | 0 | (TOBJ_T(tobj_material) *)tobj_vec_at(&b->materials, (size_t)cur), |
701 | 0 | kd_seen); |
702 | 0 | if (b->materials.count >= b->caps.materials) { |
703 | 0 | TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); |
704 | 0 | break; |
705 | 0 | } |
706 | 0 | TOBJ_T(tobj_material) *m = |
707 | 0 | (TOBJ_T(tobj_material) *)tobj_vec_push(&b->materials, b->alloc); |
708 | 0 | if (!m) { |
709 | 0 | TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
710 | 0 | break; |
711 | 0 | } |
712 | 0 | TOBJ_T(material_init)(m, b->arena); |
713 | 0 | m->name = TOBJ_T(intern_rest)(b, &c); |
714 | 0 | cur = (int)(b->materials.count - 1); |
715 | 0 | kd_seen = false; |
716 | 0 | const char **k = (const char **)tobj_vec_push(&b->matmap_key, b->alloc); |
717 | 0 | int *id = (int *)tobj_vec_push(&b->matmap_id, b->alloc); |
718 | 0 | if (!k || !id) { |
719 | 0 | TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
720 | 0 | break; |
721 | 0 | } |
722 | 0 | *k = m->name; |
723 | 0 | *id = cur; |
724 | 0 | continue; |
725 | 0 | } |
726 | 0 | if (cur < 0) continue; |
727 | 0 | TOBJ_T(tobj_material) *m = |
728 | 0 | (TOBJ_T(tobj_material) *)tobj_vec_at(&b->materials, (size_t)cur); |
729 | |
|
730 | 0 | if (tobj_slice_eq(tok, tl, "Ka")) { |
731 | 0 | TOBJ_T(read_reals)(&c, m->ambient, 3); |
732 | 0 | } else if (tobj_slice_eq(tok, tl, "Kd")) { |
733 | 0 | TOBJ_T(read_reals)(&c, m->diffuse, 3); |
734 | 0 | kd_seen = true; |
735 | 0 | } else if (tobj_slice_eq(tok, tl, "Ks")) { |
736 | 0 | TOBJ_T(read_reals)(&c, m->specular, 3); |
737 | 0 | } else if (tobj_slice_eq(tok, tl, "Ke")) { |
738 | 0 | TOBJ_T(read_reals)(&c, m->emission, 3); |
739 | 0 | } else if (tobj_slice_eq(tok, tl, "Kt") || tobj_slice_eq(tok, tl, "Tf")) { |
740 | 0 | TOBJ_T(read_reals)(&c, m->transmittance, 3); |
741 | 0 | } else if (tobj_slice_eq(tok, tl, "Ns")) { |
742 | 0 | TOBJ_T(read_reals)(&c, &m->shininess, 1); |
743 | 0 | } else if (tobj_slice_eq(tok, tl, "Ni")) { |
744 | 0 | TOBJ_T(read_reals)(&c, &m->ior, 1); |
745 | 0 | } else if (tobj_slice_eq(tok, tl, "d")) { |
746 | 0 | TOBJ_T(read_reals)(&c, &m->dissolve, 1); |
747 | 0 | } else if (tobj_slice_eq(tok, tl, "Tr")) { |
748 | 0 | TOBJ_REAL tr = 0; |
749 | 0 | TOBJ_T(read_reals)(&c, &tr, 1); |
750 | 0 | m->dissolve = (TOBJ_REAL)1 - tr; |
751 | 0 | } else if (tobj_slice_eq(tok, tl, "illum")) { |
752 | 0 | int v = 0; |
753 | 0 | tobj_scan_int(&c.p, c.end, &v); |
754 | 0 | m->illum = v; |
755 | 0 | } else if (tobj_slice_eq(tok, tl, "Pr")) { |
756 | 0 | TOBJ_T(read_reals)(&c, &m->roughness, 1); |
757 | 0 | } else if (tobj_slice_eq(tok, tl, "Pm")) { |
758 | 0 | TOBJ_T(read_reals)(&c, &m->metallic, 1); |
759 | 0 | } else if (tobj_slice_eq(tok, tl, "Ps")) { |
760 | 0 | TOBJ_T(read_reals)(&c, &m->sheen, 1); |
761 | 0 | } else if (tobj_slice_eq(tok, tl, "Pc")) { |
762 | 0 | TOBJ_T(read_reals)(&c, &m->clearcoat_thickness, 1); |
763 | 0 | } else if (tobj_slice_eq(tok, tl, "Pcr")) { |
764 | 0 | TOBJ_T(read_reals)(&c, &m->clearcoat_roughness, 1); |
765 | 0 | } else if (tobj_slice_eq(tok, tl, "aniso")) { |
766 | 0 | TOBJ_T(read_reals)(&c, &m->anisotropy, 1); |
767 | 0 | } else if (tobj_slice_eq(tok, tl, "anisor")) { |
768 | 0 | TOBJ_T(read_reals)(&c, &m->anisotropy_rotation, 1); |
769 | 0 | } else if (tobj_slice_eq(tok, tl, "map_Ka")) { |
770 | 0 | m->ambient_texname = TOBJ_T(parse_texopt)(b, &c, &m->ambient_texopt); |
771 | 0 | } else if (tobj_slice_eq(tok, tl, "map_Kd")) { |
772 | 0 | m->diffuse_texname = TOBJ_T(parse_texopt)(b, &c, &m->diffuse_texopt); |
773 | 0 | } else if (tobj_slice_eq(tok, tl, "map_Ks")) { |
774 | 0 | m->specular_texname = TOBJ_T(parse_texopt)(b, &c, &m->specular_texopt); |
775 | 0 | } else if (tobj_slice_eq(tok, tl, "map_Ns")) { |
776 | 0 | m->specular_highlight_texname = |
777 | 0 | TOBJ_T(parse_texopt)(b, &c, &m->specular_highlight_texopt); |
778 | 0 | } else if (tobj_slice_eq(tok, tl, "map_d")) { |
779 | 0 | m->alpha_texname = TOBJ_T(parse_texopt)(b, &c, &m->alpha_texopt); |
780 | 0 | } else if (tobj_slice_eq(tok, tl, "map_bump") || |
781 | 0 | tobj_slice_eq(tok, tl, "map_Bump") || |
782 | 0 | tobj_slice_eq(tok, tl, "bump")) { |
783 | 0 | m->bump_texopt.imfchan = 'l'; |
784 | 0 | m->bump_texname = TOBJ_T(parse_texopt)(b, &c, &m->bump_texopt); |
785 | 0 | } else if (tobj_slice_eq(tok, tl, "disp")) { |
786 | 0 | m->displacement_texname = |
787 | 0 | TOBJ_T(parse_texopt)(b, &c, &m->displacement_texopt); |
788 | 0 | } else if (tobj_slice_eq(tok, tl, "refl")) { |
789 | 0 | m->reflection_texname = TOBJ_T(parse_texopt)(b, &c, &m->reflection_texopt); |
790 | 0 | } else if (tobj_slice_eq(tok, tl, "norm")) { |
791 | 0 | m->normal_texname = TOBJ_T(parse_texopt)(b, &c, &m->normal_texopt); |
792 | 0 | } else if (tobj_slice_eq(tok, tl, "map_Pr")) { |
793 | 0 | m->roughness_texname = TOBJ_T(parse_texopt)(b, &c, &m->roughness_texopt); |
794 | 0 | } else if (tobj_slice_eq(tok, tl, "map_Pm")) { |
795 | 0 | m->metallic_texname = TOBJ_T(parse_texopt)(b, &c, &m->metallic_texopt); |
796 | 0 | } else if (tobj_slice_eq(tok, tl, "map_Ps")) { |
797 | 0 | m->sheen_texname = TOBJ_T(parse_texopt)(b, &c, &m->sheen_texopt); |
798 | 0 | } else if (tobj_slice_eq(tok, tl, "map_Ke")) { |
799 | 0 | m->emissive_texname = TOBJ_T(parse_texopt)(b, &c, &m->emissive_texopt); |
800 | 0 | } else { |
801 | | /* unknown parameter: store key -> rest of line */ |
802 | 0 | if (!TOBJ_T(push_unknown)(b, (size_t)cur, tok, tl, &c)) break; |
803 | 0 | } |
804 | 0 | } |
805 | |
|
806 | 0 | if (cur >= 0) |
807 | 0 | TOBJ_T(apply_kd_default)( |
808 | 0 | (TOBJ_T(tobj_material) *)tobj_vec_at(&b->materials, (size_t)cur), |
809 | 0 | kd_seen); |
810 | 0 | tobj_vec_free(&lines, b->alloc); |
811 | 0 | return b->err == TOBJ_OK; |
812 | 0 | } Unexecuted instantiation: tiny_obj_c.c:parse_mtl_buffer_f Unexecuted instantiation: tiny_obj_c.c:parse_mtl_buffer_d |
813 | | |
814 | 259 | static bool TOBJ_T(handle_mtllib)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { |
815 | 259 | if (!b->cfg->mtl_resolver) { |
816 | 259 | TOBJ_T(b_warn)(b, "tinyobjc: mtllib present but no material resolver\n"); |
817 | 259 | return true; |
818 | 259 | } |
819 | 0 | const char *tok; |
820 | 0 | size_t tl; |
821 | 0 | while (tobj_next_token(c, &tok, &tl)) { |
822 | 0 | char *name = (char *)tobj_arena_alloc(b->arena, tl + 1, 1); |
823 | 0 | if (!name) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
824 | 0 | tobj_memcpy(name, tok, tl); |
825 | 0 | name[tl] = '\0'; |
826 | 0 | tobj_mtl_source src; |
827 | 0 | tobj_memset(&src, 0, sizeof src); |
828 | 0 | tobj_result r = |
829 | 0 | b->cfg->mtl_resolver(b->cfg->mtl_resolver_user_data, name, &src); |
830 | 0 | if (r != TOBJ_OK) { |
831 | 0 | TOBJ_T(b_warn)(b, "tinyobjc: failed to resolve mtllib\n"); |
832 | 0 | continue; |
833 | 0 | } |
834 | 0 | TOBJ_T(parse_mtl_buffer)(b, src.data, src.len); |
835 | 0 | if (src.release) src.release(src.release_ud, src.data, src.len); |
836 | 0 | if (b->err != TOBJ_OK) return false; |
837 | 0 | } |
838 | 0 | return true; |
839 | 0 | } tiny_obj_c.c:handle_mtllib_f Line | Count | Source | 814 | 259 | static bool TOBJ_T(handle_mtllib)(TOBJ_T(tobj_builder) * b, tobj_cursor *c) { | 815 | 259 | if (!b->cfg->mtl_resolver) { | 816 | 259 | TOBJ_T(b_warn)(b, "tinyobjc: mtllib present but no material resolver\n"); | 817 | 259 | return true; | 818 | 259 | } | 819 | 0 | const char *tok; | 820 | 0 | size_t tl; | 821 | 0 | while (tobj_next_token(c, &tok, &tl)) { | 822 | 0 | char *name = (char *)tobj_arena_alloc(b->arena, tl + 1, 1); | 823 | 0 | if (!name) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 824 | 0 | tobj_memcpy(name, tok, tl); | 825 | 0 | name[tl] = '\0'; | 826 | 0 | tobj_mtl_source src; | 827 | 0 | tobj_memset(&src, 0, sizeof src); | 828 | 0 | tobj_result r = | 829 | 0 | b->cfg->mtl_resolver(b->cfg->mtl_resolver_user_data, name, &src); | 830 | 0 | if (r != TOBJ_OK) { | 831 | 0 | TOBJ_T(b_warn)(b, "tinyobjc: failed to resolve mtllib\n"); | 832 | 0 | continue; | 833 | 0 | } | 834 | 0 | TOBJ_T(parse_mtl_buffer)(b, src.data, src.len); | 835 | 0 | if (src.release) src.release(src.release_ud, src.data, src.len); | 836 | 0 | if (b->err != TOBJ_OK) return false; | 837 | 0 | } | 838 | 0 | return true; | 839 | 0 | } |
Unexecuted instantiation: tiny_obj_c.c:handle_mtllib_d |
840 | | |
841 | | /* ----------------------------------------------------------------------- */ |
842 | | /* free-form geometry (parse & retain; no NURBS evaluation) */ |
843 | | /* ----------------------------------------------------------------------- */ |
844 | | |
845 | 0 | static void TOBJ_T(ff_reset_elem)(TOBJ_T(tobj_builder) * b) { |
846 | 0 | b->ff_active = false; |
847 | 0 | b->ff_kind = 0; |
848 | 0 | b->ff_cp_int.count = 0; |
849 | 0 | b->ff_cp_idx.count = 0; |
850 | 0 | b->ff_knu.count = 0; |
851 | 0 | b->ff_knv.count = 0; |
852 | 0 | b->ff_trim.count = 0; |
853 | 0 | b->ff_hole.count = 0; |
854 | 0 | b->ff_scrv.count = 0; |
855 | 0 | } Unexecuted instantiation: tiny_obj_c.c:ff_reset_elem_f Unexecuted instantiation: tiny_obj_c.c:ff_reset_elem_d |
856 | | |
857 | 0 | static bool TOBJ_T(ff_finalize_elem)(TOBJ_T(tobj_builder) * b) { |
858 | 0 | if (!b->ff_active) return true; |
859 | 0 | if (b->ff_kind == 1) { /* curv */ |
860 | 0 | TOBJ_T(tobj_curve) *cv = |
861 | 0 | (TOBJ_T(tobj_curve) *)tobj_vec_push(&b->sh_curves, b->alloc); |
862 | 0 | if (!cv) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
863 | 0 | cv->type = b->ff_cstype; |
864 | 0 | cv->rational = b->ff_rational; |
865 | 0 | cv->degree = b->ff_degu; |
866 | 0 | cv->u0 = b->ff_u0; |
867 | 0 | cv->u1 = b->ff_u1; |
868 | 0 | cv->num_control_points = b->ff_cp_int.count; |
869 | 0 | cv->control_points = (int *)tobj_vec_finalize(&b->ff_cp_int, b->arena, 16); |
870 | 0 | cv->num_knots = b->ff_knu.count; |
871 | 0 | cv->knots = (TOBJ_REAL *)tobj_vec_finalize(&b->ff_knu, b->arena, 16); |
872 | 0 | if ((cv->num_control_points && !cv->control_points) || |
873 | 0 | (cv->num_knots && !cv->knots)) |
874 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
875 | 0 | } else if (b->ff_kind == 2) { /* curv2 */ |
876 | 0 | TOBJ_T(tobj_curve2) *cv = |
877 | 0 | (TOBJ_T(tobj_curve2) *)tobj_vec_push(&b->sh_curves2, b->alloc); |
878 | 0 | if (!cv) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
879 | 0 | cv->type = b->ff_cstype; |
880 | 0 | cv->rational = b->ff_rational; |
881 | 0 | cv->degree = b->ff_degu; |
882 | 0 | cv->num_control_points = b->ff_cp_int.count; |
883 | 0 | cv->control_points = (int *)tobj_vec_finalize(&b->ff_cp_int, b->arena, 16); |
884 | 0 | cv->num_knots = b->ff_knu.count; |
885 | 0 | cv->knots = (TOBJ_REAL *)tobj_vec_finalize(&b->ff_knu, b->arena, 16); |
886 | 0 | if ((cv->num_control_points && !cv->control_points) || |
887 | 0 | (cv->num_knots && !cv->knots)) |
888 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
889 | 0 | } else if (b->ff_kind == 3) { /* surf */ |
890 | 0 | TOBJ_T(tobj_surface) *sf = |
891 | 0 | (TOBJ_T(tobj_surface) *)tobj_vec_push(&b->sh_surfaces, b->alloc); |
892 | 0 | if (!sf) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
893 | 0 | sf->type = b->ff_cstype; |
894 | 0 | sf->rational = b->ff_rational; |
895 | 0 | sf->degu = b->ff_degu; |
896 | 0 | sf->degv = b->ff_degv; |
897 | 0 | sf->s0 = b->ff_s0; |
898 | 0 | sf->s1 = b->ff_s1; |
899 | 0 | sf->t0 = b->ff_t0; |
900 | 0 | sf->t1 = b->ff_t1; |
901 | 0 | sf->num_control_points = b->ff_cp_idx.count; |
902 | 0 | sf->control_points = |
903 | 0 | (tobj_index *)tobj_vec_finalize(&b->ff_cp_idx, b->arena, 16); |
904 | 0 | sf->num_knots_u = b->ff_knu.count; |
905 | 0 | sf->knots_u = (TOBJ_REAL *)tobj_vec_finalize(&b->ff_knu, b->arena, 16); |
906 | 0 | sf->num_knots_v = b->ff_knv.count; |
907 | 0 | sf->knots_v = (TOBJ_REAL *)tobj_vec_finalize(&b->ff_knv, b->arena, 16); |
908 | 0 | sf->num_trims = b->ff_trim.count; |
909 | 0 | sf->trims = (TOBJ_T(tobj_trim_loop) *)tobj_vec_finalize(&b->ff_trim, |
910 | 0 | b->arena, 16); |
911 | 0 | sf->num_holes = b->ff_hole.count; |
912 | 0 | sf->holes = (TOBJ_T(tobj_trim_loop) *)tobj_vec_finalize(&b->ff_hole, |
913 | 0 | b->arena, 16); |
914 | 0 | sf->num_scrvs = b->ff_scrv.count; |
915 | 0 | sf->scrvs = (TOBJ_T(tobj_trim_loop) *)tobj_vec_finalize(&b->ff_scrv, |
916 | 0 | b->arena, 16); |
917 | 0 | } |
918 | 0 | b->ff_present = true; |
919 | 0 | TOBJ_T(ff_reset_elem)(b); |
920 | 0 | return true; |
921 | 0 | } Unexecuted instantiation: tiny_obj_c.c:ff_finalize_elem_f Unexecuted instantiation: tiny_obj_c.c:ff_finalize_elem_d |
922 | | |
923 | | static void TOBJ_T(ff_loops)(TOBJ_T(tobj_builder) * b, tobj_cursor *c, |
924 | 0 | tobj_vec *dst) { |
925 | 0 | double u0, u1; |
926 | 0 | int idx; |
927 | 0 | while (tobj_scan_double(&c->p, c->end, &u0)) { |
928 | 0 | if (!tobj_scan_double(&c->p, c->end, &u1)) break; |
929 | 0 | if (!tobj_scan_int(&c->p, c->end, &idx)) break; |
930 | 0 | TOBJ_T(tobj_trim_loop) *t = |
931 | 0 | (TOBJ_T(tobj_trim_loop) *)tobj_vec_push(dst, b->alloc); |
932 | 0 | if (!t) { |
933 | 0 | TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
934 | 0 | return; |
935 | 0 | } |
936 | 0 | t->u0 = (TOBJ_REAL)u0; |
937 | 0 | t->u1 = (TOBJ_REAL)u1; |
938 | 0 | t->curve2_index = idx; |
939 | 0 | } |
940 | 0 | } Unexecuted instantiation: tiny_obj_c.c:ff_loops_f Unexecuted instantiation: tiny_obj_c.c:ff_loops_d |
941 | | |
942 | | static bool TOBJ_T(handle_freeform)(TOBJ_T(tobj_builder) * b, const char *tok, |
943 | 0 | size_t tl, tobj_cursor *c) { |
944 | 0 | if (tobj_slice_eq(tok, tl, "vp")) { |
945 | 0 | double d; |
946 | 0 | int n = 0; |
947 | 0 | TOBJ_REAL uvw[3] = {0, 0, 0}; |
948 | 0 | for (; n < 3; n++) { |
949 | 0 | if (!tobj_scan_double(&c->p, c->end, &d)) break; |
950 | 0 | uvw[n] = (TOBJ_REAL)d; |
951 | 0 | } |
952 | 0 | if (n < 1) return true; |
953 | 0 | if (n > b->ff_vp_comps) b->ff_vp_comps = n; |
954 | 0 | return tobj_vec_append(&b->ff_vp, uvw, (size_t)n, b->alloc) |
955 | 0 | ? true |
956 | 0 | : TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
957 | 0 | } |
958 | 0 | if (tobj_slice_eq(tok, tl, "cstype")) { |
959 | 0 | const char *t2; |
960 | 0 | size_t l2; |
961 | 0 | b->ff_rational = false; |
962 | 0 | b->ff_cstype = TOBJ_CSTYPE_NONE; |
963 | 0 | while (tobj_next_token(c, &t2, &l2)) { |
964 | 0 | if (tobj_slice_eq(t2, l2, "rat")) |
965 | 0 | b->ff_rational = true; |
966 | 0 | else if (tobj_slice_eq(t2, l2, "bmatrix")) |
967 | 0 | b->ff_cstype = TOBJ_CSTYPE_BMATRIX; |
968 | 0 | else if (tobj_slice_eq(t2, l2, "bezier")) |
969 | 0 | b->ff_cstype = TOBJ_CSTYPE_BEZIER; |
970 | 0 | else if (tobj_slice_eq(t2, l2, "bspline")) |
971 | 0 | b->ff_cstype = TOBJ_CSTYPE_BSPLINE; |
972 | 0 | else if (tobj_slice_eq(t2, l2, "cardinal")) |
973 | 0 | b->ff_cstype = TOBJ_CSTYPE_CARDINAL; |
974 | 0 | else if (tobj_slice_eq(t2, l2, "taylor")) |
975 | 0 | b->ff_cstype = TOBJ_CSTYPE_TAYLOR; |
976 | 0 | } |
977 | 0 | return true; |
978 | 0 | } |
979 | 0 | if (tobj_slice_eq(tok, tl, "deg")) { |
980 | 0 | int du = 0, dv = 0; |
981 | 0 | if (tobj_scan_int(&c->p, c->end, &du)) b->ff_degu = du; |
982 | 0 | if (tobj_scan_int(&c->p, c->end, &dv)) b->ff_degv = dv; |
983 | 0 | return true; |
984 | 0 | } |
985 | 0 | if (tobj_slice_eq(tok, tl, "curv")) { |
986 | 0 | TOBJ_T(ff_reset_elem)(b); |
987 | 0 | b->ff_active = true; |
988 | 0 | b->ff_kind = 1; |
989 | 0 | double a, bb; |
990 | 0 | b->ff_u0 = tobj_scan_double(&c->p, c->end, &a) ? (TOBJ_REAL)a : (TOBJ_REAL)0; |
991 | 0 | b->ff_u1 = tobj_scan_double(&c->p, c->end, &bb) ? (TOBJ_REAL)bb : (TOBJ_REAL)0; |
992 | 0 | int vi; |
993 | 0 | size_t numv = TOBJ_T(cnt_v)(b); |
994 | 0 | while (tobj_scan_int(&c->p, c->end, &vi)) { |
995 | 0 | int r; |
996 | 0 | TOBJ_T(fix_index)(vi, numv, &r); |
997 | 0 | if (!tobj_vec_append(&b->ff_cp_int, &r, 1, b->alloc)) |
998 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
999 | 0 | } |
1000 | 0 | return true; |
1001 | 0 | } |
1002 | 0 | if (tobj_slice_eq(tok, tl, "curv2")) { |
1003 | 0 | TOBJ_T(ff_reset_elem)(b); |
1004 | 0 | b->ff_active = true; |
1005 | 0 | b->ff_kind = 2; |
1006 | 0 | int vi; |
1007 | 0 | size_t numvp = b->prefilled |
1008 | 0 | ? b->run_numvp |
1009 | 0 | : (b->ff_vp_comps ? b->ff_vp.count / (size_t)b->ff_vp_comps |
1010 | 0 | : 0); |
1011 | 0 | while (tobj_scan_int(&c->p, c->end, &vi)) { |
1012 | 0 | int r; |
1013 | 0 | TOBJ_T(fix_index)(vi, numvp, &r); |
1014 | 0 | if (!tobj_vec_append(&b->ff_cp_int, &r, 1, b->alloc)) |
1015 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
1016 | 0 | } |
1017 | 0 | return true; |
1018 | 0 | } |
1019 | 0 | if (tobj_slice_eq(tok, tl, "surf")) { |
1020 | 0 | TOBJ_T(ff_reset_elem)(b); |
1021 | 0 | b->ff_active = true; |
1022 | 0 | b->ff_kind = 3; |
1023 | 0 | double s0, s1, t0, t1; |
1024 | 0 | b->ff_s0 = tobj_scan_double(&c->p, c->end, &s0) ? (TOBJ_REAL)s0 : 0; |
1025 | 0 | b->ff_s1 = tobj_scan_double(&c->p, c->end, &s1) ? (TOBJ_REAL)s1 : 0; |
1026 | 0 | b->ff_t0 = tobj_scan_double(&c->p, c->end, &t0) ? (TOBJ_REAL)t0 : 0; |
1027 | 0 | b->ff_t1 = tobj_scan_double(&c->p, c->end, &t1) ? (TOBJ_REAL)t1 : 0; |
1028 | 0 | const char *t2; |
1029 | 0 | size_t l2; |
1030 | 0 | while (tobj_next_token(c, &t2, &l2)) { |
1031 | 0 | tobj_index idx; |
1032 | 0 | TOBJ_T(parse_corner_n)(t2, l2, TOBJ_T(cnt_v)(b), TOBJ_T(cnt_vt)(b), |
1033 | 0 | TOBJ_T(cnt_vn)(b), &idx); |
1034 | 0 | if (!tobj_vec_append(&b->ff_cp_idx, &idx, 1, b->alloc)) |
1035 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
1036 | 0 | } |
1037 | 0 | return true; |
1038 | 0 | } |
1039 | 0 | if (tobj_slice_eq(tok, tl, "parm")) { |
1040 | 0 | const char *t2; |
1041 | 0 | size_t l2; |
1042 | 0 | if (!tobj_next_token(c, &t2, &l2)) return true; |
1043 | 0 | tobj_vec *dst = tobj_slice_eq(t2, l2, "v") ? &b->ff_knv : &b->ff_knu; |
1044 | 0 | double d; |
1045 | 0 | while (tobj_scan_double(&c->p, c->end, &d)) { |
1046 | 0 | TOBJ_REAL r = (TOBJ_REAL)d; |
1047 | 0 | if (!tobj_vec_append(dst, &r, 1, b->alloc)) |
1048 | 0 | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
1049 | 0 | } |
1050 | 0 | return true; |
1051 | 0 | } |
1052 | 0 | if (tobj_slice_eq(tok, tl, "trim")) { |
1053 | 0 | TOBJ_T(ff_loops)(b, c, &b->ff_trim); |
1054 | 0 | return b->err == TOBJ_OK; |
1055 | 0 | } |
1056 | 0 | if (tobj_slice_eq(tok, tl, "hole")) { |
1057 | 0 | TOBJ_T(ff_loops)(b, c, &b->ff_hole); |
1058 | 0 | return b->err == TOBJ_OK; |
1059 | 0 | } |
1060 | 0 | if (tobj_slice_eq(tok, tl, "scrv")) { |
1061 | 0 | TOBJ_T(ff_loops)(b, c, &b->ff_scrv); |
1062 | 0 | return b->err == TOBJ_OK; |
1063 | 0 | } |
1064 | 0 | if (tobj_slice_eq(tok, tl, "end")) { |
1065 | 0 | return TOBJ_T(ff_finalize_elem)(b); |
1066 | 0 | } |
1067 | | /* sp / con / bmat / step etc.: recognized but not retained */ |
1068 | 0 | return true; |
1069 | 0 | } Unexecuted instantiation: tiny_obj_c.c:handle_freeform_f Unexecuted instantiation: tiny_obj_c.c:handle_freeform_d |
1070 | | |
1071 | | /* ----------------------------------------------------------------------- */ |
1072 | | /* line dispatch */ |
1073 | | /* ----------------------------------------------------------------------- */ |
1074 | | |
1075 | | static bool TOBJ_T(dispatch_line)(TOBJ_T(tobj_builder) * b, const char *p, |
1076 | 15.9M | size_t len) { |
1077 | 15.9M | if (len > b->caps.line_bytes) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); |
1078 | 15.9M | tobj_cursor c; |
1079 | 15.9M | tobj_cur_init(&c, p, len); |
1080 | 15.9M | const char *tok; |
1081 | 15.9M | size_t tl; |
1082 | 15.9M | if (!tobj_next_token(&c, &tok, &tl)) return true; |
1083 | 14.7M | if (tok[0] == '#') return true; |
1084 | | |
1085 | | /* In MT pass 2 the vertex data is already parsed; just advance the running |
1086 | | * counts used for relative-index resolution. */ |
1087 | 14.7M | if (b->prefilled) { |
1088 | 0 | if (tobj_slice_eq(tok, tl, "v")) { |
1089 | 0 | b->run_numv++; |
1090 | 0 | return true; |
1091 | 0 | } |
1092 | 0 | if (tobj_slice_eq(tok, tl, "vn")) { |
1093 | 0 | b->run_numvn++; |
1094 | 0 | return true; |
1095 | 0 | } |
1096 | 0 | if (tobj_slice_eq(tok, tl, "vt")) { |
1097 | 0 | b->run_numvt++; |
1098 | 0 | return true; |
1099 | 0 | } |
1100 | 0 | if (tobj_slice_eq(tok, tl, "vp")) { |
1101 | 0 | b->run_numvp++; |
1102 | 0 | return true; |
1103 | 0 | } |
1104 | 0 | } |
1105 | | |
1106 | 14.7M | if (tobj_slice_eq(tok, tl, "v")) return TOBJ_T(handle_v)(b, &c); |
1107 | 5.78M | if (tobj_slice_eq(tok, tl, "vn")) return TOBJ_T(handle_vn)(b, &c); |
1108 | 4.05M | if (tobj_slice_eq(tok, tl, "vt")) return TOBJ_T(handle_vt)(b, &c); |
1109 | 2.00M | if (tobj_slice_eq(tok, tl, "f")) return TOBJ_T(handle_f)(b, &c); |
1110 | 1.93M | if (tobj_slice_eq(tok, tl, "l")) return TOBJ_T(handle_l)(b, &c); |
1111 | 1.44M | if (tobj_slice_eq(tok, tl, "p")) return TOBJ_T(handle_p)(b, &c); |
1112 | 1.10M | if (tobj_slice_eq(tok, tl, "g") || tobj_slice_eq(tok, tl, "o")) { |
1113 | 379k | const char *name = TOBJ_T(intern_rest)(b, &c); |
1114 | 379k | if (!name) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
1115 | 379k | return TOBJ_T(new_group)(b, name); |
1116 | 379k | } |
1117 | 729k | if (tobj_slice_eq(tok, tl, "s")) { |
1118 | 18.7k | const char *st; |
1119 | 18.7k | size_t sl; |
1120 | 18.7k | if (tobj_next_token(&c, &st, &sl)) { |
1121 | 16.2k | if (tobj_slice_eq(st, sl, "off")) { |
1122 | 4.33k | b->cur_smooth = 0; |
1123 | 11.8k | } else { |
1124 | 11.8k | const char *q = st; |
1125 | 11.8k | int v = 0; |
1126 | 11.8k | tobj_scan_int(&q, st + sl, &v); |
1127 | 11.8k | b->cur_smooth = v > 0 ? (unsigned)v : 0u; |
1128 | 11.8k | } |
1129 | 16.2k | } |
1130 | 18.7k | return true; |
1131 | 18.7k | } |
1132 | 711k | if (tobj_slice_eq(tok, tl, "usemtl")) { |
1133 | 581 | const char *name = c.p; |
1134 | 1.81k | while (name < c.end && tobj_is_space(*name)) name++; |
1135 | 581 | const char *e = c.end; |
1136 | 1.11k | while (e > name && tobj_is_space(e[-1])) e--; |
1137 | 581 | int id = TOBJ_T(mat_find)(b, name, (size_t)(e - name)); |
1138 | 581 | if (id < 0) TOBJ_T(b_warn)(b, "tinyobjc: usemtl references unknown material\n"); |
1139 | 581 | b->cur_material = id; |
1140 | 581 | return true; |
1141 | 581 | } |
1142 | 710k | if (tobj_slice_eq(tok, tl, "mtllib")) return TOBJ_T(handle_mtllib)(b, &c); |
1143 | 710k | if (b->cfg->parse_freeform) return TOBJ_T(handle_freeform)(b, tok, tl, &c); |
1144 | | /* unrecognized directive: silently skipped */ |
1145 | 710k | return true; |
1146 | 710k | } tiny_obj_c.c:dispatch_line_f Line | Count | Source | 1076 | 15.9M | size_t len) { | 1077 | 15.9M | if (len > b->caps.line_bytes) return TOBJ_T(b_fail)(b, TOBJ_ERR_LIMIT_EXCEEDED); | 1078 | 15.9M | tobj_cursor c; | 1079 | 15.9M | tobj_cur_init(&c, p, len); | 1080 | 15.9M | const char *tok; | 1081 | 15.9M | size_t tl; | 1082 | 15.9M | if (!tobj_next_token(&c, &tok, &tl)) return true; | 1083 | 14.7M | if (tok[0] == '#') return true; | 1084 | | | 1085 | | /* In MT pass 2 the vertex data is already parsed; just advance the running | 1086 | | * counts used for relative-index resolution. */ | 1087 | 14.7M | if (b->prefilled) { | 1088 | 0 | if (tobj_slice_eq(tok, tl, "v")) { | 1089 | 0 | b->run_numv++; | 1090 | 0 | return true; | 1091 | 0 | } | 1092 | 0 | if (tobj_slice_eq(tok, tl, "vn")) { | 1093 | 0 | b->run_numvn++; | 1094 | 0 | return true; | 1095 | 0 | } | 1096 | 0 | if (tobj_slice_eq(tok, tl, "vt")) { | 1097 | 0 | b->run_numvt++; | 1098 | 0 | return true; | 1099 | 0 | } | 1100 | 0 | if (tobj_slice_eq(tok, tl, "vp")) { | 1101 | 0 | b->run_numvp++; | 1102 | 0 | return true; | 1103 | 0 | } | 1104 | 0 | } | 1105 | | | 1106 | 14.7M | if (tobj_slice_eq(tok, tl, "v")) return TOBJ_T(handle_v)(b, &c); | 1107 | 5.78M | if (tobj_slice_eq(tok, tl, "vn")) return TOBJ_T(handle_vn)(b, &c); | 1108 | 4.05M | if (tobj_slice_eq(tok, tl, "vt")) return TOBJ_T(handle_vt)(b, &c); | 1109 | 2.00M | if (tobj_slice_eq(tok, tl, "f")) return TOBJ_T(handle_f)(b, &c); | 1110 | 1.93M | if (tobj_slice_eq(tok, tl, "l")) return TOBJ_T(handle_l)(b, &c); | 1111 | 1.44M | if (tobj_slice_eq(tok, tl, "p")) return TOBJ_T(handle_p)(b, &c); | 1112 | 1.10M | if (tobj_slice_eq(tok, tl, "g") || tobj_slice_eq(tok, tl, "o")) { | 1113 | 379k | const char *name = TOBJ_T(intern_rest)(b, &c); | 1114 | 379k | if (!name) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 1115 | 379k | return TOBJ_T(new_group)(b, name); | 1116 | 379k | } | 1117 | 729k | if (tobj_slice_eq(tok, tl, "s")) { | 1118 | 18.7k | const char *st; | 1119 | 18.7k | size_t sl; | 1120 | 18.7k | if (tobj_next_token(&c, &st, &sl)) { | 1121 | 16.2k | if (tobj_slice_eq(st, sl, "off")) { | 1122 | 4.33k | b->cur_smooth = 0; | 1123 | 11.8k | } else { | 1124 | 11.8k | const char *q = st; | 1125 | 11.8k | int v = 0; | 1126 | 11.8k | tobj_scan_int(&q, st + sl, &v); | 1127 | 11.8k | b->cur_smooth = v > 0 ? (unsigned)v : 0u; | 1128 | 11.8k | } | 1129 | 16.2k | } | 1130 | 18.7k | return true; | 1131 | 18.7k | } | 1132 | 711k | if (tobj_slice_eq(tok, tl, "usemtl")) { | 1133 | 581 | const char *name = c.p; | 1134 | 1.81k | while (name < c.end && tobj_is_space(*name)) name++; | 1135 | 581 | const char *e = c.end; | 1136 | 1.11k | while (e > name && tobj_is_space(e[-1])) e--; | 1137 | 581 | int id = TOBJ_T(mat_find)(b, name, (size_t)(e - name)); | 1138 | 581 | if (id < 0) TOBJ_T(b_warn)(b, "tinyobjc: usemtl references unknown material\n"); | 1139 | 581 | b->cur_material = id; | 1140 | 581 | return true; | 1141 | 581 | } | 1142 | 710k | if (tobj_slice_eq(tok, tl, "mtllib")) return TOBJ_T(handle_mtllib)(b, &c); | 1143 | 710k | if (b->cfg->parse_freeform) return TOBJ_T(handle_freeform)(b, tok, tl, &c); | 1144 | | /* unrecognized directive: silently skipped */ | 1145 | 710k | return true; | 1146 | 710k | } |
Unexecuted instantiation: tiny_obj_c.c:dispatch_line_d |
1147 | | |
1148 | | /* ----------------------------------------------------------------------- */ |
1149 | | /* public entry points */ |
1150 | | /* ----------------------------------------------------------------------- */ |
1151 | | |
1152 | | /* Group pending unknown params by material, sort by key, attach to materials. */ |
1153 | 3.65k | static bool TOBJ_T(finalize_unknowns)(TOBJ_T(tobj_builder) * b) { |
1154 | 3.65k | if (b->mat_unknown.count == 0) return true; |
1155 | 0 | const tobj_pending_kv *pend = (const tobj_pending_kv *)b->mat_unknown.data; |
1156 | 0 | for (size_t mi = 0; mi < b->materials.count; mi++) { |
1157 | 0 | size_t cnt = 0; |
1158 | 0 | for (size_t j = 0; j < b->mat_unknown.count; j++) |
1159 | 0 | if (pend[j].mat_index == mi) cnt++; |
1160 | 0 | if (cnt == 0) continue; |
1161 | 0 | tobj_kv *arr = (tobj_kv *)tobj_arena_alloc(b->arena, cnt * sizeof(tobj_kv), |
1162 | 0 | 16); |
1163 | 0 | if (!arr) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
1164 | 0 | size_t w = 0; |
1165 | 0 | for (size_t j = 0; j < b->mat_unknown.count; j++) { |
1166 | 0 | if (pend[j].mat_index != mi) continue; |
1167 | | /* stable insertion sort by key; equal keys keep insertion order */ |
1168 | 0 | size_t pos = w; |
1169 | 0 | while (pos > 0 && tobj_strcmp(arr[pos - 1].key, pend[j].key) > 0) { |
1170 | 0 | arr[pos] = arr[pos - 1]; |
1171 | 0 | pos--; |
1172 | 0 | } |
1173 | 0 | arr[pos].key = pend[j].key; |
1174 | 0 | arr[pos].value = pend[j].value; |
1175 | 0 | w++; |
1176 | 0 | } |
1177 | 0 | TOBJ_T(tobj_material) *m = |
1178 | 0 | (TOBJ_T(tobj_material) *)tobj_vec_at(&b->materials, mi); |
1179 | 0 | m->unknown_params = arr; |
1180 | 0 | m->num_unknown_params = w; |
1181 | 0 | } |
1182 | 0 | return true; |
1183 | 0 | } tiny_obj_c.c:finalize_unknowns_f Line | Count | Source | 1153 | 3.65k | static bool TOBJ_T(finalize_unknowns)(TOBJ_T(tobj_builder) * b) { | 1154 | 3.65k | if (b->mat_unknown.count == 0) return true; | 1155 | 0 | const tobj_pending_kv *pend = (const tobj_pending_kv *)b->mat_unknown.data; | 1156 | 0 | for (size_t mi = 0; mi < b->materials.count; mi++) { | 1157 | 0 | size_t cnt = 0; | 1158 | 0 | for (size_t j = 0; j < b->mat_unknown.count; j++) | 1159 | 0 | if (pend[j].mat_index == mi) cnt++; | 1160 | 0 | if (cnt == 0) continue; | 1161 | 0 | tobj_kv *arr = (tobj_kv *)tobj_arena_alloc(b->arena, cnt * sizeof(tobj_kv), | 1162 | 0 | 16); | 1163 | 0 | if (!arr) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); | 1164 | 0 | size_t w = 0; | 1165 | 0 | for (size_t j = 0; j < b->mat_unknown.count; j++) { | 1166 | 0 | if (pend[j].mat_index != mi) continue; | 1167 | | /* stable insertion sort by key; equal keys keep insertion order */ | 1168 | 0 | size_t pos = w; | 1169 | 0 | while (pos > 0 && tobj_strcmp(arr[pos - 1].key, pend[j].key) > 0) { | 1170 | 0 | arr[pos] = arr[pos - 1]; | 1171 | 0 | pos--; | 1172 | 0 | } | 1173 | 0 | arr[pos].key = pend[j].key; | 1174 | 0 | arr[pos].value = pend[j].value; | 1175 | 0 | w++; | 1176 | 0 | } | 1177 | 0 | TOBJ_T(tobj_material) *m = | 1178 | 0 | (TOBJ_T(tobj_material) *)tobj_vec_at(&b->materials, mi); | 1179 | 0 | m->unknown_params = arr; | 1180 | 0 | m->num_unknown_params = w; | 1181 | 0 | } | 1182 | 0 | return true; | 1183 | 0 | } |
Unexecuted instantiation: tiny_obj_c.c:finalize_unknowns_d |
1184 | | |
1185 | 3.65k | static void TOBJ_T(builder_init)(TOBJ_T(tobj_builder) * b) { |
1186 | 3.65k | tobj_vec_init(&b->av, sizeof(TOBJ_REAL)); |
1187 | 3.65k | tobj_vec_init(&b->avw, sizeof(TOBJ_REAL)); |
1188 | 3.65k | tobj_vec_init(&b->avn, sizeof(TOBJ_REAL)); |
1189 | 3.65k | tobj_vec_init(&b->avt, sizeof(TOBJ_REAL)); |
1190 | 3.65k | tobj_vec_init(&b->avtw, sizeof(TOBJ_REAL)); |
1191 | 3.65k | tobj_vec_init(&b->acol, sizeof(TOBJ_REAL)); |
1192 | 3.65k | tobj_vec_init(&b->materials, sizeof(TOBJ_T(tobj_material))); |
1193 | 3.65k | tobj_vec_init(&b->matmap_key, sizeof(const char *)); |
1194 | 3.65k | tobj_vec_init(&b->matmap_id, sizeof(int)); |
1195 | 3.65k | tobj_vec_init(&b->mat_unknown, sizeof(tobj_pending_kv)); |
1196 | 3.65k | tobj_vec_init(&b->shapes, sizeof(TOBJ_T(tobj_shape))); |
1197 | 3.65k | tobj_vec_init(&b->m_idx, sizeof(tobj_index)); |
1198 | 3.65k | tobj_vec_init(&b->m_fv, sizeof(unsigned)); |
1199 | 3.65k | tobj_vec_init(&b->m_mid, sizeof(int)); |
1200 | 3.65k | tobj_vec_init(&b->m_sg, sizeof(unsigned)); |
1201 | 3.65k | tobj_vec_init(&b->l_idx, sizeof(tobj_index)); |
1202 | 3.65k | tobj_vec_init(&b->l_cnt, sizeof(int)); |
1203 | 3.65k | tobj_vec_init(&b->p_idx, sizeof(tobj_index)); |
1204 | 3.65k | tobj_vec_init(&b->corners, sizeof(tobj_index)); |
1205 | 3.65k | tobj_vec_init(&b->ringpos, sizeof(TOBJ_REAL)); |
1206 | 3.65k | tobj_vec_init(&b->tris, sizeof(uint32_t)); |
1207 | 3.65k | tobj_vec_init(&b->tscratch, 1); |
1208 | 3.65k | tobj_vec_init(&b->ff_vp, sizeof(TOBJ_REAL)); |
1209 | 3.65k | tobj_vec_init(&b->ff_cp_int, sizeof(int)); |
1210 | 3.65k | tobj_vec_init(&b->ff_cp_idx, sizeof(tobj_index)); |
1211 | 3.65k | tobj_vec_init(&b->ff_knu, sizeof(TOBJ_REAL)); |
1212 | 3.65k | tobj_vec_init(&b->ff_knv, sizeof(TOBJ_REAL)); |
1213 | 3.65k | tobj_vec_init(&b->ff_trim, sizeof(TOBJ_T(tobj_trim_loop))); |
1214 | 3.65k | tobj_vec_init(&b->ff_hole, sizeof(TOBJ_T(tobj_trim_loop))); |
1215 | 3.65k | tobj_vec_init(&b->ff_scrv, sizeof(TOBJ_T(tobj_trim_loop))); |
1216 | 3.65k | tobj_vec_init(&b->sh_curves, sizeof(TOBJ_T(tobj_curve))); |
1217 | 3.65k | tobj_vec_init(&b->sh_curves2, sizeof(TOBJ_T(tobj_curve2))); |
1218 | 3.65k | tobj_vec_init(&b->sh_surfaces, sizeof(TOBJ_T(tobj_surface))); |
1219 | 3.65k | b->ff_degu = 0; |
1220 | 3.65k | b->ff_degv = 0; |
1221 | 3.65k | } tiny_obj_c.c:builder_init_f Line | Count | Source | 1185 | 3.65k | static void TOBJ_T(builder_init)(TOBJ_T(tobj_builder) * b) { | 1186 | 3.65k | tobj_vec_init(&b->av, sizeof(TOBJ_REAL)); | 1187 | 3.65k | tobj_vec_init(&b->avw, sizeof(TOBJ_REAL)); | 1188 | 3.65k | tobj_vec_init(&b->avn, sizeof(TOBJ_REAL)); | 1189 | 3.65k | tobj_vec_init(&b->avt, sizeof(TOBJ_REAL)); | 1190 | 3.65k | tobj_vec_init(&b->avtw, sizeof(TOBJ_REAL)); | 1191 | 3.65k | tobj_vec_init(&b->acol, sizeof(TOBJ_REAL)); | 1192 | 3.65k | tobj_vec_init(&b->materials, sizeof(TOBJ_T(tobj_material))); | 1193 | 3.65k | tobj_vec_init(&b->matmap_key, sizeof(const char *)); | 1194 | 3.65k | tobj_vec_init(&b->matmap_id, sizeof(int)); | 1195 | 3.65k | tobj_vec_init(&b->mat_unknown, sizeof(tobj_pending_kv)); | 1196 | 3.65k | tobj_vec_init(&b->shapes, sizeof(TOBJ_T(tobj_shape))); | 1197 | 3.65k | tobj_vec_init(&b->m_idx, sizeof(tobj_index)); | 1198 | 3.65k | tobj_vec_init(&b->m_fv, sizeof(unsigned)); | 1199 | 3.65k | tobj_vec_init(&b->m_mid, sizeof(int)); | 1200 | 3.65k | tobj_vec_init(&b->m_sg, sizeof(unsigned)); | 1201 | 3.65k | tobj_vec_init(&b->l_idx, sizeof(tobj_index)); | 1202 | 3.65k | tobj_vec_init(&b->l_cnt, sizeof(int)); | 1203 | 3.65k | tobj_vec_init(&b->p_idx, sizeof(tobj_index)); | 1204 | 3.65k | tobj_vec_init(&b->corners, sizeof(tobj_index)); | 1205 | 3.65k | tobj_vec_init(&b->ringpos, sizeof(TOBJ_REAL)); | 1206 | 3.65k | tobj_vec_init(&b->tris, sizeof(uint32_t)); | 1207 | 3.65k | tobj_vec_init(&b->tscratch, 1); | 1208 | 3.65k | tobj_vec_init(&b->ff_vp, sizeof(TOBJ_REAL)); | 1209 | 3.65k | tobj_vec_init(&b->ff_cp_int, sizeof(int)); | 1210 | 3.65k | tobj_vec_init(&b->ff_cp_idx, sizeof(tobj_index)); | 1211 | 3.65k | tobj_vec_init(&b->ff_knu, sizeof(TOBJ_REAL)); | 1212 | 3.65k | tobj_vec_init(&b->ff_knv, sizeof(TOBJ_REAL)); | 1213 | 3.65k | tobj_vec_init(&b->ff_trim, sizeof(TOBJ_T(tobj_trim_loop))); | 1214 | 3.65k | tobj_vec_init(&b->ff_hole, sizeof(TOBJ_T(tobj_trim_loop))); | 1215 | 3.65k | tobj_vec_init(&b->ff_scrv, sizeof(TOBJ_T(tobj_trim_loop))); | 1216 | 3.65k | tobj_vec_init(&b->sh_curves, sizeof(TOBJ_T(tobj_curve))); | 1217 | 3.65k | tobj_vec_init(&b->sh_curves2, sizeof(TOBJ_T(tobj_curve2))); | 1218 | 3.65k | tobj_vec_init(&b->sh_surfaces, sizeof(TOBJ_T(tobj_surface))); | 1219 | 3.65k | b->ff_degu = 0; | 1220 | 3.65k | b->ff_degv = 0; | 1221 | 3.65k | } |
Unexecuted instantiation: tiny_obj_c.c:builder_init_d |
1222 | | |
1223 | 3.65k | static void TOBJ_T(builder_dispose)(TOBJ_T(tobj_builder) * b) { |
1224 | 3.65k | const tobj_allocator *a = b->alloc; |
1225 | 3.65k | tobj_vec_free(&b->av, a); |
1226 | 3.65k | tobj_vec_free(&b->avw, a); |
1227 | 3.65k | tobj_vec_free(&b->avn, a); |
1228 | 3.65k | tobj_vec_free(&b->avt, a); |
1229 | 3.65k | tobj_vec_free(&b->avtw, a); |
1230 | 3.65k | tobj_vec_free(&b->acol, a); |
1231 | 3.65k | tobj_vec_free(&b->materials, a); |
1232 | 3.65k | tobj_vec_free(&b->matmap_key, a); |
1233 | 3.65k | tobj_vec_free(&b->matmap_id, a); |
1234 | 3.65k | tobj_vec_free(&b->mat_unknown, a); |
1235 | 3.65k | tobj_vec_free(&b->shapes, a); |
1236 | 3.65k | tobj_vec_free(&b->m_idx, a); |
1237 | 3.65k | tobj_vec_free(&b->m_fv, a); |
1238 | 3.65k | tobj_vec_free(&b->m_mid, a); |
1239 | 3.65k | tobj_vec_free(&b->m_sg, a); |
1240 | 3.65k | tobj_vec_free(&b->l_idx, a); |
1241 | 3.65k | tobj_vec_free(&b->l_cnt, a); |
1242 | 3.65k | tobj_vec_free(&b->p_idx, a); |
1243 | 3.65k | tobj_vec_free(&b->corners, a); |
1244 | 3.65k | tobj_vec_free(&b->ringpos, a); |
1245 | 3.65k | tobj_vec_free(&b->tris, a); |
1246 | 3.65k | tobj_vec_free(&b->tscratch, a); |
1247 | 3.65k | tobj_vec_free(&b->ff_vp, a); |
1248 | 3.65k | tobj_vec_free(&b->ff_cp_int, a); |
1249 | 3.65k | tobj_vec_free(&b->ff_cp_idx, a); |
1250 | 3.65k | tobj_vec_free(&b->ff_knu, a); |
1251 | 3.65k | tobj_vec_free(&b->ff_knv, a); |
1252 | 3.65k | tobj_vec_free(&b->ff_trim, a); |
1253 | 3.65k | tobj_vec_free(&b->ff_hole, a); |
1254 | 3.65k | tobj_vec_free(&b->ff_scrv, a); |
1255 | 3.65k | tobj_vec_free(&b->sh_curves, a); |
1256 | 3.65k | tobj_vec_free(&b->sh_curves2, a); |
1257 | 3.65k | tobj_vec_free(&b->sh_surfaces, a); |
1258 | 3.65k | } tiny_obj_c.c:builder_dispose_f Line | Count | Source | 1223 | 3.65k | static void TOBJ_T(builder_dispose)(TOBJ_T(tobj_builder) * b) { | 1224 | 3.65k | const tobj_allocator *a = b->alloc; | 1225 | 3.65k | tobj_vec_free(&b->av, a); | 1226 | 3.65k | tobj_vec_free(&b->avw, a); | 1227 | 3.65k | tobj_vec_free(&b->avn, a); | 1228 | 3.65k | tobj_vec_free(&b->avt, a); | 1229 | 3.65k | tobj_vec_free(&b->avtw, a); | 1230 | 3.65k | tobj_vec_free(&b->acol, a); | 1231 | 3.65k | tobj_vec_free(&b->materials, a); | 1232 | 3.65k | tobj_vec_free(&b->matmap_key, a); | 1233 | 3.65k | tobj_vec_free(&b->matmap_id, a); | 1234 | 3.65k | tobj_vec_free(&b->mat_unknown, a); | 1235 | 3.65k | tobj_vec_free(&b->shapes, a); | 1236 | 3.65k | tobj_vec_free(&b->m_idx, a); | 1237 | 3.65k | tobj_vec_free(&b->m_fv, a); | 1238 | 3.65k | tobj_vec_free(&b->m_mid, a); | 1239 | 3.65k | tobj_vec_free(&b->m_sg, a); | 1240 | 3.65k | tobj_vec_free(&b->l_idx, a); | 1241 | 3.65k | tobj_vec_free(&b->l_cnt, a); | 1242 | 3.65k | tobj_vec_free(&b->p_idx, a); | 1243 | 3.65k | tobj_vec_free(&b->corners, a); | 1244 | 3.65k | tobj_vec_free(&b->ringpos, a); | 1245 | 3.65k | tobj_vec_free(&b->tris, a); | 1246 | 3.65k | tobj_vec_free(&b->tscratch, a); | 1247 | 3.65k | tobj_vec_free(&b->ff_vp, a); | 1248 | 3.65k | tobj_vec_free(&b->ff_cp_int, a); | 1249 | 3.65k | tobj_vec_free(&b->ff_cp_idx, a); | 1250 | 3.65k | tobj_vec_free(&b->ff_knu, a); | 1251 | 3.65k | tobj_vec_free(&b->ff_knv, a); | 1252 | 3.65k | tobj_vec_free(&b->ff_trim, a); | 1253 | 3.65k | tobj_vec_free(&b->ff_hole, a); | 1254 | 3.65k | tobj_vec_free(&b->ff_scrv, a); | 1255 | 3.65k | tobj_vec_free(&b->sh_curves, a); | 1256 | 3.65k | tobj_vec_free(&b->sh_curves2, a); | 1257 | 3.65k | tobj_vec_free(&b->sh_surfaces, a); | 1258 | 3.65k | } |
Unexecuted instantiation: tiny_obj_c.c:builder_dispose_d |
1259 | | |
1260 | 3.65k | void TOBJ_T(tobj_scene_free)(TOBJ_T(tobj_scene) * s) { |
1261 | 3.65k | if (!s) return; |
1262 | 3.65k | if (s->arena) { |
1263 | 3.65k | tobj_arena *ar = (tobj_arena *)s->arena; |
1264 | 3.65k | tobj_allocator a = s->allocator; |
1265 | 3.65k | tobj_arena_destroy(ar); |
1266 | 3.65k | tobj_free(&a, ar, sizeof(tobj_arena)); |
1267 | 3.65k | } |
1268 | 3.65k | tobj_memset(s, 0, sizeof *s); |
1269 | 3.65k | } Line | Count | Source | 1260 | 3.65k | void TOBJ_T(tobj_scene_free)(TOBJ_T(tobj_scene) * s) { | 1261 | 3.65k | if (!s) return; | 1262 | 3.65k | if (s->arena) { | 1263 | 3.65k | tobj_arena *ar = (tobj_arena *)s->arena; | 1264 | 3.65k | tobj_allocator a = s->allocator; | 1265 | 3.65k | tobj_arena_destroy(ar); | 1266 | 3.65k | tobj_free(&a, ar, sizeof(tobj_arena)); | 1267 | 3.65k | } | 1268 | 3.65k | tobj_memset(s, 0, sizeof *s); | 1269 | 3.65k | } |
Unexecuted instantiation: tobj_scene_free_d |
1270 | | |
1271 | | const char *TOBJ_T(tobj_material_get_param)(const TOBJ_T(tobj_material) * m, |
1272 | 0 | const char *key) { |
1273 | 0 | if (!m || !key) return NULL; |
1274 | 0 | size_t lo = 0, hi = m->num_unknown_params; |
1275 | 0 | while (lo < hi) { |
1276 | 0 | size_t mid = lo + (hi - lo) / 2; |
1277 | 0 | const char *k = m->unknown_params[mid].key; |
1278 | | /* strcmp without libc */ |
1279 | 0 | size_t i = 0; |
1280 | 0 | int cmp = 0; |
1281 | 0 | for (;; i++) { |
1282 | 0 | unsigned char a = (unsigned char)k[i], bb = (unsigned char)key[i]; |
1283 | 0 | if (a != bb) { |
1284 | 0 | cmp = (int)a - (int)bb; |
1285 | 0 | break; |
1286 | 0 | } |
1287 | 0 | if (!a) break; |
1288 | 0 | } |
1289 | 0 | if (cmp == 0) return m->unknown_params[mid].value; |
1290 | 0 | if (cmp < 0) |
1291 | 0 | lo = mid + 1; |
1292 | 0 | else |
1293 | 0 | hi = mid; |
1294 | 0 | } |
1295 | 0 | return NULL; |
1296 | 0 | } Unexecuted instantiation: tobj_material_get_param_f Unexecuted instantiation: tobj_material_get_param_d |
1297 | | |
1298 | | #ifdef TOBJ_ENABLE_MULTITHREADING |
1299 | | /* Per-thread vertex-parse output (MT pass 1). */ |
1300 | | typedef struct TOBJ_T(tobj_tls) { |
1301 | | const char *base; |
1302 | | const tobj_line *lines; |
1303 | | size_t lo, hi; |
1304 | | const tobj_allocator *alloc; |
1305 | | bool store_colors; |
1306 | | bool parse_vp; |
1307 | | bool oom; |
1308 | | tobj_vec lv, lvw, lvw_has, lcol, lcol_has, lvn, lvt, lvtw, lvtw_has, lvp; |
1309 | | int vp_comps; |
1310 | | } TOBJ_T(tobj_tls); |
1311 | | |
1312 | | static void TOBJ_T(mt_worker)(void *arg) { |
1313 | | TOBJ_T(tobj_tls) *w = (TOBJ_T(tobj_tls) *)arg; |
1314 | | const tobj_allocator *a = w->alloc; |
1315 | | for (size_t i = w->lo; i < w->hi && !w->oom; i++) { |
1316 | | const tobj_line *ln = &w->lines[i]; |
1317 | | tobj_cursor c; |
1318 | | tobj_cur_init(&c, w->base + ln->pos, ln->len); |
1319 | | const char *tok; |
1320 | | size_t tl; |
1321 | | if (!tobj_next_token(&c, &tok, &tl)) continue; |
1322 | | if (tobj_slice_eq(tok, tl, "v")) { |
1323 | | double nums[8]; |
1324 | | int n = 0; |
1325 | | while (n < 8) { |
1326 | | double d; |
1327 | | const char *s = c.p; |
1328 | | if (!tobj_scan_double(&c.p, c.end, &d)) { |
1329 | | c.p = s; |
1330 | | break; |
1331 | | } |
1332 | | nums[n++] = d; |
1333 | | } |
1334 | | while (n < 3) nums[n++] = 0.0; |
1335 | | TOBJ_REAL xyz[3] = {(TOBJ_REAL)nums[0], (TOBJ_REAL)nums[1], |
1336 | | (TOBJ_REAL)nums[2]}; |
1337 | | uint8_t wh = (n == 4); |
1338 | | TOBJ_REAL wv = wh ? (TOBJ_REAL)nums[3] : (TOBJ_REAL)1; |
1339 | | if (!tobj_vec_append(&w->lv, xyz, 3, a) || |
1340 | | !tobj_vec_append(&w->lvw, &wv, 1, a) || |
1341 | | !tobj_vec_append(&w->lvw_has, &wh, 1, a)) { |
1342 | | w->oom = true; |
1343 | | return; |
1344 | | } |
1345 | | if (w->store_colors) { |
1346 | | uint8_t ch = (n >= 6); |
1347 | | TOBJ_REAL rgb[3] = {ch ? (TOBJ_REAL)nums[3] : (TOBJ_REAL)1, |
1348 | | ch ? (TOBJ_REAL)nums[4] : (TOBJ_REAL)1, |
1349 | | ch ? (TOBJ_REAL)nums[5] : (TOBJ_REAL)1}; |
1350 | | if (!tobj_vec_append(&w->lcol, rgb, 3, a) || |
1351 | | !tobj_vec_append(&w->lcol_has, &ch, 1, a)) { |
1352 | | w->oom = true; |
1353 | | return; |
1354 | | } |
1355 | | } |
1356 | | } else if (tobj_slice_eq(tok, tl, "vn")) { |
1357 | | TOBJ_REAL xyz[3] = {0, 0, 0}; |
1358 | | double d; |
1359 | | for (int k = 0; k < 3; k++) |
1360 | | if (tobj_scan_double(&c.p, c.end, &d)) xyz[k] = (TOBJ_REAL)d; |
1361 | | if (!tobj_vec_append(&w->lvn, xyz, 3, a)) { |
1362 | | w->oom = true; |
1363 | | return; |
1364 | | } |
1365 | | } else if (tobj_slice_eq(tok, tl, "vt")) { |
1366 | | double d; |
1367 | | TOBJ_REAL uv[2] = {0, 0}; |
1368 | | int n = 0; |
1369 | | for (; n < 2; n++) { |
1370 | | if (!tobj_scan_double(&c.p, c.end, &d)) break; |
1371 | | uv[n] = (TOBJ_REAL)d; |
1372 | | } |
1373 | | uint8_t wh = (uint8_t)tobj_scan_double(&c.p, c.end, &d); |
1374 | | TOBJ_REAL wv = wh ? (TOBJ_REAL)d : (TOBJ_REAL)0; |
1375 | | if (!tobj_vec_append(&w->lvt, uv, 2, a) || |
1376 | | !tobj_vec_append(&w->lvtw, &wv, 1, a) || |
1377 | | !tobj_vec_append(&w->lvtw_has, &wh, 1, a)) { |
1378 | | w->oom = true; |
1379 | | return; |
1380 | | } |
1381 | | } else if (w->parse_vp && tobj_slice_eq(tok, tl, "vp")) { |
1382 | | double d; |
1383 | | int n = 0; |
1384 | | TOBJ_REAL uvw[3] = {0, 0, 0}; |
1385 | | for (; n < 3; n++) { |
1386 | | if (!tobj_scan_double(&c.p, c.end, &d)) break; |
1387 | | uvw[n] = (TOBJ_REAL)d; |
1388 | | } |
1389 | | if (n < 1) continue; |
1390 | | if (n > w->vp_comps) w->vp_comps = n; |
1391 | | if (!tobj_vec_append(&w->lvp, uvw, (size_t)n, a)) { |
1392 | | w->oom = true; |
1393 | | return; |
1394 | | } |
1395 | | } |
1396 | | } |
1397 | | } |
1398 | | |
1399 | | /* Reconstruct a lazy optional array (weights/colors/texcoord-w) from the |
1400 | | * per-thread (value,has) streams, reproducing the single-threaded semantics |
1401 | | * exactly: empty until the first present entry, then dense with backfill. */ |
1402 | | static bool TOBJ_T(mt_lazy)(tobj_vec *dst, size_t comps, const TOBJ_REAL *dflt, |
1403 | | TOBJ_T(tobj_tls) * tls, int T, int kind, |
1404 | | const tobj_allocator *a) { |
1405 | | bool started = false; |
1406 | | size_t gi = 0; |
1407 | | for (int t = 0; t < T; t++) { |
1408 | | tobj_vec *vval = (kind == 0) ? &tls[t].lvw |
1409 | | : (kind == 1) ? &tls[t].lcol : &tls[t].lvtw; |
1410 | | tobj_vec *vhas = (kind == 0) ? &tls[t].lvw_has |
1411 | | : (kind == 1) ? &tls[t].lcol_has |
1412 | | : &tls[t].lvtw_has; |
1413 | | size_t cnt = vhas->count; |
1414 | | const TOBJ_REAL *val = (const TOBJ_REAL *)vval->data; |
1415 | | const uint8_t *has = (const uint8_t *)vhas->data; |
1416 | | for (size_t j = 0; j < cnt; j++, gi++) { |
1417 | | if (has[j] || started) { |
1418 | | if (!started) { |
1419 | | for (size_t k = 0; k < gi; k++) |
1420 | | if (!tobj_vec_append(dst, dflt, comps, a)) return false; |
1421 | | started = true; |
1422 | | } |
1423 | | if (!tobj_vec_append(dst, &val[j * comps], comps, a)) return false; |
1424 | | } |
1425 | | } |
1426 | | } |
1427 | | return true; |
1428 | | } |
1429 | | |
1430 | | /* MT pass 1: parse v/vn/vt/vp in parallel and merge into the builder's attrib |
1431 | | * arrays, reproducing single-threaded output exactly. Sets b->prefilled. */ |
1432 | | static bool TOBJ_T(mt_prepass)(TOBJ_T(tobj_builder) * b, const tobj_vec *lines, |
1433 | | const char *base, int T) { |
1434 | | const tobj_allocator *a = b->alloc; |
1435 | | TOBJ_T(tobj_tls) *tls = |
1436 | | (TOBJ_T(tobj_tls) *)tobj_alloc(a, (size_t)T * sizeof(*tls), 16); |
1437 | | tobj_thunk *thunks = (tobj_thunk *)tobj_alloc(a, (size_t)T * sizeof(*thunks), |
1438 | | 16); |
1439 | | if (!tls || !thunks) { |
1440 | | if (tls) tobj_free(a, tls, (size_t)T * sizeof(*tls)); |
1441 | | if (thunks) tobj_free(a, thunks, (size_t)T * sizeof(*thunks)); |
1442 | | return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
1443 | | } |
1444 | | size_t nlines = lines->count; |
1445 | | const tobj_line *ld = (const tobj_line *)lines->data; |
1446 | | for (int t = 0; t < T; t++) { |
1447 | | tobj_memset(&tls[t], 0, sizeof tls[t]); |
1448 | | tls[t].base = base; |
1449 | | tls[t].lines = ld; |
1450 | | tls[t].lo = (size_t)t * nlines / (size_t)T; |
1451 | | tls[t].hi = (size_t)(t + 1) * nlines / (size_t)T; |
1452 | | tls[t].alloc = a; |
1453 | | tls[t].store_colors = b->cfg->store_vertex_colors; |
1454 | | tls[t].parse_vp = b->cfg->parse_freeform; |
1455 | | tobj_vec_init(&tls[t].lv, sizeof(TOBJ_REAL)); |
1456 | | tobj_vec_init(&tls[t].lvw, sizeof(TOBJ_REAL)); |
1457 | | tobj_vec_init(&tls[t].lvw_has, 1); |
1458 | | tobj_vec_init(&tls[t].lcol, sizeof(TOBJ_REAL)); |
1459 | | tobj_vec_init(&tls[t].lcol_has, 1); |
1460 | | tobj_vec_init(&tls[t].lvn, sizeof(TOBJ_REAL)); |
1461 | | tobj_vec_init(&tls[t].lvt, sizeof(TOBJ_REAL)); |
1462 | | tobj_vec_init(&tls[t].lvtw, sizeof(TOBJ_REAL)); |
1463 | | tobj_vec_init(&tls[t].lvtw_has, 1); |
1464 | | tobj_vec_init(&tls[t].lvp, sizeof(TOBJ_REAL)); |
1465 | | thunks[t].fn = TOBJ_T(mt_worker); |
1466 | | thunks[t].arg = &tls[t]; |
1467 | | } |
1468 | | |
1469 | | tobj_run_parallel(thunks, T); |
1470 | | |
1471 | | bool ok = true; |
1472 | | for (int t = 0; t < T; t++) |
1473 | | if (tls[t].oom) ok = false; |
1474 | | |
1475 | | /* merge plain arrays in thread (= file) order */ |
1476 | | for (int t = 0; ok && t < T; t++) { |
1477 | | if (!tobj_vec_append(&b->av, tls[t].lv.data, tls[t].lv.count, a) || |
1478 | | !tobj_vec_append(&b->avn, tls[t].lvn.data, tls[t].lvn.count, a) || |
1479 | | !tobj_vec_append(&b->avt, tls[t].lvt.data, tls[t].lvt.count, a)) |
1480 | | ok = false; |
1481 | | if (ok && b->cfg->parse_freeform && tls[t].lvp.count) { |
1482 | | if (!tobj_vec_append(&b->ff_vp, tls[t].lvp.data, tls[t].lvp.count, a)) |
1483 | | ok = false; |
1484 | | if (tls[t].vp_comps > b->ff_vp_comps) b->ff_vp_comps = tls[t].vp_comps; |
1485 | | } |
1486 | | } |
1487 | | /* reconstruct lazy optional arrays */ |
1488 | | if (ok) { |
1489 | | TOBJ_REAL d1 = (TOBJ_REAL)1, d0 = (TOBJ_REAL)0; |
1490 | | TOBJ_REAL white[3] = {(TOBJ_REAL)1, (TOBJ_REAL)1, (TOBJ_REAL)1}; |
1491 | | if (!TOBJ_T(mt_lazy)(&b->avw, 1, &d1, tls, T, 0, a)) ok = false; |
1492 | | if (ok && b->cfg->store_vertex_colors && |
1493 | | !TOBJ_T(mt_lazy)(&b->acol, 3, white, tls, T, 1, a)) |
1494 | | ok = false; |
1495 | | if (ok && !TOBJ_T(mt_lazy)(&b->avtw, 1, &d0, tls, T, 2, a)) ok = false; |
1496 | | } |
1497 | | |
1498 | | for (int t = 0; t < T; t++) { |
1499 | | tobj_vec_free(&tls[t].lv, a); |
1500 | | tobj_vec_free(&tls[t].lvw, a); |
1501 | | tobj_vec_free(&tls[t].lvw_has, a); |
1502 | | tobj_vec_free(&tls[t].lcol, a); |
1503 | | tobj_vec_free(&tls[t].lcol_has, a); |
1504 | | tobj_vec_free(&tls[t].lvn, a); |
1505 | | tobj_vec_free(&tls[t].lvt, a); |
1506 | | tobj_vec_free(&tls[t].lvtw, a); |
1507 | | tobj_vec_free(&tls[t].lvtw_has, a); |
1508 | | tobj_vec_free(&tls[t].lvp, a); |
1509 | | } |
1510 | | tobj_free(a, tls, (size_t)T * sizeof(*tls)); |
1511 | | tobj_free(a, thunks, (size_t)T * sizeof(*thunks)); |
1512 | | if (!ok) return TOBJ_T(b_fail)(b, TOBJ_ERR_ALLOC); |
1513 | | b->prefilled = true; |
1514 | | return true; |
1515 | | } |
1516 | | #endif /* TOBJ_ENABLE_MULTITHREADING */ |
1517 | | |
1518 | | tobj_result TOBJ_T(tobj_load_obj_from_memory)(TOBJ_T(tobj_scene) * out, |
1519 | | const uint8_t *buf, size_t len, |
1520 | | const tobj_load_config *cfg, |
1521 | 3.65k | tobj_diag *diag) { |
1522 | 3.65k | if (!out) return TOBJ_ERR_INVALID_ARG; |
1523 | 3.65k | tobj_memset(out, 0, sizeof *out); |
1524 | 3.65k | if (!buf && len) return TOBJ_ERR_INVALID_ARG; |
1525 | | |
1526 | 3.65k | tobj_load_config defcfg; |
1527 | 3.65k | if (!cfg) { |
1528 | 0 | defcfg = tobj_default_config(); |
1529 | 0 | cfg = &defcfg; |
1530 | 0 | } |
1531 | 3.65k | if (len > tobj_resolve_caps(cfg).input_bytes) return TOBJ_ERR_LIMIT_EXCEEDED; |
1532 | | |
1533 | 3.65k | tobj_allocator alloc; |
1534 | 3.65k | if (!tobj_resolve_allocator(&cfg->allocator, &alloc)) |
1535 | 0 | return TOBJ_ERR_INVALID_ARG; |
1536 | | |
1537 | 3.65k | tobj_arena *arena = (tobj_arena *)tobj_alloc(&alloc, sizeof(tobj_arena), 16); |
1538 | 3.65k | if (!arena) return TOBJ_ERR_ALLOC; |
1539 | 3.65k | tobj_arena_init(arena, &alloc, cfg->use_arena ? (size_t)(1u << 20) : 0); |
1540 | | |
1541 | 3.65k | TOBJ_T(tobj_builder) b; |
1542 | 3.65k | tobj_memset(&b, 0, sizeof b); |
1543 | 3.65k | b.alloc = &alloc; |
1544 | 3.65k | b.arena = arena; |
1545 | 3.65k | b.diag = diag; |
1546 | 3.65k | b.cfg = cfg; |
1547 | 3.65k | b.caps = tobj_resolve_caps(cfg); |
1548 | 3.65k | b.err = TOBJ_OK; |
1549 | 3.65k | b.triangulate = cfg->triangulate; |
1550 | 3.65k | b.cur_material = -1; |
1551 | 3.65k | b.cur_smooth = 0; |
1552 | 3.65k | b.cur_name = NULL; |
1553 | 3.65k | TOBJ_T(builder_init)(&b); |
1554 | | |
1555 | 3.65k | tobj_vec lines; |
1556 | 3.65k | tobj_vec_init(&lines, sizeof(tobj_line)); |
1557 | 3.65k | if (!tobj_build_line_index(buf, len, &lines, &alloc)) { |
1558 | 0 | b.err = TOBJ_ERR_ALLOC; |
1559 | 0 | } |
1560 | | |
1561 | 3.65k | const char *base = (const char *)buf; |
1562 | | |
1563 | | #ifdef TOBJ_ENABLE_MULTITHREADING |
1564 | | if (b.err == TOBJ_OK) { |
1565 | | int T = cfg->num_threads < 0 ? (int)tobj_hw_threads() : cfg->num_threads; |
1566 | | if (T > 64) T = 64; |
1567 | | /* Only worth threading on sizeable inputs. */ |
1568 | | if (T > 1 && lines.count >= (size_t)(256 * T)) { |
1569 | | TOBJ_T(mt_prepass)(&b, &lines, base, T); |
1570 | | } |
1571 | | } |
1572 | | #endif |
1573 | | |
1574 | 15.9M | for (size_t i = 0; i < lines.count && b.err == TOBJ_OK; i++) { |
1575 | 15.9M | tobj_line *ln = (tobj_line *)tobj_vec_at(&lines, i); |
1576 | 15.9M | b.line = i + 1; |
1577 | 15.9M | TOBJ_T(dispatch_line)(&b, base + ln->pos, ln->len); |
1578 | 15.9M | } |
1579 | | |
1580 | 3.65k | if (b.err == TOBJ_OK) TOBJ_T(finalize_shape)(&b); |
1581 | | |
1582 | | /* vertex color fallback: fill white if requested and none present */ |
1583 | 3.65k | if (b.err == TOBJ_OK && cfg->store_vertex_colors && |
1584 | 3.65k | cfg->vertex_color_fallback && b.acol.count == 0) { |
1585 | 3.43k | size_t numv = b.av.count / 3u; |
1586 | 3.43k | TOBJ_REAL white[3] = {(TOBJ_REAL)1, (TOBJ_REAL)1, (TOBJ_REAL)1}; |
1587 | 1.97M | for (size_t i = 0; i < numv && b.err == TOBJ_OK; i++) { |
1588 | 1.97M | if (!tobj_vec_append(&b.acol, white, 3, &alloc)) b.err = TOBJ_ERR_ALLOC; |
1589 | 1.97M | } |
1590 | 3.43k | } |
1591 | | |
1592 | 3.65k | if (b.err == TOBJ_OK) { |
1593 | 3.65k | #define TOBJ_FIN_BUF(field, vec) \ |
1594 | 21.9k | do { \ |
1595 | 21.9k | out->attrib.field.count = (vec).count; \ |
1596 | 21.9k | out->attrib.field.ptr = \ |
1597 | 21.9k | (TOBJ_REAL *)tobj_vec_finalize(&(vec), arena, 16); \ |
1598 | 21.9k | if ((vec).count && !out->attrib.field.ptr) b.err = TOBJ_ERR_ALLOC; \ |
1599 | 21.9k | } while (0) |
1600 | 3.65k | TOBJ_FIN_BUF(vertices, b.av); |
1601 | 3.65k | TOBJ_FIN_BUF(vertex_weights, b.avw); |
1602 | 3.65k | TOBJ_FIN_BUF(normals, b.avn); |
1603 | 3.65k | TOBJ_FIN_BUF(texcoords, b.avt); |
1604 | 3.65k | TOBJ_FIN_BUF(texcoord_ws, b.avtw); |
1605 | 3.65k | TOBJ_FIN_BUF(colors, b.acol); |
1606 | 3.65k | #undef TOBJ_FIN_BUF |
1607 | 3.65k | } |
1608 | | |
1609 | 3.65k | if (b.err == TOBJ_OK) TOBJ_T(finalize_unknowns)(&b); |
1610 | | |
1611 | 3.65k | if (b.err == TOBJ_OK) { |
1612 | 3.65k | out->num_shapes = b.shapes.count; |
1613 | 3.65k | out->shapes = (TOBJ_T(tobj_shape) *)tobj_vec_finalize( |
1614 | 3.65k | &b.shapes, arena, 16); |
1615 | 3.65k | if (b.shapes.count && !out->shapes) b.err = TOBJ_ERR_ALLOC; |
1616 | 3.65k | out->num_materials = b.materials.count; |
1617 | 3.65k | out->materials = (TOBJ_T(tobj_material) *)tobj_vec_finalize( |
1618 | 3.65k | &b.materials, arena, 16); |
1619 | 3.65k | if (b.materials.count && !out->materials) b.err = TOBJ_ERR_ALLOC; |
1620 | 3.65k | } |
1621 | | |
1622 | 3.65k | TOBJ_T(builder_dispose)(&b); |
1623 | 3.65k | tobj_vec_free(&lines, &alloc); |
1624 | | |
1625 | 3.65k | if (b.err != TOBJ_OK) { |
1626 | 0 | tobj_arena_destroy(arena); |
1627 | 0 | tobj_free(&alloc, arena, sizeof(tobj_arena)); |
1628 | 0 | tobj_memset(out, 0, sizeof *out); |
1629 | 0 | return b.err; |
1630 | 0 | } |
1631 | | |
1632 | 3.65k | out->allocator = alloc; |
1633 | 3.65k | out->arena = arena; |
1634 | 3.65k | out->strpool = NULL; |
1635 | 3.65k | return TOBJ_OK; |
1636 | 3.65k | } tobj_load_obj_from_memory_f Line | Count | Source | 1521 | 3.65k | tobj_diag *diag) { | 1522 | 3.65k | if (!out) return TOBJ_ERR_INVALID_ARG; | 1523 | 3.65k | tobj_memset(out, 0, sizeof *out); | 1524 | 3.65k | if (!buf && len) return TOBJ_ERR_INVALID_ARG; | 1525 | | | 1526 | 3.65k | tobj_load_config defcfg; | 1527 | 3.65k | if (!cfg) { | 1528 | 0 | defcfg = tobj_default_config(); | 1529 | 0 | cfg = &defcfg; | 1530 | 0 | } | 1531 | 3.65k | if (len > tobj_resolve_caps(cfg).input_bytes) return TOBJ_ERR_LIMIT_EXCEEDED; | 1532 | | | 1533 | 3.65k | tobj_allocator alloc; | 1534 | 3.65k | if (!tobj_resolve_allocator(&cfg->allocator, &alloc)) | 1535 | 0 | return TOBJ_ERR_INVALID_ARG; | 1536 | | | 1537 | 3.65k | tobj_arena *arena = (tobj_arena *)tobj_alloc(&alloc, sizeof(tobj_arena), 16); | 1538 | 3.65k | if (!arena) return TOBJ_ERR_ALLOC; | 1539 | 3.65k | tobj_arena_init(arena, &alloc, cfg->use_arena ? (size_t)(1u << 20) : 0); | 1540 | | | 1541 | 3.65k | TOBJ_T(tobj_builder) b; | 1542 | 3.65k | tobj_memset(&b, 0, sizeof b); | 1543 | 3.65k | b.alloc = &alloc; | 1544 | 3.65k | b.arena = arena; | 1545 | 3.65k | b.diag = diag; | 1546 | 3.65k | b.cfg = cfg; | 1547 | 3.65k | b.caps = tobj_resolve_caps(cfg); | 1548 | 3.65k | b.err = TOBJ_OK; | 1549 | 3.65k | b.triangulate = cfg->triangulate; | 1550 | 3.65k | b.cur_material = -1; | 1551 | 3.65k | b.cur_smooth = 0; | 1552 | 3.65k | b.cur_name = NULL; | 1553 | 3.65k | TOBJ_T(builder_init)(&b); | 1554 | | | 1555 | 3.65k | tobj_vec lines; | 1556 | 3.65k | tobj_vec_init(&lines, sizeof(tobj_line)); | 1557 | 3.65k | if (!tobj_build_line_index(buf, len, &lines, &alloc)) { | 1558 | 0 | b.err = TOBJ_ERR_ALLOC; | 1559 | 0 | } | 1560 | | | 1561 | 3.65k | const char *base = (const char *)buf; | 1562 | | | 1563 | | #ifdef TOBJ_ENABLE_MULTITHREADING | 1564 | | if (b.err == TOBJ_OK) { | 1565 | | int T = cfg->num_threads < 0 ? (int)tobj_hw_threads() : cfg->num_threads; | 1566 | | if (T > 64) T = 64; | 1567 | | /* Only worth threading on sizeable inputs. */ | 1568 | | if (T > 1 && lines.count >= (size_t)(256 * T)) { | 1569 | | TOBJ_T(mt_prepass)(&b, &lines, base, T); | 1570 | | } | 1571 | | } | 1572 | | #endif | 1573 | | | 1574 | 15.9M | for (size_t i = 0; i < lines.count && b.err == TOBJ_OK; i++) { | 1575 | 15.9M | tobj_line *ln = (tobj_line *)tobj_vec_at(&lines, i); | 1576 | 15.9M | b.line = i + 1; | 1577 | 15.9M | TOBJ_T(dispatch_line)(&b, base + ln->pos, ln->len); | 1578 | 15.9M | } | 1579 | | | 1580 | 3.65k | if (b.err == TOBJ_OK) TOBJ_T(finalize_shape)(&b); | 1581 | | | 1582 | | /* vertex color fallback: fill white if requested and none present */ | 1583 | 3.65k | if (b.err == TOBJ_OK && cfg->store_vertex_colors && | 1584 | 3.65k | cfg->vertex_color_fallback && b.acol.count == 0) { | 1585 | 3.43k | size_t numv = b.av.count / 3u; | 1586 | 3.43k | TOBJ_REAL white[3] = {(TOBJ_REAL)1, (TOBJ_REAL)1, (TOBJ_REAL)1}; | 1587 | 1.97M | for (size_t i = 0; i < numv && b.err == TOBJ_OK; i++) { | 1588 | 1.97M | if (!tobj_vec_append(&b.acol, white, 3, &alloc)) b.err = TOBJ_ERR_ALLOC; | 1589 | 1.97M | } | 1590 | 3.43k | } | 1591 | | | 1592 | 3.65k | if (b.err == TOBJ_OK) { | 1593 | 3.65k | #define TOBJ_FIN_BUF(field, vec) \ | 1594 | 3.65k | do { \ | 1595 | 3.65k | out->attrib.field.count = (vec).count; \ | 1596 | 3.65k | out->attrib.field.ptr = \ | 1597 | 3.65k | (TOBJ_REAL *)tobj_vec_finalize(&(vec), arena, 16); \ | 1598 | 3.65k | if ((vec).count && !out->attrib.field.ptr) b.err = TOBJ_ERR_ALLOC; \ | 1599 | 3.65k | } while (0) | 1600 | 3.65k | TOBJ_FIN_BUF(vertices, b.av); | 1601 | 3.65k | TOBJ_FIN_BUF(vertex_weights, b.avw); | 1602 | 3.65k | TOBJ_FIN_BUF(normals, b.avn); | 1603 | 3.65k | TOBJ_FIN_BUF(texcoords, b.avt); | 1604 | 3.65k | TOBJ_FIN_BUF(texcoord_ws, b.avtw); | 1605 | 3.65k | TOBJ_FIN_BUF(colors, b.acol); | 1606 | 3.65k | #undef TOBJ_FIN_BUF | 1607 | 3.65k | } | 1608 | | | 1609 | 3.65k | if (b.err == TOBJ_OK) TOBJ_T(finalize_unknowns)(&b); | 1610 | | | 1611 | 3.65k | if (b.err == TOBJ_OK) { | 1612 | 3.65k | out->num_shapes = b.shapes.count; | 1613 | 3.65k | out->shapes = (TOBJ_T(tobj_shape) *)tobj_vec_finalize( | 1614 | 3.65k | &b.shapes, arena, 16); | 1615 | 3.65k | if (b.shapes.count && !out->shapes) b.err = TOBJ_ERR_ALLOC; | 1616 | 3.65k | out->num_materials = b.materials.count; | 1617 | 3.65k | out->materials = (TOBJ_T(tobj_material) *)tobj_vec_finalize( | 1618 | 3.65k | &b.materials, arena, 16); | 1619 | 3.65k | if (b.materials.count && !out->materials) b.err = TOBJ_ERR_ALLOC; | 1620 | 3.65k | } | 1621 | | | 1622 | 3.65k | TOBJ_T(builder_dispose)(&b); | 1623 | 3.65k | tobj_vec_free(&lines, &alloc); | 1624 | | | 1625 | 3.65k | if (b.err != TOBJ_OK) { | 1626 | 0 | tobj_arena_destroy(arena); | 1627 | 0 | tobj_free(&alloc, arena, sizeof(tobj_arena)); | 1628 | 0 | tobj_memset(out, 0, sizeof *out); | 1629 | 0 | return b.err; | 1630 | 0 | } | 1631 | | | 1632 | 3.65k | out->allocator = alloc; | 1633 | 3.65k | out->arena = arena; | 1634 | | out->strpool = NULL; | 1635 | 3.65k | return TOBJ_OK; | 1636 | 3.65k | } |
Unexecuted instantiation: tobj_load_obj_from_memory_d |
1637 | | |
1638 | | tobj_result TOBJ_T(tobj_load_obj_from_io)(TOBJ_T(tobj_scene) * out, |
1639 | | const tobj_io_callbacks *io, |
1640 | | const tobj_load_config *cfg, |
1641 | 0 | tobj_diag *diag) { |
1642 | 0 | if (!out) return TOBJ_ERR_INVALID_ARG; |
1643 | 0 | tobj_memset(out, 0, sizeof *out); |
1644 | 0 | if (!io || !io->read) return TOBJ_ERR_INVALID_ARG; |
1645 | | |
1646 | 0 | tobj_load_config cc = cfg ? *cfg : tobj_default_config(); |
1647 | 0 | tobj_allocator alloc; |
1648 | 0 | if (!tobj_resolve_allocator(&cc.allocator, &alloc)) |
1649 | 0 | return TOBJ_ERR_INVALID_ARG; |
1650 | 0 | cc.allocator = alloc; |
1651 | |
|
1652 | 0 | tobj_caps caps = tobj_resolve_caps(&cc); |
1653 | 0 | tobj_vec buf; |
1654 | 0 | tobj_vec_init(&buf, 1); |
1655 | 0 | tobj_result r = TOBJ_OK; |
1656 | |
|
1657 | 0 | for (;;) { |
1658 | 0 | size_t remain = caps.input_bytes - buf.count; |
1659 | 0 | if (remain == 0) { |
1660 | 0 | uint8_t extra; |
1661 | 0 | size_t got = 0; |
1662 | 0 | r = io->read(io->user_data, &extra, 1, &got); |
1663 | 0 | if (r == TOBJ_OK && got != 0) r = TOBJ_ERR_LIMIT_EXCEEDED; |
1664 | 0 | break; |
1665 | 0 | } |
1666 | 0 | size_t want = remain < (size_t)(64u * 1024u) ? remain |
1667 | 0 | : (size_t)(64u * 1024u); |
1668 | 0 | size_t old = buf.count; |
1669 | 0 | if (!tobj_vec_reserve(&buf, old + want, &alloc)) { |
1670 | 0 | r = TOBJ_ERR_ALLOC; |
1671 | 0 | break; |
1672 | 0 | } |
1673 | 0 | size_t got = 0; |
1674 | 0 | r = io->read(io->user_data, (uint8_t *)buf.data + old, want, &got); |
1675 | 0 | if (r != TOBJ_OK) break; |
1676 | 0 | if (got > want) { |
1677 | 0 | r = TOBJ_ERR_IO; |
1678 | 0 | break; |
1679 | 0 | } |
1680 | 0 | if (got == 0) break; |
1681 | 0 | buf.count = old + got; |
1682 | 0 | } |
1683 | |
|
1684 | 0 | if (io->close) io->close(io->user_data); |
1685 | 0 | if (r == TOBJ_OK) |
1686 | 0 | r = TOBJ_T(tobj_load_obj_from_memory)(out, (const uint8_t *)buf.data, |
1687 | 0 | buf.count, &cc, diag); |
1688 | 0 | tobj_vec_free(&buf, &alloc); |
1689 | 0 | return r; |
1690 | 0 | } Unexecuted instantiation: tobj_load_obj_from_io_f Unexecuted instantiation: tobj_load_obj_from_io_d |
1691 | | |
1692 | | #ifdef TOBJ_ENABLE_FILE_IO |
1693 | | tobj_result TOBJ_T(tobj_load_obj_from_file)(TOBJ_T(tobj_scene) * out, |
1694 | | const char *path, |
1695 | | const tobj_load_config *cfg, |
1696 | 0 | tobj_diag *diag) { |
1697 | 0 | if (!out) return TOBJ_ERR_INVALID_ARG; |
1698 | 0 | tobj_memset(out, 0, sizeof *out); |
1699 | 0 | if (!path) return TOBJ_ERR_INVALID_ARG; |
1700 | | |
1701 | 0 | tobj_load_config cc = cfg ? *cfg : tobj_default_config(); |
1702 | 0 | tobj_allocator alloc; |
1703 | 0 | if (!tobj_resolve_allocator(&cc.allocator, &alloc)) |
1704 | 0 | return TOBJ_ERR_INVALID_ARG; |
1705 | 0 | cc.allocator = alloc; |
1706 | |
|
1707 | 0 | tobj_file_buf fb; |
1708 | 0 | tobj_result r = tobj_file_open(&fb, path, &alloc, |
1709 | 0 | tobj_resolve_caps(&cc).input_bytes); |
1710 | 0 | if (r != TOBJ_OK) return r; |
1711 | | |
1712 | 0 | size_t dlen; |
1713 | 0 | char *basedir = tobj_dirname_dup(path, &alloc, &dlen); |
1714 | 0 | if (!basedir) { |
1715 | 0 | tobj_file_close(&fb); |
1716 | 0 | return TOBJ_ERR_ALLOC; |
1717 | 0 | } |
1718 | 0 | tobj_file_res_ctx ctx; |
1719 | 0 | ctx.basedir = basedir; |
1720 | 0 | ctx.alloc = alloc; |
1721 | 0 | ctx.max_bytes = tobj_resolve_caps(&cc).input_bytes; |
1722 | 0 | if (!cc.mtl_resolver) { |
1723 | 0 | cc.mtl_resolver = tobj_file_material_resolver; |
1724 | 0 | cc.mtl_resolver_user_data = &ctx; |
1725 | 0 | } |
1726 | |
|
1727 | 0 | r = TOBJ_T(tobj_load_obj_from_memory)(out, fb.data, fb.len, &cc, diag); |
1728 | |
|
1729 | 0 | tobj_free(&alloc, basedir, dlen + 1); |
1730 | 0 | tobj_file_close(&fb); |
1731 | 0 | return r; |
1732 | 0 | } Unexecuted instantiation: tobj_load_obj_from_file_f Unexecuted instantiation: tobj_load_obj_from_file_d |
1733 | | #endif /* TOBJ_ENABLE_FILE_IO */ |
1734 | | |
1735 | | /* ----------------------------------------------------------------------- */ |
1736 | | /* standalone .mtl parsing */ |
1737 | | /* ----------------------------------------------------------------------- */ |
1738 | | |
1739 | | tobj_result TOBJ_T(tobj_parse_mtl_from_memory)(TOBJ_T(tobj_material_list) * out, |
1740 | | const uint8_t *buf, size_t len, |
1741 | | const tobj_load_config *cfg, |
1742 | 0 | tobj_diag *diag) { |
1743 | 0 | if (!out) return TOBJ_ERR_INVALID_ARG; |
1744 | 0 | tobj_memset(out, 0, sizeof *out); |
1745 | 0 | if (!buf && len) return TOBJ_ERR_INVALID_ARG; |
1746 | | |
1747 | 0 | tobj_load_config defcfg; |
1748 | 0 | if (!cfg) { |
1749 | 0 | defcfg = tobj_default_config(); |
1750 | 0 | cfg = &defcfg; |
1751 | 0 | } |
1752 | 0 | if (len > tobj_resolve_caps(cfg).input_bytes) return TOBJ_ERR_LIMIT_EXCEEDED; |
1753 | 0 | tobj_allocator alloc; |
1754 | 0 | if (!tobj_resolve_allocator(&cfg->allocator, &alloc)) |
1755 | 0 | return TOBJ_ERR_INVALID_ARG; |
1756 | 0 | tobj_arena *arena = (tobj_arena *)tobj_alloc(&alloc, sizeof(tobj_arena), 16); |
1757 | 0 | if (!arena) return TOBJ_ERR_ALLOC; |
1758 | 0 | tobj_arena_init(arena, &alloc, 0); |
1759 | |
|
1760 | 0 | TOBJ_T(tobj_builder) b; |
1761 | 0 | tobj_memset(&b, 0, sizeof b); |
1762 | 0 | b.alloc = &alloc; |
1763 | 0 | b.arena = arena; |
1764 | 0 | b.diag = diag; |
1765 | 0 | b.cfg = cfg; |
1766 | 0 | b.caps = tobj_resolve_caps(cfg); |
1767 | 0 | b.err = TOBJ_OK; |
1768 | 0 | TOBJ_T(builder_init)(&b); |
1769 | |
|
1770 | 0 | TOBJ_T(parse_mtl_buffer)(&b, buf, len); |
1771 | 0 | if (b.err == TOBJ_OK) TOBJ_T(finalize_unknowns)(&b); |
1772 | |
|
1773 | 0 | if (b.err == TOBJ_OK) { |
1774 | 0 | out->count = b.materials.count; |
1775 | 0 | out->items = (TOBJ_T(tobj_material) *)tobj_vec_finalize(&b.materials, |
1776 | 0 | arena, 16); |
1777 | 0 | if (b.materials.count && !out->items) b.err = TOBJ_ERR_ALLOC; |
1778 | 0 | } |
1779 | |
|
1780 | 0 | TOBJ_T(builder_dispose)(&b); |
1781 | |
|
1782 | 0 | if (b.err != TOBJ_OK) { |
1783 | 0 | tobj_arena_destroy(arena); |
1784 | 0 | tobj_free(&alloc, arena, sizeof(tobj_arena)); |
1785 | 0 | tobj_memset(out, 0, sizeof *out); |
1786 | 0 | return b.err; |
1787 | 0 | } |
1788 | 0 | out->allocator = alloc; |
1789 | 0 | out->strpool = arena; |
1790 | 0 | return TOBJ_OK; |
1791 | 0 | } Unexecuted instantiation: tobj_parse_mtl_from_memory_f Unexecuted instantiation: tobj_parse_mtl_from_memory_d |
1792 | | |
1793 | 0 | void TOBJ_T(tobj_material_list_free)(TOBJ_T(tobj_material_list) * list) { |
1794 | 0 | if (!list) return; |
1795 | 0 | if (list->strpool) { |
1796 | 0 | tobj_arena *ar = (tobj_arena *)list->strpool; |
1797 | 0 | tobj_allocator a = list->allocator; |
1798 | 0 | tobj_arena_destroy(ar); |
1799 | 0 | tobj_free(&a, ar, sizeof(tobj_arena)); |
1800 | 0 | } |
1801 | 0 | tobj_memset(list, 0, sizeof *list); |
1802 | 0 | } Unexecuted instantiation: tobj_material_list_free_f Unexecuted instantiation: tobj_material_list_free_d |
1803 | | |
1804 | | /* ----------------------------------------------------------------------- */ |
1805 | | /* streaming callback API */ |
1806 | | /* ----------------------------------------------------------------------- */ |
1807 | | |
1808 | | tobj_result TOBJ_T(tobj_load_obj_with_callbacks)( |
1809 | | const uint8_t *buf, size_t len, const TOBJ_T(tobj_callbacks) * cb, |
1810 | 0 | const tobj_load_config *cfg, tobj_diag *diag) { |
1811 | 0 | if (!cb) return TOBJ_ERR_INVALID_ARG; |
1812 | 0 | if (!buf && len) return TOBJ_ERR_INVALID_ARG; |
1813 | | |
1814 | 0 | tobj_load_config defcfg; |
1815 | 0 | if (!cfg) { |
1816 | 0 | defcfg = tobj_default_config(); |
1817 | 0 | cfg = &defcfg; |
1818 | 0 | } |
1819 | 0 | if (len > tobj_resolve_caps(cfg).input_bytes) return TOBJ_ERR_LIMIT_EXCEEDED; |
1820 | 0 | tobj_allocator alloc; |
1821 | 0 | if (!tobj_resolve_allocator(&cfg->allocator, &alloc)) |
1822 | 0 | return TOBJ_ERR_INVALID_ARG; |
1823 | 0 | tobj_arena *arena = (tobj_arena *)tobj_alloc(&alloc, sizeof(tobj_arena), 16); |
1824 | 0 | if (!arena) return TOBJ_ERR_ALLOC; |
1825 | 0 | tobj_arena_init(arena, &alloc, 0); |
1826 | |
|
1827 | 0 | TOBJ_T(tobj_builder) b; |
1828 | 0 | tobj_memset(&b, 0, sizeof b); |
1829 | 0 | b.alloc = &alloc; |
1830 | 0 | b.arena = arena; |
1831 | 0 | b.diag = diag; |
1832 | 0 | b.cfg = cfg; |
1833 | 0 | b.caps = tobj_resolve_caps(cfg); |
1834 | 0 | b.err = TOBJ_OK; |
1835 | 0 | TOBJ_T(builder_init)(&b); |
1836 | 0 | void *ud = cb->user_data; |
1837 | |
|
1838 | 0 | tobj_vec lines; |
1839 | 0 | tobj_vec_init(&lines, sizeof(tobj_line)); |
1840 | 0 | if (!tobj_build_line_index(buf, len, &lines, &alloc)) b.err = TOBJ_ERR_ALLOC; |
1841 | |
|
1842 | 0 | size_t numv = 0, numvt = 0, numvn = 0; |
1843 | 0 | const char *base = (const char *)buf; |
1844 | |
|
1845 | 0 | for (size_t i = 0; i < lines.count && b.err == TOBJ_OK; i++) { |
1846 | 0 | tobj_line *ln = (tobj_line *)tobj_vec_at(&lines, i); |
1847 | 0 | b.line = i + 1; |
1848 | 0 | if (ln->len > b.caps.line_bytes) { |
1849 | 0 | b.err = TOBJ_ERR_LIMIT_EXCEEDED; |
1850 | 0 | break; |
1851 | 0 | } |
1852 | 0 | tobj_cursor c; |
1853 | 0 | tobj_cur_init(&c, base + ln->pos, ln->len); |
1854 | 0 | const char *tok; |
1855 | 0 | size_t tl; |
1856 | 0 | if (!tobj_next_token(&c, &tok, &tl)) continue; |
1857 | 0 | if (tok[0] == '#') continue; |
1858 | | |
1859 | 0 | if (tobj_slice_eq(tok, tl, "v")) { |
1860 | 0 | double nums[8]; |
1861 | 0 | int n = 0; |
1862 | 0 | while (n < 8) { |
1863 | 0 | double d; |
1864 | 0 | const char *save = c.p; |
1865 | 0 | if (!tobj_scan_double(&c.p, c.end, &d)) { |
1866 | 0 | c.p = save; |
1867 | 0 | break; |
1868 | 0 | } |
1869 | 0 | nums[n++] = d; |
1870 | 0 | } |
1871 | 0 | while (n < 3) nums[n++] = 0.0; |
1872 | 0 | TOBJ_REAL w = (n == 4) ? (TOBJ_REAL)nums[3] : (TOBJ_REAL)1; |
1873 | 0 | if (cb->vertex_cb) |
1874 | 0 | cb->vertex_cb(ud, (TOBJ_REAL)nums[0], (TOBJ_REAL)nums[1], |
1875 | 0 | (TOBJ_REAL)nums[2], w); |
1876 | 0 | if (cb->vertex_color_cb) { |
1877 | 0 | bool hc = n >= 6; |
1878 | 0 | cb->vertex_color_cb(ud, (TOBJ_REAL)nums[0], (TOBJ_REAL)nums[1], |
1879 | 0 | (TOBJ_REAL)nums[2], |
1880 | 0 | hc ? (TOBJ_REAL)nums[3] : (TOBJ_REAL)1, |
1881 | 0 | hc ? (TOBJ_REAL)nums[4] : (TOBJ_REAL)1, |
1882 | 0 | hc ? (TOBJ_REAL)nums[5] : (TOBJ_REAL)1, hc); |
1883 | 0 | } |
1884 | 0 | numv++; |
1885 | 0 | } else if (tobj_slice_eq(tok, tl, "vn")) { |
1886 | 0 | double d; |
1887 | 0 | TOBJ_REAL xyz[3] = {0, 0, 0}; |
1888 | 0 | for (int k = 0; k < 3; k++) |
1889 | 0 | if (tobj_scan_double(&c.p, c.end, &d)) xyz[k] = (TOBJ_REAL)d; |
1890 | 0 | if (cb->normal_cb) cb->normal_cb(ud, xyz[0], xyz[1], xyz[2]); |
1891 | 0 | numvn++; |
1892 | 0 | } else if (tobj_slice_eq(tok, tl, "vt")) { |
1893 | 0 | double d; |
1894 | 0 | TOBJ_REAL uvw[3] = {0, 0, 0}; |
1895 | 0 | for (int k = 0; k < 3; k++) |
1896 | 0 | if (tobj_scan_double(&c.p, c.end, &d)) uvw[k] = (TOBJ_REAL)d; |
1897 | 0 | if (cb->texcoord_cb) cb->texcoord_cb(ud, uvw[0], uvw[1], uvw[2]); |
1898 | 0 | numvt++; |
1899 | 0 | } else if (tobj_slice_eq(tok, tl, "f") || tobj_slice_eq(tok, tl, "l") || |
1900 | 0 | tobj_slice_eq(tok, tl, "p")) { |
1901 | 0 | char kind = tok[0]; |
1902 | 0 | b.corners.count = 0; |
1903 | 0 | const char *t2; |
1904 | 0 | size_t l2; |
1905 | 0 | while (tobj_next_token(&c, &t2, &l2)) { |
1906 | 0 | tobj_index *slot = (tobj_index *)tobj_vec_push(&b.corners, &alloc); |
1907 | 0 | if (!slot) { |
1908 | 0 | b.err = TOBJ_ERR_ALLOC; |
1909 | 0 | break; |
1910 | 0 | } |
1911 | 0 | TOBJ_T(parse_corner_n)(t2, l2, numv, numvt, numvn, slot); |
1912 | 0 | } |
1913 | 0 | if (b.err != TOBJ_OK) break; |
1914 | 0 | int nidx = tobj_size_to_int(b.corners.count); |
1915 | 0 | const tobj_index *ci = (const tobj_index *)b.corners.data; |
1916 | 0 | if (kind == 'f' && cb->index_cb && nidx >= 3) |
1917 | 0 | cb->index_cb(ud, ci, nidx); |
1918 | 0 | else if (kind == 'l' && cb->line_cb && nidx >= 2) |
1919 | 0 | cb->line_cb(ud, ci, nidx); |
1920 | 0 | else if (kind == 'p' && cb->point_cb && nidx >= 1) |
1921 | 0 | cb->point_cb(ud, ci, nidx); |
1922 | 0 | } else if (tobj_slice_eq(tok, tl, "g") || tobj_slice_eq(tok, tl, "o")) { |
1923 | 0 | const char *name = TOBJ_T(intern_rest)(&b, &c); |
1924 | 0 | if (!name) { |
1925 | 0 | b.err = TOBJ_ERR_ALLOC; |
1926 | 0 | break; |
1927 | 0 | } |
1928 | 0 | if (tok[0] == 'o') { |
1929 | 0 | if (cb->object_cb) cb->object_cb(ud, name); |
1930 | 0 | } else { |
1931 | 0 | if (cb->group_cb) { |
1932 | 0 | const char *names[1] = {name}; |
1933 | 0 | cb->group_cb(ud, names, 1); |
1934 | 0 | } |
1935 | 0 | } |
1936 | 0 | } else if (tobj_slice_eq(tok, tl, "usemtl")) { |
1937 | 0 | const char *p = c.p, *e = c.end; |
1938 | 0 | while (p < e && tobj_is_space(*p)) p++; |
1939 | 0 | while (e > p && tobj_is_space(e[-1])) e--; |
1940 | 0 | int id = TOBJ_T(mat_find)(&b, p, (size_t)(e - p)); |
1941 | 0 | if (cb->usemtl_cb) { |
1942 | 0 | const char *name = tobj_intern(arena, p, (size_t)(e - p)); |
1943 | 0 | cb->usemtl_cb(ud, name, id); |
1944 | 0 | } |
1945 | 0 | } else if (tobj_slice_eq(tok, tl, "mtllib")) { |
1946 | 0 | if (cfg->mtl_resolver) { |
1947 | 0 | const char *t2; |
1948 | 0 | size_t l2; |
1949 | 0 | size_t before = b.materials.count; |
1950 | 0 | while (tobj_next_token(&c, &t2, &l2)) { |
1951 | 0 | char *name = (char *)tobj_arena_alloc(arena, l2 + 1, 1); |
1952 | 0 | if (!name) { |
1953 | 0 | b.err = TOBJ_ERR_ALLOC; |
1954 | 0 | break; |
1955 | 0 | } |
1956 | 0 | tobj_memcpy(name, t2, l2); |
1957 | 0 | name[l2] = '\0'; |
1958 | 0 | tobj_mtl_source src; |
1959 | 0 | tobj_memset(&src, 0, sizeof src); |
1960 | 0 | if (cfg->mtl_resolver(cfg->mtl_resolver_user_data, name, &src) == |
1961 | 0 | TOBJ_OK) { |
1962 | 0 | TOBJ_T(parse_mtl_buffer)(&b, src.data, src.len); |
1963 | 0 | if (src.release) src.release(src.release_ud, src.data, src.len); |
1964 | 0 | } |
1965 | 0 | } |
1966 | 0 | if (b.err == TOBJ_OK && cb->mtllib_cb && b.materials.count > before) { |
1967 | 0 | cb->mtllib_cb(ud, (const TOBJ_T(tobj_material) *)b.materials.data, |
1968 | 0 | tobj_size_to_int(b.materials.count)); |
1969 | 0 | } |
1970 | 0 | } |
1971 | 0 | } |
1972 | 0 | } |
1973 | |
|
1974 | 0 | TOBJ_T(builder_dispose)(&b); |
1975 | 0 | tobj_vec_free(&lines, &alloc); |
1976 | 0 | tobj_arena_destroy(arena); |
1977 | 0 | tobj_free(&alloc, arena, sizeof(tobj_arena)); |
1978 | 0 | return b.err; |
1979 | 0 | } Unexecuted instantiation: tobj_load_obj_with_callbacks_f Unexecuted instantiation: tobj_load_obj_with_callbacks_d |