gltf2loader.monkey2 18 KB

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