gltf2loader.monkey2 18 KB

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