code wiki / (root) / nx_fbx_bind.nx

nx_fbx_bind.nx source

↩ module page · 501 lines · 21341 B

1// Bind-pose geometry conversion for skinned binary FBX assets. 2// Diagnostic prototype: raw Transform is bone-relative. TransformLink * Transform 3// reconstructs mesh-global bind space; agreement must be qualified before conversion. 4import "nx_fbx_core.nx" 5 6const FBB_WORD: i64 = 8 7const FBB_MATRIX_WORDS: i64 = 16 8const FBB_Q: i64 = 1048576 9const FBB_VERTEX_Q: i64 = 1024 10const FBB_I64_MAX: i64 = 9223372036854775807 11const FBB_BAD: i64 = 0 - 10 12const FBB_MISSING: i64 = 0 - 11 13const FBB_CONFLICT: i64 = 0 - 12 14const FBB_RANGE: i64 = 0 - 13 15const FBB_GEOMETRIC: i64 = 0 - 14 16const FBB_MEMORY: i64 = 0 - 15 17const FBB_GEOMETRY: i64 = 1 18const FBB_SKIN: i64 = 2 19const FBB_CLUSTER: i64 = 3 20const FBB_MODEL: i64 = 4 21 22struct FbxBindObject { 23 id: i64, 24 kind: i64, 25 count: i64, 26 matrix: i64, 27 geometric: i64, 28 link_matrix: i64, 29} 30struct FbxBindScene { 31 objects: *FbxBindObject, 32 count: i64, 33 links: *i64, 34 link_count: i64, 35} 36 37func fbb_property_size(b: *u8,p: i64,end: i64) -> i64 { 38 if p < 0 || p >= end { return FBB_BAD } 39 let t: i64 = b[p] as i64 40 var h: i64 = 1 41 if t == 83 || t == 82 { h = 5 } 42 if t == 102 || t == 100 || t == 108 || t == 105 || t == 98 { h = 13 } 43 if h > end-p { return FBB_BAD } 44 let size: i64 = fbxc_prop_size(b,p) 45 if size <= 0 || size > end-p { return FBB_BAD } 46 return size 47} 48func fbb_string(b: *u8,p: i64,end: i64,s: *u8) -> i64 { 49 let size: i64 = fbb_property_size(b,p,end) 50 if size < 5 { return 0 } 51 if b[p] != (83 as u8) { return 0 } 52 return fbxc_name_is(b,p+5,size-5,s) 53} 54func fbb_node(b: *u8,n: i64,p: i64,end: i64,big: i64,h: *i64) -> i64 { 55 var hs: i64 = 13 56 if big == 1 { hs = 25 } 57 if p < 0 || p > end || end > n || hs > end-p { return FBB_BAD } 58 // A null record terminates this sibling list. 59 if fbxc_u32(b,p) == 0 { 60 var z: i64 = 0 61 while z < hs { if b[p+z] != (0 as u8) { return FBB_BAD } z = z+1 } 62 return 0 63 } 64 if fbxc_hdr(b,n,p,big,h) != 0 { return FBB_BAD } 65 let eo: i64 = h[FBXC_END] 66 let po: i64 = h[FBXC_PROPSOFF] 67 let pl: i64 = h[FBXC_PLEN] 68 if eo <= p || eo > end || po < p || po > eo || pl < 0 || pl > eo-po { return FBB_BAD } 69 return 1 70} 71func fbb_find_child(b: *u8,n: i64,start: i64,end: i64,big: i64,name: *u8,out: *i64) -> i64 { 72 let h: *i64 = sys_mmap(FBXC_OUTN*FBB_WORD) as *i64 73 var p: i64 = start 74 var rc: i64 = 0 75 var stop: i64 = 0 76 while p < end && stop == 0 { 77 rc = fbb_node(b,n,p,end,big,h) 78 if rc <= 0 { stop = 1 } 79 else { 80 if fbxc_name_is(b,h[FBXC_NAMEOFF],h[FBXC_NAMELEN],name) == 1 { 81 var j: i64 = 0 82 while j < FBXC_OUTN { out[j] = h[j]; j = j+1 } 83 stop = 1 84 } else { p = h[FBXC_END]; rc = 0 } 85 } 86 } 87 sys_munmap(h as *u8,FBXC_OUTN*FBB_WORD) 88 return rc 89} 90func fbb_sibling_count(b: *u8,n: i64,start: i64,end: i64,big: i64) -> i64 { 91 let h: *i64 = sys_mmap(FBXC_OUTN*FBB_WORD) as *i64 92 var p: i64 = start 93 var count: i64 = 0 94 var stop: i64 = 0 95 while p < end && stop == 0 { 96 let rc: i64 = fbb_node(b,n,p,end,big,h) 97 if rc < 0 { count = rc; stop = 1 } 98 else { if rc == 0 { stop = 1 } else { count = count+1; p = h[FBXC_END] } } 99 } 100 sys_munmap(h as *u8,FBXC_OUTN*FBB_WORD) 101 return count 102} 103func fbb_matrix(b: *u8,p: i64,end: i64,out: *i64) -> i64 { 104 let size: i64 = fbb_property_size(b,p,end) 105 if size < 13 { return FBB_BAD } 106 if b[p] != (100 as u8) || fbxc_u32(b,p+1) != FBB_MATRIX_WORDS { return FBB_BAD } 107 let meta: *i64 = sys_mmap(4*FBB_WORD) as *i64 108 if fbxc_array(b,p+1,FBB_WORD,meta) != 0 { sys_munmap(meta as *u8,4*FBB_WORD); return FBB_BAD } 109 var rc: i64 = 0 110 if meta[1] != FBB_MATRIX_WORDS*FBB_WORD { rc = FBB_BAD } 111 var j: i64 = 0 112 while j < FBB_MATRIX_WORDS && rc == 0 { 113 let bits: i64 = fbxc_i64le(meta[0] as *u8,j*FBB_WORD) 114 let exponent: i64 = (bits >> 52) & 2047 115 // Q20 must fit a signed i64; reject nonfinite and unrepresentable input. 116 if exponent >= 1065 { rc = FBB_RANGE } 117 else { out[j] = fbxc_f64_p20(bits) } 118 j = j+1 119 } 120 if meta[3] == 1 { sys_munmap(meta[0] as *u8,meta[1]) } 121 sys_munmap(meta as *u8,4*FBB_WORD) 122 if rc != 0 { return rc } 123 if out[3] != 0 || out[7] != 0 || out[11] != 0 || out[15] != FBB_Q { return FBB_BAD } 124 return 0 125} 126func fbb_parent(s: *FbxBindScene,id: i64,kind: i64) -> i64 { 127 var found: i64 = FBB_MISSING 128 var i: i64 = 0 129 while i < s.link_count { 130 if s.links[i*2] == id { 131 let pid: i64 = s.links[i*2+1] 132 var j: i64 = 0 133 while j < s.count { 134 let o: *FbxBindObject = ((s.objects as i64)+j*__size_of(FbxBindObject)) as *FbxBindObject 135 if o.id == pid && o.kind == kind { 136 if found >= 0 && found != j { return FBB_CONFLICT } 137 found = j 138 } 139 j = j+1 140 } 141 } 142 i = i+1 143 } 144 return found 145} 146func fbb_object(s: *FbxBindScene,i: i64) -> *FbxBindObject { 147 return ((s.objects as i64)+i*__size_of(FbxBindObject)) as *FbxBindObject 148} 149func fbb_geometric_check(b: *u8,n: i64,start: i64,end: i64,big: i64,h: *i64) -> i64 { 150 let hit: i64 = fbb_find_child(b,n,start,end,big,"Properties70" as *u8,h) 151 if hit <= 0 { return hit } 152 var p: i64 = h[FBXC_PROPSOFF]+h[FBXC_PLEN] 153 let pe: i64 = h[FBXC_END] 154 while p < pe { 155 let rc: i64 = fbb_node(b,n,p,pe,big,h) 156 if rc <= 0 { return rc } 157 let po: i64 = h[FBXC_PROPSOFF] 158 let ep: i64 = po+h[FBXC_PLEN] 159 if fbb_string(b,po,ep,"GeometricTranslation" as *u8) == 1 { return FBB_GEOMETRIC } 160 if fbb_string(b,po,ep,"GeometricRotation" as *u8) == 1 { return FBB_GEOMETRIC } 161 if fbb_string(b,po,ep,"GeometricScaling" as *u8) == 1 { return FBB_GEOMETRIC } 162 p = h[FBXC_END] 163 } 164 return 0 165} 166func fbb_load(b: *u8,n: i64,s: *FbxBindScene) -> i64 { 167 let version: i64 = fbxc_version(b,n) 168 if version < 0 { return FBB_BAD } 169 let big: i64 = fbxc_big(version) 170 let h: *i64 = sys_mmap(FBXC_OUTN*FBB_WORD) as *i64 171 let c: *i64 = sys_mmap(FBXC_OUTN*FBB_WORD) as *i64 172 if fbb_find_child(b,n,FBXC_TOPOFF,n,big,"Objects" as *u8,h) != 1 { return FBB_BAD } 173 let start: i64 = h[FBXC_PROPSOFF]+h[FBXC_PLEN] 174 let end: i64 = h[FBXC_END] 175 let count: i64 = fbb_sibling_count(b,n,start,end,big) 176 if count <= 0 { return FBB_BAD } 177 s.objects = sys_mmap(count*__size_of(FbxBindObject)) as *FbxBindObject 178 s.count = count 179 var p: i64 = start 180 var i: i64 = 0 181 while i < count { 182 if fbb_node(b,n,p,end,big,h) != 1 { return FBB_BAD } 183 let o: *FbxBindObject = fbb_object(s,i) 184 let po: i64 = h[FBXC_PROPSOFF] 185 let ep: i64 = po+h[FBXC_PLEN] 186 if fbb_property_size(b,po,ep) < 9 || b[po] != (76 as u8) { return FBB_BAD } 187 o.id = fbxc_i64le(b,po+1) 188 let named: i64 = fbb_property_size(b,po+9,ep) 189 if named < 0 { return FBB_BAD } 190 let typep: i64 = po+9+named 191 let child: i64 = ep 192 let objend: i64 = h[FBXC_END] 193 if fbxc_name_is(b,h[FBXC_NAMEOFF],h[FBXC_NAMELEN],"Geometry" as *u8) == 1 { 194 if fbb_string(b,typep,ep,"Mesh" as *u8) == 1 { 195 o.kind = FBB_GEOMETRY 196 if fbb_find_child(b,n,child,objend,big,"Vertices" as *u8,c) != 1 { return FBB_BAD } 197 let vp: i64 = c[FBXC_PROPSOFF] 198 if fbb_property_size(b,vp,vp+c[FBXC_PLEN]) < 13 || b[vp] != (100 as u8) { return FBB_BAD } 199 let scalars: i64 = fbxc_u32(b,vp+1) 200 if scalars%3 != 0 { return FBB_BAD } 201 o.count = scalars/3 202 } 203 } 204 if fbxc_name_is(b,h[FBXC_NAMEOFF],h[FBXC_NAMELEN],"Deformer" as *u8) == 1 { 205 if fbb_string(b,typep,ep,"Skin" as *u8) == 1 { o.kind = FBB_SKIN } 206 if fbb_string(b,typep,ep,"Cluster" as *u8) == 1 { 207 o.kind = FBB_CLUSTER 208 if fbb_find_child(b,n,child,objend,big,"Transform" as *u8,c) != 1 { return FBB_MISSING } 209 o.matrix = sys_mmap(FBB_MATRIX_WORDS*FBB_WORD) as i64 210 let rc: i64 = fbb_matrix(b,c[FBXC_PROPSOFF],c[FBXC_PROPSOFF]+c[FBXC_PLEN],o.matrix as *i64) 211 if rc != 0 { return rc } 212 if fbb_find_child(b,n,child,objend,big,"TransformLink" as *u8,c) != 1 { return FBB_MISSING } 213 o.link_matrix = sys_mmap(FBB_MATRIX_WORDS*FBB_WORD) as i64 214 let lr: i64 = fbb_matrix(b,c[FBXC_PROPSOFF],c[FBXC_PROPSOFF]+c[FBXC_PLEN],o.link_matrix as *i64) 215 if lr != 0 { return lr } 216 } 217 } 218 if fbxc_name_is(b,h[FBXC_NAMEOFF],h[FBXC_NAMELEN],"Model" as *u8) == 1 { 219 o.kind = FBB_MODEL 220 o.geometric = fbb_geometric_check(b,n,child,objend,big,c) 221 if o.geometric < 0 && o.geometric != FBB_GEOMETRIC { return o.geometric } 222 } 223 p = objend 224 i = i+1 225 } 226 if fbb_find_child(b,n,FBXC_TOPOFF,n,big,"Connections" as *u8,h) != 1 { return FBB_BAD } 227 p = h[FBXC_PROPSOFF]+h[FBXC_PLEN] 228 let lend: i64 = h[FBXC_END] 229 let lc: i64 = fbb_sibling_count(b,n,p,lend,big) 230 if lc < 0 { return lc } 231 s.links = sys_mmap(lc*2*FBB_WORD) as *i64 232 s.link_count = 0 233 i = 0 234 while i < lc { 235 if fbb_node(b,n,p,lend,big,h) != 1 { return FBB_BAD } 236 let po: i64 = h[FBXC_PROPSOFF] 237 let ep: i64 = po+h[FBXC_PLEN] 238 if fbb_string(b,po,ep,"OO" as *u8) == 1 { 239 let a: i64 = po+fbb_property_size(b,po,ep) 240 if fbb_property_size(b,a,ep) != 9 || fbb_property_size(b,a+9,ep) != 9 { return FBB_BAD } 241 if b[a] != (76 as u8) || b[a+9] != (76 as u8) { return FBB_BAD } 242 s.links[s.link_count*2] = fbxc_i64le(b,a+1) 243 s.links[s.link_count*2+1] = fbxc_i64le(b,a+10) 244 s.link_count = s.link_count+1 245 } 246 p = h[FBXC_END] 247 i = i+1 248 } 249 sys_munmap(h as *u8,FBXC_OUTN*FBB_WORD) 250 sys_munmap(c as *u8,FBXC_OUTN*FBB_WORD) 251 return 0 252} 253func fbb_resolve(s: *FbxBindScene) -> i64 { 254 var i: i64 = 0 255 while i < s.count { 256 let c: *FbxBindObject = fbb_object(s,i) 257 if c.kind == FBB_CLUSTER { 258 let si: i64 = fbb_parent(s,c.id,FBB_SKIN) 259 if si < 0 { return si } 260 let sk: *FbxBindObject = fbb_object(s,si) 261 let gi: i64 = fbb_parent(s,sk.id,FBB_GEOMETRY) 262 if gi < 0 { return gi } 263 let g: *FbxBindObject = fbb_object(s,gi) 264 if g.matrix == 0 { g.matrix = c.matrix } 265 else { 266 let a: *i64 = g.matrix as *i64 267 let d: *i64 = c.matrix as *i64 268 var j: i64 = 0 269 while j < FBB_MATRIX_WORDS { if a[j] != d[j] { return FBB_CONFLICT } j = j+1 } 270 } 271 } 272 i = i+1 273 } 274 i = 0 275 while i < s.count { 276 let g: *FbxBindObject = fbb_object(s,i) 277 if g.kind == FBB_GEOMETRY { 278 if g.matrix == 0 { return FBB_MISSING } 279 let mi: i64 = fbb_parent(s,g.id,FBB_MODEL) 280 if mi < 0 { return mi } 281 let model: *FbxBindObject = fbb_object(s,mi) 282 if model.geometric != 0 { return model.geometric } 283 } 284 i = i+1 285 } 286 return 0 287} 288 289// Column-major affine composition. Overflow checks precede every multiply/add. 290// out remains untouched on failure; Q20 truncation is measured by the diagnostic. 291// Caller-owned scratch avoids one allocation per joint while preserving atomic output. 292func fbb_compose_into(a:*i64,b:*i64,out:*i64,tmp:*i64,tmp_words:i64)->i64 { 293 if (a as i64)<=0||(b as i64)<=0||(out as i64)<=0||(tmp as i64)<=0||tmp_words<FBB_MATRIX_WORDS{return FBB_BAD} 294 let bytes:i64=FBB_MATRIX_WORDS*FBB_WORD 295 let ta:i64=tmp as i64;let aa:i64=a as i64;let ba:i64=b as i64;let oa:i64=out as i64 296 if (ta>=aa&&ta-aa<bytes)||(aa>ta&&aa-ta<bytes){return FBB_CONFLICT} 297 if (ta>=ba&&ta-ba<bytes)||(ba>ta&&ba-ta<bytes){return FBB_CONFLICT} 298 if (ta>=oa&&ta-oa<bytes)||(oa>ta&&oa-ta<bytes){return FBB_CONFLICT} 299 var rc: i64 = 0 300 var col: i64 = 0 301 while col < 4 && rc == 0 { 302 var row: i64 = 0 303 while row < 4 && rc == 0 { 304 var sum: i64 = 0 305 var k: i64 = 0 306 while k < 4 && rc == 0 { 307 let x: i64 = a[k*4+row] 308 let y: i64 = b[col*4+k] 309 if x < (0-FBB_I64_MAX) || y < (0-FBB_I64_MAX) { rc = FBB_RANGE } 310 else { 311 var ax: i64 = x 312 var ay: i64 = y 313 if ax < 0 { ax = 0-ax } 314 if ay < 0 { ay = 0-ay } 315 if ay != 0 { if ax > FBB_I64_MAX/ay { rc = FBB_RANGE } } 316 if rc == 0 { 317 let term: i64 = (x*y)/FBB_Q 318 if term > 0 && sum > FBB_I64_MAX-term { rc = FBB_RANGE } 319 else { 320 if term < 0 && sum < (0-FBB_I64_MAX)-term { rc = FBB_RANGE } 321 else { sum = sum+term } 322 } 323 } 324 } 325 k = k+1 326 } 327 tmp[col*4+row] = sum 328 row = row+1 329 } 330 col = col+1 331 } 332 if rc == 0 { 333 var j: i64 = 0 334 while j < FBB_MATRIX_WORDS { out[j] = tmp[j]; j = j+1 } 335 } 336 return rc 337} 338 339func fbb_compose(a:*i64,b:*i64,out:*i64)->i64 { 340 let tmp:*i64=sys_mmap_try(FBB_MATRIX_WORDS*FBB_WORD) as *i64 341 if (tmp as i64)<=0{return FBB_MEMORY} 342 let rc:i64=fbb_compose_into(a,b,out,tmp,FBB_MATRIX_WORDS) 343 sys_munmap_direct(tmp as *u8,FBB_MATRIX_WORDS*FBB_WORD) 344 return rc 345} 346 347func fbb_pose_models(b: *u8,n: i64,s: *FbxBindScene) -> i64 { 348 let big: i64 = fbxc_big(fbxc_version(b,n)) 349 let h: *i64 = sys_mmap(FBXC_OUTN*FBB_WORD) as *i64 350 let c: *i64 = sys_mmap(FBXC_OUTN*FBB_WORD) as *i64 351 let d: *i64 = sys_mmap(FBXC_OUTN*FBB_WORD) as *i64 352 let matrix: *i64 = sys_mmap(FBB_MATRIX_WORDS*FBB_WORD) as *i64 353 var rc: i64 = 0 354 if fbb_find_child(b,n,FBXC_TOPOFF,n,big,"Objects" as *u8,h) != 1 { rc = FBB_BAD } 355 var p: i64 = h[FBXC_PROPSOFF]+h[FBXC_PLEN] 356 let end: i64 = h[FBXC_END] 357 while p < end && rc == 0 { 358 let node: i64 = fbb_node(b,n,p,end,big,h) 359 if node <= 0 { if node < 0 { rc = node } p = end } 360 else { 361 let next: i64 = h[FBXC_END] 362 if fbxc_name_is(b,h[FBXC_NAMEOFF],h[FBXC_NAMELEN],"Pose" as *u8) == 1 { 363 let child: i64 = h[FBXC_PROPSOFF]+h[FBXC_PLEN] 364 let hit: i64 = fbb_find_child(b,n,child,next,big,"Type" as *u8,c) 365 if hit < 0 { rc = hit } 366 if hit == 1 { 367 if fbb_string(b,c[FBXC_PROPSOFF],c[FBXC_PROPSOFF]+c[FBXC_PLEN],"BindPose" as *u8) == 1 { 368 var q: i64 = child 369 while q < next && rc == 0 { 370 let sub: i64 = fbb_node(b,n,q,next,big,c) 371 if sub <= 0 { if sub < 0 { rc = sub } q = next } 372 else { 373 let qe: i64 = c[FBXC_END] 374 if fbxc_name_is(b,c[FBXC_NAMEOFF],c[FBXC_NAMELEN],"PoseNode" as *u8) == 1 { 375 let qp: i64 = c[FBXC_PROPSOFF]+c[FBXC_PLEN] 376 if fbb_find_child(b,n,qp,qe,big,"Node" as *u8,d) != 1 { rc = FBB_BAD } 377 else { 378 let np: i64 = d[FBXC_PROPSOFF] 379 if fbb_property_size(b,np,np+d[FBXC_PLEN]) != 9 { rc = FBB_BAD } 380 else { 381 if b[np] != (76 as u8) { rc = FBB_BAD } 382 else { 383 let id: i64 = fbxc_i64le(b,np+1) 384 var i: i64 = 0 385 while i < s.count && rc == 0 { 386 let o: *FbxBindObject = fbb_object(s,i) 387 if o.id == id && o.kind == FBB_MODEL { 388 if fbb_find_child(b,n,qp,qe,big,"Matrix" as *u8,d) != 1 { rc = FBB_MISSING } 389 else { 390 rc = fbb_matrix(b,d[FBXC_PROPSOFF],d[FBXC_PROPSOFF]+d[FBXC_PLEN],matrix) 391 if rc == 0 { 392 if o.matrix == 0 { 393 o.matrix = sys_mmap(FBB_MATRIX_WORDS*FBB_WORD) as i64 394 let dest: *i64 = o.matrix as *i64 395 var j: i64 = 0 396 while j < FBB_MATRIX_WORDS { dest[j] = matrix[j]; j = j+1 } 397 } else { 398 let saved: *i64 = o.matrix as *i64 399 var j: i64 = 0 400 while j < FBB_MATRIX_WORDS { 401 if saved[j] != matrix[j] { rc = FBB_CONFLICT } 402 j = j+1 403 } 404 } 405 } 406 } 407 } 408 i = i+1 409 } 410 } 411 } 412 } 413 } 414 q = qe 415 } 416 } 417 } 418 } 419 } 420 p = next 421 } 422 } 423 sys_munmap(h as *u8,FBXC_OUTN*FBB_WORD) 424 sys_munmap(c as *u8,FBXC_OUTN*FBB_WORD) 425 sys_munmap(d as *u8,FBXC_OUTN*FBB_WORD) 426 sys_munmap(matrix as *u8,FBB_MATRIX_WORDS*FBB_WORD) 427 return rc 428} 429 430// Applies explicit BindPose model matrices to the ordered geometry stream. 431// Q20 matrix * fx1024 position returns fx1024; originals/output remain intact on error. 432func fbb_point(m: *i64,v: *i64,out: *i64) -> i64 { 433 var row: i64 = 0 434 while row < 3 { 435 // Translation is converted from Q20 to fx1024 before accumulation. 436 var sum: i64 = m[12+row]/(FBB_Q/FBB_VERTEX_Q) 437 var k: i64 = 0 438 while k < 3 { 439 let a: i64 = m[k*4+row] 440 let b: i64 = v[k] 441 if a < (0-FBB_I64_MAX) || b < (0-FBB_I64_MAX) { return FBB_RANGE } 442 var aa: i64 = a 443 var bb: i64 = b 444 if aa < 0 { aa=0-aa } 445 if bb < 0 { bb=0-bb } 446 if bb != 0 { if aa > FBB_I64_MAX/bb { return FBB_RANGE } } 447 let term: i64 = (a*b)/FBB_Q 448 if term > 0 { if sum > FBB_I64_MAX-term { return FBB_RANGE } } 449 if term < 0 { if sum < (0-FBB_I64_MAX)-term { return FBB_RANGE } } 450 sum=sum+term 451 k=k+1 452 } 453 out[row]=sum 454 row=row+1 455 } 456 return 0 457} 458func fbb_apply_pose(s: *FbxBindScene,input: *i64,nv: i64,out: *i64) -> i64 { 459 if nv <= 0 || nv > FBB_I64_MAX/(3*FBB_WORD) { return FBB_RANGE } 460 var total: i64 = 0 461 var i: i64 = 0 462 while i < s.count { 463 let g: *FbxBindObject = fbb_object(s,i) 464 if g.kind == FBB_GEOMETRY { 465 if g.count < 0 || g.count > nv-total { return FBB_BAD } 466 total=total+g.count 467 let mi: i64 = fbb_parent(s,g.id,FBB_MODEL) 468 if mi < 0 { return mi } 469 let model: *FbxBindObject = fbb_object(s,mi) 470 if model.matrix == 0 { return FBB_MISSING } 471 if model.geometric != 0 { return model.geometric } 472 } 473 i=i+1 474 } 475 if total != nv { return FBB_BAD } 476 let scratch: *i64 = sys_mmap(nv*3*FBB_WORD) as *i64 477 var base: i64 = 0 478 var rc: i64 = 0 479 i=0 480 while i < s.count && rc == 0 { 481 let g: *FbxBindObject = fbb_object(s,i) 482 if g.kind == FBB_GEOMETRY { 483 let mi: i64 = fbb_parent(s,g.id,FBB_MODEL) 484 let model: *FbxBindObject = fbb_object(s,mi) 485 var j: i64 = 0 486 while j < g.count && rc == 0 { 487 let off: i64 = (base+j)*3*FBB_WORD 488 rc=fbb_point(model.matrix as *i64,((input as i64)+off) as *i64,((scratch as i64)+off) as *i64) 489 j=j+1 490 } 491 base=base+g.count 492 } 493 i=i+1 494 } 495 if rc == 0 { 496 var j: i64 = 0 497 while j < nv*3 { out[j]=scratch[j]; j=j+1 } 498 } 499 sys_munmap(scratch as *u8,nv*3*FBB_WORD) 500 return rc 501}