gltf2loader.monkey2 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. Namespace mojo3d.gltf2
  2. Private
  3. Class Gltf2Loader
  4. Method New( asset:Gltf2Asset,bindata:DataBuffer,dir:String )
  5. _asset=asset
  6. _bindata=bindata
  7. _dir=dir
  8. End
  9. Method LoadMesh:Mesh()
  10. Local mesh:=New Mesh
  11. For Local node:=Eachin _asset.scene.nodes
  12. LoadMesh( node,mesh,Null )
  13. Next
  14. Return mesh
  15. End
  16. Method LoadModel:Model()
  17. Local mesh:=New Mesh
  18. Local materials:=New Stack<Material>
  19. For Local node:=Eachin _asset.scene.nodes
  20. LoadMesh( node,mesh,materials )
  21. Next
  22. Local model:=New Model
  23. model.Mesh=mesh
  24. model.Materials=materials.ToArray()
  25. Return model
  26. End
  27. Method LoadBonedModel:Model()
  28. Local pivot:=New Model
  29. For Local node:=Eachin _asset.scene.nodes
  30. LoadBonedModel( node,pivot )
  31. Next
  32. LoadAnimator( pivot )
  33. LoadBones()
  34. For Local node:=Eachin _asset.scene.nodes
  35. LoadBonedMesh( node )
  36. Next
  37. Return pivot
  38. End
  39. Private
  40. Alias IndexType:UInt
  41. Field _asset:Gltf2Asset
  42. Field _dir:String
  43. Field _data:=New Map<Gltf2Buffer,DataBuffer>
  44. Field _uridata:=New StringMap<DataBuffer>
  45. Field _bindata:DataBuffer
  46. Field _textureCache:=New Map<Gltf2Texture,Texture>
  47. Field _materialCache:=New Map<Gltf2Material,Material>
  48. Field _nodeIds:=New Map<Gltf2Node,Int>
  49. Field _entityIds:=New Map<Entity,Int>
  50. Field _entities:=New Stack<Entity>
  51. Field _bones:Model.Bone[]
  52. Method GetData:UByte Ptr( buffer:Gltf2Buffer )
  53. If _data.Contains( buffer ) Return _data[buffer]?.Data
  54. Local data:DataBuffer,uri:=buffer.uri
  55. If Not uri
  56. data=_bindata
  57. Else If uri.StartsWith( "data:" )
  58. Local i:=uri.Find( ";base64," )
  59. If i<>-1
  60. Local base64:=uri.Slice( i+8 )
  61. data=DecodeBase64( base64 )
  62. Else
  63. Print "Can't decode data:"
  64. Endif
  65. Else If _uridata.Contains( uri )
  66. data=_uridata[uri]
  67. Else
  68. data=DataBuffer.Load( _dir+uri )
  69. _uridata[uri]=data
  70. Endif
  71. _data[buffer]=data
  72. Return data?.Data
  73. End
  74. Method GetData:UByte Ptr( bufferView:Gltf2BufferView )
  75. Return GetData( bufferView.buffer )+bufferView.byteOffset
  76. End
  77. Method GetData:UByte Ptr( accessor:Gltf2Accessor )
  78. Return GetData( accessor.bufferView )+accessor.byteOffset
  79. End
  80. Method GetTexture:Texture( texture:Gltf2Texture )
  81. If Not texture Return Null
  82. If _textureCache.Contains( texture ) Return _textureCache[texture]
  83. Local flags:=TextureFlags.Filter|TextureFlags.Mipmap|TextureFlags.WrapS|TextureFlags.WrapT
  84. Local tex:Texture
  85. Local source:=texture.source
  86. If source.uri
  87. tex=Texture.Load( _dir+source.uri,flags )
  88. Else If source.bufferView
  89. Local start:=ULong( GetData( source.bufferView ) )
  90. Local length:=source.bufferView.byteLength
  91. Local path:="memory::("+start+","+length+")"
  92. If source.mimeType.StartsWith( "image/" ) path+="."+texture.source.mimeType.Slice( 6 )
  93. tex=Texture.Load( path,flags )
  94. Endif
  95. _textureCache[texture]=tex
  96. Return tex
  97. End
  98. Method GetMaterial:Material( material:Gltf2Material,textured:Bool,boned:Bool )
  99. If Not material
  100. Local mat:=New PbrMaterial( Color.Magenta,0,1 )
  101. mat.Boned=boned
  102. Return mat
  103. Endif
  104. If _materialCache.Contains( material ) Return _materialCache[material]
  105. Local baseColorTexture:Texture
  106. Local metallicRoughnessTexture:Texture
  107. Local emissiveTexture:Texture
  108. Local occlusionTexture:Texture
  109. Local normalTexture:Texture
  110. If textured
  111. baseColorTexture=GetTexture( material.baseColorTexture )
  112. metallicRoughnessTexture=GetTexture( material.metallicRoughnessTexture )
  113. emissiveTexture=GetTexture( material.emissiveTexture )
  114. occlusionTexture=GetTexture( material.occlusionTexture )
  115. normalTexture=GetTexture( material.normalTexture )
  116. Endif
  117. Local mat:=New PbrMaterial
  118. mat.Boned=boned
  119. mat.Name=material.name
  120. mat.Uniforms.LinearColors=True
  121. If baseColorTexture mat.ColorTexture=baseColorTexture
  122. mat.ColorFactor=New Color( material.baseColorFactor )
  123. If metallicRoughnessTexture
  124. mat.MetalnessTexture=metallicRoughnessTexture
  125. mat.RoughnessTexture=metallicRoughnessTexture
  126. Endif
  127. mat.MetalnessFactor=material.metallicFactor
  128. mat.RoughnessFactor=material.roughnessFactor
  129. If emissiveTexture
  130. mat.EmissiveTexture=emissiveTexture
  131. If material.emissiveFactor<>Null
  132. mat.EmissiveFactor=New Color( material.emissiveFactor.x,material.emissiveFactor.y,material.emissiveFactor.z )
  133. Else
  134. mat.EmissiveFactor=Color.White
  135. Endif
  136. Else If material.emissiveFactor<>Null
  137. mat.EmissiveTexture=Texture.ColorTexture( Color.White )
  138. mat.EmissiveFactor=New Color( material.emissiveFactor.x,material.emissiveFactor.y,material.emissiveFactor.z )
  139. Endif
  140. If occlusionTexture mat.OcclusionTexture=occlusionTexture
  141. If normalTexture mat.NormalTexture=normalTexture
  142. Select material.alphaMode
  143. Case "BLEND" mat.BlendMode=BlendMode.Alpha
  144. End
  145. If material.doubleSided
  146. mat.CullMode=CullMode.None
  147. Endif
  148. _materialCache[material]=mat
  149. Return mat
  150. End
  151. Method FlipMatrix:Mat4f( matrix:Mat4f )
  152. matrix.i.z=-matrix.i.z
  153. matrix.j.z=-matrix.j.z
  154. matrix.k.x=-matrix.k.x
  155. matrix.k.y=-matrix.k.y
  156. matrix.t.z=-matrix.t.z
  157. Return matrix
  158. End
  159. Method GetWorldMatrix:Mat4f( node:Gltf2Node )
  160. Return node.parent ? GetWorldMatrix( node.parent ) * GetLocalMatrix( node ) Else GetLocalMatrix( node )
  161. End
  162. Method GetLocalMatrix:Mat4f( node:Gltf2Node )
  163. Local matrix:Mat4f
  164. If node.hasMatrix Return FlipMatrix( node.matrix )
  165. Local v:=node.translation
  166. v.z=-v.z
  167. Local q:=node.rotation
  168. q.v.x=-q.v.x
  169. q.v.y=-q.v.y
  170. q.w=-q.w
  171. Local s:=node.scale
  172. Return Mat4f.Translation( v ) * Mat4f.Rotation( q ) * Mat4f.Scaling( s )
  173. End
  174. Method LoadPrimitive:Mesh( prim:Gltf2Primitive )
  175. 'some sanity checking!
  176. '
  177. If prim.mode<>4
  178. Print "Gltf invalid mesh mode:"+prim.mode
  179. Return Null
  180. Endif
  181. If Not prim.indices
  182. Print "Gltf mesh has no indices"
  183. Return Null
  184. Endif
  185. If prim.POSITION.componentType<>GLTF_FLOAT Or prim.POSITION.type<>"VEC3"
  186. Print "Gltf nesh has invalid POSITION data type"
  187. Return Null
  188. Endif
  189. If Not prim.indices Or (prim.indices.componentType<>GLTF_UNSIGNED_BYTE And prim.indices.componentType<>GLTF_UNSIGNED_SHORT And prim.indices.componentType<>GLTF_UNSIGNED_INT) Or prim.indices.type<>"SCALAR"
  190. Print "Gltf mesh has invalid index data"
  191. Return Null
  192. Endif
  193. Local vcount:=prim.POSITION.count
  194. Local vertices:=New Vertex3f[vcount]
  195. Local datap:=GetData( prim.POSITION )
  196. Local stride:=prim.POSITION.bufferView.byteStride ?Else 12
  197. For Local i:=0 Until vcount
  198. vertices[i].position=Cast<Vec3f Ptr>( datap )[0]
  199. vertices[i].position.z=-vertices[i].position.z
  200. datap+=stride
  201. Next
  202. If prim.NORMAL
  203. If prim.NORMAL.componentType=GLTF_FLOAT And prim.NORMAL.type="VEC3"
  204. ' Print "Gltf2 primitive has normals"
  205. Local datap:=GetData( prim.NORMAL )
  206. Local stride:=prim.NORMAL.bufferView.byteStride ?Else 12
  207. For Local i:=0 Until vcount
  208. vertices[i].normal=Cast<Vec3f Ptr>( datap )[0]
  209. vertices[i].normal.z=-vertices[i].normal.z
  210. datap+=stride
  211. Next
  212. Else
  213. Print "Unsupported gltf2 primitive NORMAL format"
  214. Endif
  215. Endif
  216. If prim.COLOR_0
  217. If prim.COLOR_0.componentType=GLTF_FLOAT And prim.COLOR_0.type="VEC4"
  218. ' Print "Gltf2 primitive has colors"
  219. Local datap:=GetData( prim.COLOR_0 )
  220. Local stride:=prim.COLOR_0.bufferView.byteStride ?Else 16
  221. For Local i:=0 Until vcount
  222. Local color:=Cast<Vec4f Ptr>( datap )[0]
  223. color.w=1
  224. Local a:=color.w * 255.0
  225. vertices[i].color=UInt(a) Shl 24 | UInt(color.z*a) Shl 16 | UInt(color.y*a) Shl 8 | UInt(color.x*a)
  226. datap+=stride
  227. Next
  228. Else
  229. Print "Unsupported gltf2 primitive COLOR_0 format"
  230. Endif
  231. Endif
  232. If prim.TEXCOORD_0
  233. If prim.TEXCOORD_0.componentType=GLTF_FLOAT And prim.TEXCOORD_0.type="VEC2"
  234. ' Print "Gltf2 primitive has texcoords0"
  235. Local datap:=GetData( prim.TEXCOORD_0 )
  236. Local stride:=prim.TEXCOORD_0.bufferView.byteStride ?Else 8
  237. For Local i:=0 Until vcount
  238. vertices[i].texCoord0=Cast<Vec2f Ptr>( datap )[0]
  239. datap+=stride
  240. Next
  241. Else
  242. Print "Unsupported gltf2 primitive TEXCOORD_0 format"
  243. Endif
  244. Endif
  245. If prim.TEXCOORD_1
  246. If prim.TEXCOORD_1.componentType=GLTF_FLOAT And prim.TEXCOORD_1.type="VEC2"
  247. ' Print "Gltf2 primitive has texcoords1"
  248. Local datap:=GetData( prim.TEXCOORD_1 )
  249. Local stride:=prim.TEXCOORD_1.bufferView.byteStride ?Else 8
  250. For Local i:=0 Until vcount
  251. vertices[i].texCoord1=Cast<Vec2f Ptr>( datap )[0]
  252. datap+=stride
  253. Next
  254. Else
  255. Print "Unsupported gltf2 primitive TEXCOORD_1 format"
  256. Endif
  257. Endif
  258. If prim.JOINTS_0
  259. Local datap:=GetData( prim.JOINTS_0 )
  260. If prim.JOINTS_0.componentType=GLTF_UNSIGNED_SHORT And prim.JOINTS_0.type="VEC4"
  261. ' Print "Primitive has ushort joints"
  262. Local stride:=prim.JOINTS_0.bufferView.byteStride ?Else 8
  263. For Local i:=0 Until vcount
  264. Local cptr:=Cast<UShort Ptr>( datap )
  265. vertices[i].bones=cptr[3] Shl 24 | cptr[2] Shl 16 | cptr[1] Shl 8 | cptr[0]
  266. datap+=stride
  267. Next
  268. Else If prim.JOINTS_0.componentType=GLTF_UNSIGNED_BYTE And prim.JOINTS_0.type="VEC4"
  269. ' Print "Primitive has ubyte joints"
  270. Local stride:=prim.JOINTS_0.bufferView.byteStride ?Else 4
  271. For Local i:=0 Until vcount
  272. Local cptr:=Cast<UByte Ptr>( datap )
  273. vertices[i].bones=cptr[3] Shl 24 | cptr[2] Shl 16 | cptr[1] Shl 8 | cptr[0]
  274. datap+=stride
  275. Next
  276. Else
  277. Print "Unsupported gltf2 primitive JOINTS_0 format"
  278. Endif
  279. Endif
  280. If prim.WEIGHTS_0
  281. Local datap:=GetData( prim.WEIGHTS_0 )
  282. If prim.WEIGHTS_0.componentType=GLTF_FLOAT And prim.WEIGHTS_0.type="VEC4"
  283. ' Print "Primitive has float weights"
  284. Local stride:=prim.WEIGHTS_0.bufferView.byteStride ?Else 16
  285. For Local i:=0 Until vcount
  286. vertices[i].weights=Cast<Vec4f Ptr>( datap )[0]
  287. datap+=stride
  288. Next
  289. Else
  290. Print "Unsupported gltf2 primitive WEIGHTS_0 format"
  291. Endif
  292. Endif
  293. Local icount:=prim.indices.count
  294. Local indices:=New IndexType[icount]
  295. datap=GetData( prim.indices )
  296. stride=prim.indices.bufferView.byteStride
  297. If prim.indices.componentType=GLTF_UNSIGNED_BYTE
  298. stride=stride ?Else 1
  299. For Local i:=0 Until icount Step 3
  300. indices[i+0]=Cast<UByte Ptr>( datap )[0]
  301. indices[i+2]=Cast<UByte Ptr>( datap )[1]
  302. indices[i+1]=Cast<UByte Ptr>( datap )[2]
  303. datap+=stride*3
  304. Next
  305. Else If prim.indices.componentType=GLTF_UNSIGNED_SHORT
  306. stride=stride ?Else 2
  307. For Local i:=0 Until icount Step 3
  308. indices[i+0]=Cast<UShort Ptr>( datap )[0]
  309. indices[i+2]=Cast<UShort Ptr>( datap )[1]
  310. indices[i+1]=Cast<UShort Ptr>( datap )[2]
  311. datap+=stride*3
  312. Next
  313. Else
  314. stride=stride ?Else 4
  315. For Local i:=0 Until icount Step 3
  316. indices[i+0]=Cast<UInt Ptr>( datap )[0]
  317. indices[i+2]=Cast<UInt Ptr>( datap )[1]
  318. indices[i+1]=Cast<UInt Ptr>( datap )[2]
  319. datap+=stride*3
  320. Next
  321. Endif
  322. Local mesh:=New Mesh( vertices,indices )
  323. If Not prim.NORMAL mesh.UpdateNormals()
  324. If prim.TEXCOORD_0 mesh.UpdateTangents()
  325. ' If prim.TEXCOORD_0 And prim.NORMAL mesh.UpdateTangents()
  326. Return mesh
  327. End
  328. Method LoadMesh( node:Gltf2Node,mesh:Mesh,materials:Stack<Material> )
  329. If node.mesh
  330. Local matrix:=New AffineMat4f( GetWorldMatrix( node ) )
  331. For Local prim:=Eachin node.mesh.primitives
  332. Local pmesh:=LoadPrimitive( prim )
  333. If Not pmesh Continue
  334. pmesh.TransformVertices( matrix )
  335. If materials
  336. Local textured:=prim.TEXCOORD_0<>Null
  337. materials.Add( GetMaterial( prim.material,textured,False ) )
  338. mesh.AddMesh( pmesh,mesh.NumMaterials )
  339. Else
  340. mesh.AddMesh( pmesh )
  341. Endif
  342. Next
  343. Endif
  344. For Local child:=Eachin node.children
  345. LoadMesh( child,mesh,materials )
  346. Next
  347. End
  348. Method LoadBonedModel:Model( node:Gltf2Node,parent:Model )
  349. Local model:=New Model( parent )
  350. model.Name=node.name
  351. model.LocalMatrix=New AffineMat4f( GetLocalMatrix( node ) )
  352. Local id:=_entities.Length
  353. _entities.Add( model )
  354. _entityIds[model]=id
  355. _nodeIds[node]=id
  356. For Local child:=Eachin node.children
  357. LoadBonedModel( child,model )
  358. Next
  359. Return model
  360. End
  361. Method LoadBonedMesh( node:Gltf2Node )
  362. If node.mesh
  363. Local mesh:=New Mesh
  364. Local materials:=New Stack<Material>
  365. For Local prim:=Eachin node.mesh.primitives
  366. Local pmesh:=LoadPrimitive( prim )
  367. If Not pmesh Continue
  368. mesh.AddMesh( pmesh,mesh.NumMaterials )
  369. Local boned:=prim.JOINTS_0<>Null
  370. Local textured:=prim.TEXCOORD_0<>Null
  371. materials.Add( GetMaterial( prim.material,textured,boned ) )
  372. Next
  373. Local model:=Cast<Model>( _entities[_nodeIds[node]] )
  374. model.Mesh=mesh
  375. model.Materials=materials.ToArray()
  376. If node.mesh.primitives[0].JOINTS_0<>Null
  377. model.Bones=_bones
  378. Endif
  379. Endif
  380. For Local child:=Eachin node.children
  381. LoadBonedMesh( child )
  382. Next
  383. End
  384. Method LoadAnimation:Animation( ganimation:Gltf2Animation )
  385. Local gchannels:=ganimation.channels
  386. Local posKeys:=New Stack<PositionKey>[_entities.Length]
  387. Local rotKeys:=New Stack<RotationKey>[_entities.Length]
  388. Local sclKeys:=New Stack<ScaleKey>[_entities.Length]
  389. Local minTime:=10000.0,maxTime:=0.0
  390. For Local i:=0 Until gchannels.Length
  391. Local gchannel:=gchannels[i]
  392. If Not _nodeIds.Contains( gchannel.targetNode )
  393. Print "Gltf2Loader: gchannel.targetNode not found"
  394. Continue
  395. Endif
  396. Local entityId:=_nodeIds[gchannel.targetNode]
  397. Local sampler:=gchannel.sampler
  398. Local n:=sampler.input.count
  399. If Not n Continue
  400. If n<>sampler.output.count
  401. Print "Gltf2Loader: sampler.input.count<>sampler.output.count"
  402. continue
  403. End
  404. Local timep:=GetData( sampler.input )
  405. Local timeStride:=sampler.input.bufferView.byteStride ?Else 4
  406. minTime=Min( minTime,Cast<Float Ptr>(timep)[0] )
  407. maxTime=Max( maxTime,Cast<Float Ptr>(timep+(n-1)*timeStride)[0] )
  408. Select gchannel.targetPath
  409. Case "translation"
  410. Local keys:=New Stack<PositionKey>
  411. If posKeys[ entityId ] Print "OOPS!"
  412. posKeys[entityId]=keys
  413. Local datap:=GetData( sampler.output )
  414. Local dataStride:=sampler.output.bufferView.byteStride ?Else 12
  415. For Local i:=0 Until n
  416. Local v:=Cast<Vec3f Ptr>( datap )[0]
  417. v.z=-v.z
  418. keys.Add( New PositionKey( Cast<Float Ptr>( timep )[0],v ) )
  419. timep+=timeStride
  420. datap+=dataStride
  421. Next
  422. Case "rotation"
  423. Local keys:=New Stack<RotationKey>
  424. If rotKeys[entityId] Print "OOPS!"
  425. rotKeys[entityId]=keys
  426. Local datap:=GetData( sampler.output )
  427. Local dataStride:=sampler.output.bufferView.byteStride ?Else 16
  428. For Local i:=0 Until n
  429. Local q:=Cast<Quatf Ptr>( datap )[0]
  430. q.v.x=-q.v.x
  431. q.v.y=-q.v.y
  432. q.w=-q.w
  433. keys.Add( New RotationKey( Cast<Float Ptr>( timep )[0],q ) )
  434. timep+=timeStride
  435. datap+=dataStride
  436. Next
  437. Case "scale"
  438. Local keys:=New Stack<ScaleKey>
  439. If sclKeys[entityId] Print "OOPS!"
  440. sclKeys[entityId]=keys
  441. Local datap:=GetData( sampler.output )
  442. Local dataStride:=sampler.output.bufferView.byteStride ?Else 12
  443. For Local i:=0 Until n
  444. Local v:=Cast<Vec3f Ptr>( datap )[0]
  445. keys.Add( New ScaleKey( Cast<Float Ptr>( timep )[0],v ) )
  446. timep+=timeStride
  447. datap+=dataStride
  448. Next
  449. Default
  450. Print "targetPath="+gchannel.targetPath+"?????"
  451. End
  452. Next
  453. Local duration:=maxTime-minTime
  454. ' Print "animation:"+ganimation.name+" duration:"+duration
  455. Local channels:=New AnimationChannel[_entities.Length]
  456. For Local i:=0 Until channels.Length
  457. Local pkeys:=posKeys[i]?.ToArray()
  458. Local rkeys:=rotKeys[i]?.ToArray()
  459. Local skeys:=sclKeys[i]?.ToArray()
  460. For Local key:=Eachin pkeys
  461. key.Time-=minTime
  462. End
  463. For Local key:=Eachin rkeys
  464. key.Time-=minTime
  465. End
  466. For Local key:=Eachin skeys
  467. key.Time-=minTime
  468. End
  469. ' If Not pkeys And Not rkeys And Not skeys
  470. ' Print "Yo1"
  471. ' Else If Not pkeys Or Not rkeys Or Not skeys
  472. ' Print "Yo2"
  473. ' Endif
  474. ' Print "channel:"+_entities[i].Name+" keys:"+pkeys.Length
  475. channels[i]=New AnimationChannel( pkeys,rkeys,skeys )
  476. Next
  477. Local animation:=New Animation( ganimation.name,channels,duration,1,AnimationMode.Looping )
  478. Return animation
  479. End
  480. Method LoadAnimator:Animator( model:Model )
  481. If Not _asset.animations Return Null
  482. Local animations:=New Animation[_asset.animations.Length]
  483. For Local i:=0 Until animations.Length
  484. animations[i]=LoadAnimation( _asset.animations[i] )
  485. Next
  486. Local animator:=New Animator( model )
  487. animator.Animations.AddAll( animations )
  488. animator.Skeleton=_entities.ToArray()
  489. Return animator
  490. End
  491. Method LoadBones()
  492. If Not _asset.skins Return
  493. Local skin:=_asset.skins[0]
  494. Local n:=skin.joints.Length
  495. Local datap:UByte Ptr,stride:Int
  496. If skin.inverseBindMatrices
  497. If skin.inverseBindMatrices.count<>n
  498. Print "Invalid skin"
  499. Return
  500. Endif
  501. datap=GetData( skin.inverseBindMatrices )
  502. stride=skin.inverseBindMatrices.bufferView.byteStride ?Else 64
  503. Endif
  504. _bones=New Model.Bone[n]
  505. ' Print "Loading "+n+" bones"
  506. For Local i:=0 Until n
  507. Local matrix:=datap ? New AffineMat4f( FlipMatrix( Cast<Mat4f Ptr>( datap )[0] ) ) Else New AffineMat4f
  508. _bones[i].entity=_entities[ _nodeIds[skin.joints[i]] ]
  509. _bones[i].offset=matrix
  510. If datap datap+=stride
  511. Next
  512. End
  513. End
  514. Public
  515. #rem monkeydoc @hidden
  516. #End
  517. Class Gltf2Mojo3dLoader Extends Mojo3dLoader
  518. Const Instance:=New Gltf2Mojo3dLoader
  519. Method LoadMesh:Mesh( path:String ) Override
  520. Local loader:=Open( path )
  521. If Not loader Return Null
  522. Local mesh:=loader.LoadMesh()
  523. Return mesh
  524. End
  525. Method LoadModel:Model( path:String ) Override
  526. Local loader:=Open( path )
  527. If Not loader Return Null
  528. Local model:=loader.LoadModel()
  529. Return model
  530. End
  531. Method LoadBonedModel:Model( path:String ) Override
  532. Local loader:=Open( path )
  533. If Not loader Return Null
  534. Local model:=loader.LoadBonedModel()
  535. Return model
  536. End
  537. Private
  538. Method Open:Gltf2Loader( path:String )
  539. path=RealPath( path )
  540. Local asset:Gltf2Asset,bindata:DataBuffer
  541. Select ExtractExt( path ).ToLower()
  542. Case ".glb"
  543. Local stream:=Stream.Open( path,"r" )
  544. If Not stream Return Null
  545. Local json:=""
  546. If stream.ReadUInt()=$46546C67 '"GLTF"
  547. Local version:=stream.ReadUInt()
  548. Local length:=stream.ReadUInt()
  549. If length>12
  550. length-=12
  551. While length>=8 And Not stream.Eof
  552. Local clength:=stream.ReadUInt()
  553. If clength>(length-8) Exit 'FAIL!
  554. Local ctype:=stream.ReadUInt()
  555. Select ctype
  556. Case $4E4F534A '"JSON"
  557. Local buf:=stream.ReadAll( clength )
  558. If buf.Length<>clength Exit 'FAIL!
  559. json=buf.PeekString( 0 )
  560. buf.Discard()
  561. Case $004E4942 '"BIN"
  562. bindata=stream.ReadAll( clength )
  563. If bindata.Length<>clength Exit 'FAIL!
  564. Default '?????
  565. If stream.Skip( clength )<>clength Exit
  566. End
  567. length-=clength+8
  568. Wend
  569. If length json=""
  570. Endif
  571. Endif
  572. stream.Close()
  573. If Not json Return Null
  574. asset=Gltf2Asset.Parse( json )
  575. Case ".gltf"
  576. asset=Gltf2Asset.Load( path )
  577. End
  578. If Not asset Return Null
  579. Local loader:=New Gltf2Loader( asset,bindata,ExtractDir( path ) )
  580. Return loader
  581. End
  582. End