chorama 0.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (256) hide show
  1. package/.configs/tsconfig.lib.json +43 -0
  2. package/.configs/tsconfig.website.json +34 -0
  3. package/.github/workflows/static.yml +88 -0
  4. package/.vscode/launch.json +29 -0
  5. package/.vscode/tasks.json +19 -0
  6. package/README.md +127 -0
  7. package/assets/images/disappointed.jpg +0 -0
  8. package/assets/images/skybox/grimmnight_back.png +0 -0
  9. package/assets/images/skybox/grimmnight_bottom.png +0 -0
  10. package/assets/images/skybox/grimmnight_front.png +0 -0
  11. package/assets/images/skybox/grimmnight_left.png +0 -0
  12. package/assets/images/skybox/grimmnight_right.png +0 -0
  13. package/assets/images/skybox/grimmnight_top.png +0 -0
  14. package/assets/images/skybox/miramar_back.png +0 -0
  15. package/assets/images/skybox/miramar_bottom.png +0 -0
  16. package/assets/images/skybox/miramar_front.png +0 -0
  17. package/assets/images/skybox/miramar_left.png +0 -0
  18. package/assets/images/skybox/miramar_right.png +0 -0
  19. package/assets/images/skybox/miramar_top.png +0 -0
  20. package/assets/images/uv.jpg +0 -0
  21. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_GlassPlasticMat_BaseColor.png +0 -0
  22. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_GlassPlasticMat_Normal.png +0 -0
  23. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_GlassPlasticMat_OcclusionRoughMetal.png +0 -0
  24. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_LeatherPartsMat_BaseColor.png +0 -0
  25. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_LeatherPartsMat_Normal.png +0 -0
  26. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_LeatherPartsMat_OcclusionRoughMetal.png +0 -0
  27. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_LensesMat_BaseColor.png +0 -0
  28. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_LensesMat_Normal.png +0 -0
  29. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_LensesMat_OcclusionRoughMetal.png +0 -0
  30. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_MetalPartsMat_BaseColor.png +0 -0
  31. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_MetalPartsMat_Normal.png +0 -0
  32. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_MetalPartsMat_OcclusionRoughMetal.png +0 -0
  33. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_RubberWoodMat_BaseColor.png +0 -0
  34. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_RubberWoodMat_Normal.png +0 -0
  35. package/assets/models/gltf/flight_helmet/FlightHelmet_Materials_RubberWoodMat_OcclusionRoughMetal.png +0 -0
  36. package/assets/models/gltf/flight_helmet/index.bin +0 -0
  37. package/assets/models/gltf/flight_helmet/index.gltf +705 -0
  38. package/assets/models/gltf/object.gltf +23 -0
  39. package/assets/models/gltf/pirate_girl/index.bin +0 -0
  40. package/assets/models/gltf/pirate_girl/index.gltf +2082 -0
  41. package/assets/models/obj/pirate_girl/pirate_girl.obj +18459 -0
  42. package/assets/models/obj/pirate_girl/pirate_girl.png +0 -0
  43. package/astro.config.mjs +45 -0
  44. package/content/guide/api-map.md +89 -0
  45. package/content/guide/camera-and-controls.md +98 -0
  46. package/content/guide/first-scene.md +176 -0
  47. package/content/guide/index.md +72 -0
  48. package/content/guide/installation.md +179 -0
  49. package/content/guide/materials-and-lighting.md +138 -0
  50. package/content/guide/plugins-and-render-pipeline.md +124 -0
  51. package/content/guide/render-targets-and-views.md +147 -0
  52. package/content/guide/scene-graph-and-transforms.md +113 -0
  53. package/content/guide/textures-and-assets.md +120 -0
  54. package/content/guide/troubleshooting.md +49 -0
  55. package/env.d.ts +19 -0
  56. package/examples/addons/rendergraph_gui.js +580 -0
  57. package/examples/camera/orthographic.js +120 -0
  58. package/examples/camera/perspective.js +138 -0
  59. package/examples/lights/directional.js +397 -0
  60. package/examples/lights/multiple_spot_lights.js +304 -0
  61. package/examples/lights/point.js +337 -0
  62. package/examples/lights/spot.js +366 -0
  63. package/examples/loader/gltf_material.js +111 -0
  64. package/examples/loader/gltfloader.js +78 -0
  65. package/examples/loader/objloader.js +95 -0
  66. package/examples/material/cullface.js +111 -0
  67. package/examples/material/materials.js +126 -0
  68. package/examples/material/standard/basic.js +164 -0
  69. package/examples/mesh/circle.js +117 -0
  70. package/examples/mesh/cuboid.js +151 -0
  71. package/examples/mesh/cylinder.js +139 -0
  72. package/examples/mesh/geometries.js +108 -0
  73. package/examples/mesh/meshTopology.js +103 -0
  74. package/examples/mesh/plane.js +117 -0
  75. package/examples/mesh/skinning.js +136 -0
  76. package/examples/mesh/uvsphere.js +113 -0
  77. package/examples/other/rotatingCube.js +93 -0
  78. package/examples/other/rotatingSphere.js +96 -0
  79. package/examples/rendertarget/basic_canvas.js +130 -0
  80. package/examples/rendertarget/depth_texture.js +130 -0
  81. package/examples/rendertarget/image_target.js +140 -0
  82. package/examples/rendertarget/multiple_views.js +158 -0
  83. package/examples/rendertarget/render_masks.js +173 -0
  84. package/examples/rendertarget/split_screen.js +123 -0
  85. package/examples/rendertarget/split_view.js +137 -0
  86. package/examples/skybox/skybox.js +111 -0
  87. package/examples/texture/arrays.js +156 -0
  88. package/examples/texture/textureWrap.js +118 -0
  89. package/examples/transform/propagation.js +92 -0
  90. package/package.json +55 -0
  91. package/rollup.config.js +66 -0
  92. package/scripts/stage-chorama.mjs +29 -0
  93. package/src/caches/cache.js +420 -0
  94. package/src/caches/index.js +2 -0
  95. package/src/caches/uniformbuffers.js +104 -0
  96. package/src/cameracontrols/index.js +258 -0
  97. package/src/constants/index.js +3 -0
  98. package/src/constants/mesh.js +197 -0
  99. package/src/constants/others.js +218 -0
  100. package/src/constants/texture.js +183 -0
  101. package/src/core/constants.js +14 -0
  102. package/src/core/extensions.js +42 -0
  103. package/src/core/index.js +7 -0
  104. package/src/core/layouts/index.js +4 -0
  105. package/src/core/layouts/meshvertex.js +60 -0
  106. package/src/core/layouts/uniform.js +21 -0
  107. package/src/core/layouts/uniformbuffer.js +15 -0
  108. package/src/core/layouts/vertexbuffer.js +43 -0
  109. package/src/core/limits.js +247 -0
  110. package/src/core/resources/blendparams.js +89 -0
  111. package/src/core/resources/framebuffer.js +127 -0
  112. package/src/core/resources/gpubuffer.js +32 -0
  113. package/src/core/resources/gpumesh.js +43 -0
  114. package/src/core/resources/gputexture.js +73 -0
  115. package/src/core/resources/index.js +5 -0
  116. package/src/core/shader.js +62 -0
  117. package/src/core/webgl/bindgroup.js +89 -0
  118. package/src/core/webgl/descriptors.js +104 -0
  119. package/src/core/webgl/index.js +5 -0
  120. package/src/core/webgl/renderpassencoder.js +96 -0
  121. package/src/core/webgl/renderpipeline.js +54 -0
  122. package/src/core/webgl/utils.js +371 -0
  123. package/src/core/webgl/webglrenderdevice.js +235 -0
  124. package/src/function.js +358 -0
  125. package/src/index.js +15 -0
  126. package/src/loader/gltf.js +2172 -0
  127. package/src/loader/index.js +3 -0
  128. package/src/loader/loader.js +174 -0
  129. package/src/loader/obj.js +188 -0
  130. package/src/loader/texture.js +85 -0
  131. package/src/loader/utils.js +16 -0
  132. package/src/material/basic.js +75 -0
  133. package/src/material/depth.js +73 -0
  134. package/src/material/index.js +8 -0
  135. package/src/material/lambert.js +73 -0
  136. package/src/material/material.js +106 -0
  137. package/src/material/normal.js +30 -0
  138. package/src/material/phong.js +86 -0
  139. package/src/material/raw.js +52 -0
  140. package/src/material/standard.js +221 -0
  141. package/src/math/index.js +3 -0
  142. package/src/math/transform.js +38 -0
  143. package/src/mesh/attribute/attribute.js +79 -0
  144. package/src/mesh/attribute/index.js +1 -0
  145. package/src/mesh/attributedata/index.js +1 -0
  146. package/src/mesh/attributedata/separate.js +180 -0
  147. package/src/mesh/builders/base.js +41 -0
  148. package/src/mesh/builders/circle.js +63 -0
  149. package/src/mesh/builders/cuboid.js +135 -0
  150. package/src/mesh/builders/cylinder.js +131 -0
  151. package/src/mesh/builders/index.js +7 -0
  152. package/src/mesh/builders/plane.js +73 -0
  153. package/src/mesh/builders/utils.js +20 -0
  154. package/src/mesh/builders/uvsphere.js +80 -0
  155. package/src/mesh/builders/wireframe.js +62 -0
  156. package/src/mesh/index.js +4 -0
  157. package/src/mesh/mesh.js +149 -0
  158. package/src/objects/bone.js +17 -0
  159. package/src/objects/camera/camera.js +56 -0
  160. package/src/objects/camera/index.js +2 -0
  161. package/src/objects/camera/projection.js +203 -0
  162. package/src/objects/debug/index.js +1 -0
  163. package/src/objects/debug/skeleton.js +28 -0
  164. package/src/objects/index.js +7 -0
  165. package/src/objects/light/ambient.js +20 -0
  166. package/src/objects/light/directional.js +29 -0
  167. package/src/objects/light/index.js +5 -0
  168. package/src/objects/light/point.js +32 -0
  169. package/src/objects/light/shadow/index.js +1 -0
  170. package/src/objects/light/shadow/shadow.js +67 -0
  171. package/src/objects/light/spot.js +56 -0
  172. package/src/objects/mesh.js +141 -0
  173. package/src/objects/object3d.js +167 -0
  174. package/src/objects/skybox.js +38 -0
  175. package/src/plugins/camera/camera.js +19 -0
  176. package/src/plugins/camera/index.js +2 -0
  177. package/src/plugins/camera/nodes/cameraview.js +46 -0
  178. package/src/plugins/camera/nodes/index.js +2 -0
  179. package/src/plugins/camera/nodes/opaquepass.js +79 -0
  180. package/src/plugins/index.js +6 -0
  181. package/src/plugins/light/index.js +2 -0
  182. package/src/plugins/light/light.js +23 -0
  183. package/src/plugins/light/nodes/index.js +1 -0
  184. package/src/plugins/light/nodes/light.js +127 -0
  185. package/src/plugins/meshmaterial/index.js +3 -0
  186. package/src/plugins/meshmaterial/meshmaterial.js +381 -0
  187. package/src/plugins/meshmaterial/nodes/index.js +1 -0
  188. package/src/plugins/meshmaterial/nodes/meshmaterial.js +50 -0
  189. package/src/plugins/meshmaterial/resources/index.js +1 -0
  190. package/src/plugins/meshmaterial/resources/meshmaterialpipelines.js +50 -0
  191. package/src/plugins/shadow/index.js +3 -0
  192. package/src/plugins/shadow/nodes/index.js +3 -0
  193. package/src/plugins/shadow/nodes/shadow.js +272 -0
  194. package/src/plugins/shadow/nodes/shadowOccluder.js +112 -0
  195. package/src/plugins/shadow/nodes/shadowOpaquePass.js +73 -0
  196. package/src/plugins/shadow/resources/ShadowMap.js +99 -0
  197. package/src/plugins/shadow/resources/index.js +2 -0
  198. package/src/plugins/shadow/resources/shadowpipelines.js +25 -0
  199. package/src/plugins/shadow/shadow.js +31 -0
  200. package/src/plugins/skeletonhelper/index.js +1 -0
  201. package/src/plugins/skeletonhelper/skeletonhelper.js +160 -0
  202. package/src/plugins/skybox/index.js +3 -0
  203. package/src/plugins/skybox/nodes/index.js +1 -0
  204. package/src/plugins/skybox/nodes/skybox.js +143 -0
  205. package/src/plugins/skybox/resources/index.js +2 -0
  206. package/src/plugins/skybox/resources/skyboxmesh.js +14 -0
  207. package/src/plugins/skybox/resources/skyboxpipeline.js +6 -0
  208. package/src/plugins/skybox/skybox.js +137 -0
  209. package/src/renderer/core/index.js +179 -0
  210. package/src/renderer/graph/index.js +3 -0
  211. package/src/renderer/graph/nodes.js +34 -0
  212. package/src/renderer/graph/rendergraph.js +182 -0
  213. package/src/renderer/index.js +5 -0
  214. package/src/renderer/plugin.js +36 -0
  215. package/src/renderer/renderer.js +179 -0
  216. package/src/renderer/views.js +28 -0
  217. package/src/rendertarget/canvastarget.js +30 -0
  218. package/src/rendertarget/image.js +132 -0
  219. package/src/rendertarget/index.js +3 -0
  220. package/src/rendertarget/rendertarget.js +89 -0
  221. package/src/shader/basicFragment.glsl +30 -0
  222. package/src/shader/basicVertex.glsl +87 -0
  223. package/src/shader/common/color.glsl +7 -0
  224. package/src/shader/common/common.glsl +25 -0
  225. package/src/shader/common/index.js +4 -0
  226. package/src/shader/common/light.glsl +437 -0
  227. package/src/shader/common/math.glsl +12 -0
  228. package/src/shader/debug/index.js +2 -0
  229. package/src/shader/debug/skeletonFragment.glsl +8 -0
  230. package/src/shader/debug/skeletonVertex.glsl +27 -0
  231. package/src/shader/depthFragment.glsl +37 -0
  232. package/src/shader/index.js +11 -0
  233. package/src/shader/lambertFragment.glsl +126 -0
  234. package/src/shader/normalFragment.glsl +25 -0
  235. package/src/shader/phongFragment.glsl +140 -0
  236. package/src/shader/skyboxFragment.glsl +16 -0
  237. package/src/shader/skyboxVertex.glsl +20 -0
  238. package/src/shader/standardFragment.glsl +274 -0
  239. package/src/texture/index.js +2 -0
  240. package/src/texture/sampler.js +111 -0
  241. package/src/texture/texture.js +234 -0
  242. package/src/utils/index.js +115 -0
  243. package/tsconfig.json +11 -0
  244. package/website/config/index.ts +1 -0
  245. package/website/config/navigation.ts +53 -0
  246. package/website/content.config.ts +92 -0
  247. package/website/layouts/DocLayout.astro +501 -0
  248. package/website/layouts/Example.astro +91 -0
  249. package/website/pages/examples/[...slug].astro +77 -0
  250. package/website/pages/examples/index.astro +98 -0
  251. package/website/pages/examples/samples/[...slug].astro +17 -0
  252. package/website/pages/guide/[slug].astro +30 -0
  253. package/website/pages/guide/index.astro +21 -0
  254. package/website/pages/index.astro +9 -0
  255. package/website/plugins/remark-link-base.js +23 -0
  256. package/website/utils/url.ts +30 -0
@@ -0,0 +1,2172 @@
1
+ /**@import { LoadSettings } from './loader.js' */
2
+ import { Attribute, Mesh } from '../mesh/index.js';
3
+ import { StandardMaterial } from '../material/index.js';
4
+ import { MeshMaterial3D, Object3D, Skin } from '../objects/index.js';
5
+ import { Loader } from './loader.js';
6
+ import { arrayBufferToJSON } from './utils.js';
7
+ import { Bone3D } from '../objects/bone.js';
8
+ import { Affine3 } from '../math/index.js';
9
+ import { SeparateAttributeData } from '../mesh/attributedata/separate.js';
10
+ import { TextureLoader } from './texture.js';
11
+ import { Texture, Sampler } from '../texture/index.js';
12
+ import { assert } from '../utils/index.js';
13
+ import { GlDataType, TextureFilter, TextureWrap, VertexFormat } from '../constants/index.js';
14
+
15
+ const defaultMaterial = new StandardMaterial()
16
+ /**
17
+ * @extends {Loader<Object3D, GLTFLoadSettings>}
18
+ */
19
+ export class GLTFLoader extends Loader {
20
+ textureLoader
21
+ constructor({ textureLoader = new TextureLoader() } = {}) {
22
+ super(Object3D)
23
+ this.textureLoader = textureLoader
24
+ }
25
+ /**
26
+ * @override
27
+ * @param {ArrayBuffer[]} buffers
28
+ * @param {Object3D} destination
29
+ * @param {GLTFLoadSettings} settings
30
+ */
31
+ async parse(buffers, destination, settings) {
32
+ const buffer = buffers[0]
33
+ const path = settings.paths[0]
34
+ if (!buffer || !path) {
35
+ return
36
+ }
37
+
38
+ /**@type {Map<number, Object3D>} */
39
+ const entityMap = new Map()
40
+ const baseUrl = new URL(path, location.href).href
41
+ const gltf = await loadGLTF(buffer, baseUrl)
42
+ const scene = gltf.scenes[gltf.scene]
43
+
44
+ if (!scene) {
45
+ throw "No root scene defined"
46
+ }
47
+
48
+ const images = await Promise.all(gltf.images.map(async (gltfTexture) => {
49
+ if (gltfTexture.uri) {
50
+ return this.textureLoader.asyncLoad({
51
+ paths: [new URL(gltfTexture.uri, baseUrl).href]
52
+ })
53
+ }
54
+
55
+ throw "Unsupported gltf image setting"
56
+ }))
57
+ const samplers = gltf.samplers.map((gltfSampler) => {
58
+ const sampler = new Sampler()
59
+ sampler.magnificationFilter = gltfSampler.magFilter || TextureFilter.Nearest
60
+ sampler.wrapS = gltfSampler.wrapS || TextureWrap.Clamp
61
+ sampler.wrapT = gltfSampler.wrapT || TextureWrap.Clamp
62
+
63
+ switch (gltfSampler.minFilter) {
64
+ case WebGL2RenderingContext.NEAREST:
65
+ sampler.minificationFilter = TextureFilter.Nearest
66
+ sampler.mipmapFilter = undefined
67
+ break;
68
+ case WebGL2RenderingContext.LINEAR:
69
+ sampler.minificationFilter = TextureFilter.Linear
70
+ sampler.mipmapFilter = undefined
71
+ break;
72
+ case WebGL2RenderingContext.NEAREST_MIPMAP_NEAREST:
73
+ sampler.minificationFilter = TextureFilter.Nearest
74
+ sampler.mipmapFilter = TextureFilter.Nearest
75
+ break;
76
+ case WebGL2RenderingContext.NEAREST_MIPMAP_LINEAR:
77
+ sampler.minificationFilter = TextureFilter.Nearest
78
+ sampler.mipmapFilter = TextureFilter.Linear
79
+ break;
80
+ case WebGL2RenderingContext.LINEAR_MIPMAP_NEAREST:
81
+ sampler.minificationFilter = TextureFilter.Linear
82
+ sampler.mipmapFilter = TextureFilter.Nearest
83
+ break;
84
+ case WebGL2RenderingContext.LINEAR_MIPMAP_LINEAR:
85
+ sampler.minificationFilter = TextureFilter.Linear
86
+ sampler.mipmapFilter = TextureFilter.Linear
87
+ break;
88
+ default:
89
+ throw 'GLTF: Invalid minification sampler';
90
+ }
91
+ return sampler
92
+ })
93
+
94
+ /**
95
+ * @type {[Texture, Sampler | undefined][]}
96
+ */
97
+ const textures = gltf.textures.map((gltfTextures) => {
98
+ const image = images[gltfTextures.source]
99
+ assert(image, "GLTF texture does not have an image source")
100
+
101
+ if (gltfTextures.sampler !== undefined) {
102
+ const sampler = samplers[gltfTextures.sampler]
103
+ if (sampler?.mipmapFilter !== undefined) {
104
+ image.generateMipmaps = true
105
+ }
106
+ return [image, sampler]
107
+ }
108
+ return [image, undefined]
109
+ })
110
+ const materials = gltf.materials.map((gltfMaterial) => {
111
+ const {
112
+ emissiveFactor,
113
+ emissiveTexture,
114
+ normalTexture,
115
+ occlusionTexture,
116
+ pbrMetallicRoughness
117
+ } = gltfMaterial
118
+ const {
119
+ baseColorFactor,
120
+ baseColorTexture,
121
+ metallicFactor,
122
+ roughnessFactor,
123
+ metallicRoughnessTexture
124
+ } = pbrMetallicRoughness
125
+ const material = new StandardMaterial()
126
+
127
+ material.color.set(
128
+ baseColorFactor[0],
129
+ baseColorFactor[1],
130
+ baseColorFactor[2],
131
+ baseColorFactor[3]
132
+ )
133
+ material.emissiveColor.set(
134
+ emissiveFactor[0],
135
+ emissiveFactor[1],
136
+ emissiveFactor[2]
137
+ )
138
+ material.metallic = metallicFactor
139
+ material.roughness = roughnessFactor
140
+
141
+ if (baseColorTexture) {
142
+ const texture = textures[baseColorTexture.index]
143
+
144
+ if (texture) {
145
+ material.mainTexture = texture[0]
146
+ material.mainSampler = texture[1]
147
+ } else {
148
+ console.warn("gltf: invalid color texture on material");
149
+ }
150
+ }
151
+
152
+ if (normalTexture) {
153
+ const texture = textures[normalTexture.index]
154
+
155
+ if (texture) {
156
+ material.normalTexture = texture[0]
157
+ material.normalSampler = texture[1]
158
+ } else {
159
+ console.warn("gltf: invalid normal texture on material");
160
+ }
161
+ }
162
+
163
+ if (occlusionTexture) {
164
+ const texture = textures[occlusionTexture.index]
165
+
166
+ if (texture) {
167
+ material.occlusionStrength = occlusionTexture.strength
168
+ material.occlusionTexture = texture[0]
169
+ material.occlusionSampler = texture[1]
170
+ } else {
171
+ console.warn("gltf: invalid occlusion texture on material");
172
+ }
173
+ }
174
+
175
+ if (emissiveTexture) {
176
+ const texture = textures[emissiveTexture.index]
177
+
178
+ if (texture) {
179
+ material.emissiveTexture = texture[0]
180
+ material.emissiveSampler = texture[1]
181
+ } else {
182
+ console.warn("gltf: invalid emissive texture on material");
183
+ }
184
+ }
185
+
186
+ if (metallicRoughnessTexture) {
187
+ const texture = textures[metallicRoughnessTexture.index]
188
+
189
+ if (texture) {
190
+ material.metallicTexture = texture[0]
191
+ material.metallicSampler = texture[1]
192
+ material.roughnessTexture = texture[0]
193
+ material.roughnessSampler = texture[1]
194
+ } else {
195
+ console.warn("gltf: invalid metallic-rougness texture on material");
196
+ }
197
+ }
198
+
199
+ return material
200
+ })
201
+ const geometries = gltf.meshes.map((data) => {
202
+ return parseGeometry(data, gltf)
203
+ })
204
+
205
+ gltf.nodes.forEach((node, index) => {
206
+ const object = parseObject(index, node, gltf, geometries, materials)
207
+
208
+ if (object) {
209
+ entityMap.set(index, object)
210
+ }
211
+ })
212
+
213
+ gltf.nodes.forEach((node, index) => {
214
+ const parent = entityMap.get(index)
215
+
216
+ if (!parent) {
217
+ return
218
+ }
219
+
220
+ for (const child of node.children) {
221
+ const childEntity = entityMap.get(child)
222
+
223
+ if (childEntity) {
224
+ parent.add(childEntity)
225
+ }
226
+ }
227
+ })
228
+
229
+ scene.nodes.forEach((node) => {
230
+ entityMap.get(node)?.update()
231
+ });
232
+
233
+ const skins = gltf.skins.map((skin) => {
234
+ return parseSkin(skin, gltf, entityMap)
235
+ })
236
+
237
+ entityMap.forEach((entity, index) => {
238
+ const node = /**@type {GLTFNode} */ (gltf.nodes[index])
239
+ if (node.skin !== undefined) {
240
+ entity.traverseBFS((mesh) => {
241
+ if (mesh instanceof MeshMaterial3D) {
242
+ mesh.skin = skins[/**@type {number} */ (node.skin)]
243
+ }
244
+ return true
245
+ })
246
+ }
247
+ })
248
+
249
+ const sceneEntities = scene.nodes.map((node) => {
250
+ return /**@type {Object3D} */ (entityMap.get(node))
251
+ })
252
+
253
+ sceneEntities.forEach((object) => {
254
+ object.traverseDFS((innerObject) => {
255
+ innerObject.update()
256
+ return true
257
+ })
258
+ })
259
+
260
+
261
+ destination.add(...sceneEntities)
262
+ }
263
+
264
+ /**
265
+ * @override
266
+ */
267
+ default() {
268
+ return new Object3D()
269
+ }
270
+ }
271
+
272
+ /**
273
+ * @param {ArrayBuffer} data
274
+ * @param {string} baseUrl
275
+ */
276
+ async function loadGLTF(data, baseUrl) {
277
+ const json = arrayBufferToJSON(data)
278
+ const { buffers: urlBuffers } = json
279
+ const buffers = urlBuffers instanceof Array ? await loadBuffers(baseUrl, urlBuffers) : []
280
+ const gltf = GLTF.deserialize(json)
281
+ gltf.buffers = buffers
282
+
283
+ return gltf
284
+ }
285
+
286
+ /**
287
+ * @param {string} base
288
+ * @param {{uri: string;}[]} uris
289
+ */
290
+ async function loadBuffers(base, uris) {
291
+
292
+ return Promise.all(
293
+ uris.map(async (buffer) => {
294
+ const url = buffer.uri.startsWith('data') ?
295
+ buffer.uri :
296
+ new URL(buffer.uri, base).href
297
+ const response = await fetch(url);
298
+ if (!response.ok) throw new Error(`Failed to fetch buffer`);
299
+ return await response.arrayBuffer();
300
+ })
301
+ )
302
+ }
303
+ /**
304
+ * @typedef {LoadSettings} GLTFLoadSettings
305
+ */
306
+
307
+ class GLTF {
308
+ /**
309
+ * @type {number}
310
+ */
311
+ scene = 0
312
+ /**
313
+ * @type {GLTFScene[]}
314
+ */
315
+ scenes = []
316
+ /**
317
+ * @type {GLTFNode[]}
318
+ */
319
+ nodes = []
320
+ /**
321
+ * @type {GLTFImage[]}
322
+ */
323
+ images = []
324
+ /**
325
+ * @type {GLFTSampler[]}
326
+ */
327
+ samplers = []
328
+ /**
329
+ * @type {GLFTTexture[]}
330
+ */
331
+ textures = []
332
+ /**
333
+ * @type {GLTFMesh[]}
334
+ */
335
+ meshes = []
336
+ /**
337
+ * @type {GLTFMaterial[]}
338
+ */
339
+ materials = []
340
+ /**
341
+ * @type {GLTFSkin[]}
342
+ */
343
+ skins = []
344
+ /**
345
+ * @type {ArrayBuffer[]}
346
+ */
347
+ buffers = []
348
+ /**
349
+ * @type {GLTFBufferView[]}
350
+ */
351
+ bufferViews = []
352
+ /**
353
+ * @type {GLTFAccessor[]}
354
+ */
355
+ accessors = []
356
+ /**
357
+ * @type {GLTFMetaData}
358
+ */
359
+ metaData
360
+
361
+ /**
362
+ * @param {GLTFMetaData} meta
363
+ */
364
+ constructor(meta) {
365
+ this.metaData = meta
366
+ }
367
+ /**
368
+ * @param {any} data
369
+ */
370
+ static deserialize(data) {
371
+ const {
372
+ scene,
373
+ scenes,
374
+ nodes,
375
+ meshes,
376
+ images,
377
+ textures,
378
+ samplers,
379
+ materials,
380
+ bufferViews,
381
+ accessors,
382
+ asset,
383
+ skins
384
+ } = data
385
+
386
+ if (
387
+ !(asset instanceof Object) ||
388
+ !(scenes instanceof Array) ||
389
+ !(nodes instanceof Array) ||
390
+ !(meshes instanceof Array) ||
391
+ !(bufferViews instanceof Array) ||
392
+ !(accessors instanceof Array)
393
+ ) {
394
+ throw new Error("Invalid gltf json")
395
+ }
396
+ const gltf = new GLTF(GLTFMetaData.deserialize(asset))
397
+
398
+ if (typeof scene === "number") {
399
+ gltf.scene = scene
400
+ } else {
401
+ gltf.scene = 0
402
+ }
403
+
404
+ gltf.scenes = scenes.map((/**@type {any}*/d) => GLTFScene.deserialize(d))
405
+ gltf.nodes = nodes.map((/**@type {any}*/d) => GLTFNode.deserialize(d))
406
+ gltf.meshes = meshes.map((/**@type {any}*/d) => GLTFMesh.deserialize(d))
407
+ gltf.bufferViews = bufferViews.map((/**@type {any}*/d) => GLTFBufferView.deserialize(d))
408
+ gltf.accessors = accessors.map((/**@type {any}*/d) => GLTFAccessor.deserialize(d))
409
+
410
+ if (materials instanceof Array) {
411
+ gltf.materials = materials.map((/**@type {any}*/d) => GLTFMaterial.deserialize(d))
412
+ }
413
+
414
+ if (images instanceof Array) {
415
+ gltf.images = images.map((/**@type {any}*/d) => GLTFImage.deserialize(d))
416
+ }
417
+
418
+ if (samplers instanceof Array) {
419
+ gltf.samplers = samplers.map((/**@type {any}*/d) => GLFTSampler.deserialize(d))
420
+ }
421
+
422
+ if (textures instanceof Array) {
423
+ gltf.textures = textures.map((/**@type {any}*/d) => GLFTTexture.deserialize(d))
424
+ }
425
+
426
+ if (skins instanceof Array) {
427
+ gltf.skins = skins.map(a => GLTFSkin.deserialize(a))
428
+ } else {
429
+ gltf.skins = []
430
+ }
431
+ return gltf
432
+ }
433
+ }
434
+
435
+ class GLTFScene {
436
+ /**
437
+ * @type {string}
438
+ */
439
+ name = ''
440
+ /**
441
+ * @type {Record<string,any>}
442
+ */
443
+ extensions = {}
444
+ /**
445
+ * @type {Record<string,any>}
446
+ */
447
+ extras = []
448
+ /**
449
+ * @type {number[]}
450
+ */
451
+ nodes = []
452
+
453
+ /**
454
+ * @param {any} data
455
+ */
456
+ static deserialize(data) {
457
+ const { nodes, name, extensions, extras } = data
458
+ const scene = new GLTFScene()
459
+
460
+ if (nodes instanceof Array) {
461
+ scene.nodes = nodes
462
+ .filter((node) => typeof node == "number")
463
+ }
464
+
465
+ if (typeof name === "string") {
466
+ scene.name = name
467
+ } else {
468
+ scene.name = ''
469
+ }
470
+ if (extensions instanceof Object) {
471
+ scene.extensions = extensions
472
+ } else {
473
+ scene.extensions = {}
474
+ }
475
+ if (extras instanceof Object) {
476
+ scene.extras = extras
477
+ } else {
478
+ scene.extras = {}
479
+ }
480
+ return scene
481
+ }
482
+ }
483
+
484
+ class GLTFNode {
485
+ /**
486
+ * @type {string}
487
+ */
488
+ name = ''
489
+ /**
490
+ * @type {Record<string,any>}
491
+ */
492
+ extensions = {}
493
+ /**
494
+ * @type {Record<string,any>}
495
+ */
496
+ extras = []
497
+ /**
498
+ * @type {number | undefined}
499
+ */
500
+ mesh
501
+ /**
502
+ * @type {number | undefined}
503
+ */
504
+ skin
505
+
506
+ /**
507
+ * @type {number | undefined}
508
+ */
509
+ camera
510
+ /**
511
+ * @type {number[] | undefined}
512
+ */
513
+ weights
514
+ /**
515
+ * @type {number[]}
516
+ */
517
+ children = []
518
+ /**
519
+ * @type {TRSTransform | MatrixTransform | undefined}
520
+ */
521
+ transform
522
+ /**
523
+ * @param {any} data
524
+ */
525
+ static deserialize(data) {
526
+ const {
527
+ mesh, matrix, translation,
528
+ rotation, scale, weights,
529
+ children, skin, camera,
530
+ name, extensions, extras
531
+ } = data
532
+ const node = new GLTFNode()
533
+
534
+ if (typeof mesh === "number") {
535
+ node.mesh = mesh
536
+ }
537
+ if (typeof skin === 'number') {
538
+ node.skin = skin
539
+ }
540
+ if (typeof camera === 'number') {
541
+ node.camera = camera
542
+ }
543
+ if (weights instanceof Array) {
544
+ node.weights = weights.filter(w => typeof w === "number")
545
+ }
546
+ if (matrix) {
547
+ node.transform = MatrixTransform.deserialize(matrix)
548
+ }
549
+ if (translation || rotation || scale) {
550
+ const ntranslation = translation || [0, 0, 0]
551
+ const nrotation = rotation || [0, 0, 0, 1]
552
+ const nscale = scale || [1, 1, 1]
553
+ node.transform = TRSTransform.deserialize(
554
+ ntranslation,
555
+ nrotation,
556
+ nscale
557
+ )
558
+ } else if (matrix) {
559
+ node.transform = MatrixTransform.deserialize(matrix)
560
+ } else {
561
+ node.transform = new TRSTransform()
562
+ }
563
+
564
+ if (children instanceof Array) {
565
+ node.children = children.filter(c => typeof c === "number")
566
+ } else {
567
+ node.children = []
568
+ }
569
+
570
+ if (typeof name === 'string') {
571
+ node.name = name
572
+ } else {
573
+ node.name = ""
574
+ }
575
+ if (extensions instanceof Object) {
576
+ node.extensions = extensions
577
+ } else {
578
+ node.extensions = {}
579
+ }
580
+ if (extras instanceof Object) {
581
+ node.extras = extras
582
+ } else {
583
+ node.extras = {}
584
+ }
585
+ return node
586
+ }
587
+ }
588
+
589
+ class GLTFMesh {
590
+ /**
591
+ * @type {string}
592
+ */
593
+ name = ''
594
+ /**
595
+ * @type {Record<string,any>}
596
+ */
597
+ extensions = {}
598
+ /**
599
+ * @type {Record<string,any>}
600
+ */
601
+ extras = {}
602
+
603
+ /**
604
+ * @type {GLTFPrimitive[]}
605
+ */
606
+ primitives = []
607
+ /**
608
+ * @type {number[]}
609
+ */
610
+ weights = []
611
+ /**
612
+ * @param {any} data
613
+ */
614
+ static deserialize(data) {
615
+ const { primitives, weights, name, extensions, extras } = data
616
+ const mesh = new GLTFMesh()
617
+
618
+ if (primitives instanceof Array) {
619
+ mesh.primitives = primitives.map((p) => GLTFPrimitive.deserialize(p))
620
+ } else {
621
+ mesh.primitives = []
622
+ }
623
+
624
+ if (weights instanceof Array) {
625
+ mesh.weights = weights.filter(weight => typeof weight === "number")
626
+ } else {
627
+ mesh.weights = []
628
+ }
629
+
630
+ if (typeof name === "string") {
631
+ mesh.name = name
632
+ } else {
633
+ mesh.name = ''
634
+ }
635
+ if (extensions instanceof Object) {
636
+ mesh.extensions = extensions
637
+ } else {
638
+ mesh.extensions = {}
639
+ }
640
+ if (extras instanceof Object) {
641
+ mesh.extras = extras
642
+ } else {
643
+ mesh.extras = {}
644
+ }
645
+ return mesh
646
+ }
647
+ }
648
+
649
+ class GLTFMaterial {
650
+ /**
651
+ * @type {string}
652
+ */
653
+ name = ''
654
+ /**
655
+ * @type {Record<string,any>}
656
+ */
657
+ extensions = {}
658
+ /**
659
+ * @type {Record<string,any>}
660
+ */
661
+ extras = {}
662
+
663
+ /**
664
+ * @type {GLTFPBRetallicRoughness}
665
+ */
666
+ pbrMetallicRoughness
667
+
668
+ /**
669
+ * @type {GLFTTextureInfo | undefined}
670
+ */
671
+ normalTexture
672
+
673
+ /**
674
+ * @type {GLFTTextureInfo | undefined}
675
+ */
676
+ occlusionTexture
677
+
678
+ /**
679
+ * @type {GLFTTextureInfo | undefined}
680
+ */
681
+ emissiveTexture
682
+
683
+ /**
684
+ * @type {[number, number, number]}
685
+ */
686
+ emissiveFactor = [0, 0, 0]
687
+
688
+ /**
689
+ * @type {GLFTAlphaMode}
690
+ */
691
+ alphaMode = GLFTAlphaMode.Opaque
692
+
693
+ /**
694
+ * @type {number}
695
+ */
696
+ alphaCutoff = 0.5
697
+
698
+ /**
699
+ * @type {boolean}
700
+ */
701
+ doubleSide = false
702
+
703
+ /**
704
+ * @param {GLTFPBRetallicRoughness} metallicRoughness
705
+ */
706
+ constructor(metallicRoughness) {
707
+ this.pbrMetallicRoughness = metallicRoughness
708
+ }
709
+ /**
710
+ * @param {any} data
711
+ */
712
+ static deserialize(data) {
713
+ const {
714
+ pbrMetallicRoughness,
715
+ normalTexture,
716
+ occlusionTexture,
717
+ emissiveTexture,
718
+ emissiveFactor,
719
+ alphaMode,
720
+ alphaCutoff,
721
+ doubleSide,
722
+ name,
723
+ extensions,
724
+ extras
725
+ } = data
726
+ const pbr = pbrMetallicRoughness ? GLTFPBRetallicRoughness.deserialize(pbrMetallicRoughness) : new GLTFPBRetallicRoughness()
727
+ const result = new GLTFMaterial(pbr)
728
+
729
+ if (normalTexture instanceof Object) {
730
+ result.normalTexture = GLFTTextureInfo.deserialize(normalTexture)
731
+ }
732
+
733
+ if (occlusionTexture instanceof Object) {
734
+ result.occlusionTexture = GLFTTextureInfo.deserialize(occlusionTexture)
735
+ }
736
+
737
+ if (emissiveTexture instanceof Object) {
738
+ result.emissiveTexture = GLFTTextureInfo.deserialize(emissiveTexture)
739
+ }
740
+
741
+ if (emissiveFactor instanceof Array && emissiveFactor.length === 3) {
742
+ result.emissiveFactor = /**@type {[number, number, number]}*/(emissiveFactor)
743
+ }
744
+
745
+ if (typeof alphaCutoff === 'number') {
746
+ result.alphaCutoff = alphaCutoff
747
+ }
748
+
749
+ if (typeof alphaMode === 'string') {
750
+ result.alphaMode = alphaMode
751
+ }
752
+
753
+ if (typeof doubleSide === 'boolean') {
754
+ result.doubleSide = doubleSide
755
+ }
756
+
757
+ if (typeof name === "string") {
758
+ result.name = name
759
+ } else {
760
+ result.name = ''
761
+ }
762
+
763
+ if (extensions instanceof Object) {
764
+ result.extensions = extensions
765
+ } else {
766
+ result.extensions = {}
767
+ }
768
+
769
+ if (extras instanceof Object) {
770
+ result.extras = extras
771
+ } else {
772
+ result.extras = {}
773
+ }
774
+ return result
775
+ }
776
+ }
777
+
778
+ class GLTFImage {
779
+ /**
780
+ * @type {string | undefined}
781
+ */
782
+ uri
783
+
784
+ /**
785
+ * @type {number | undefined}
786
+ */
787
+ bufferView
788
+
789
+ /**
790
+ * @type {string | undefined}
791
+ */
792
+ mimeType
793
+
794
+
795
+ /**
796
+ * @type {string}
797
+ */
798
+ name = ''
799
+ /**
800
+ * @type {Record<string,any>}
801
+ */
802
+ extensions = {}
803
+ /**
804
+ * @type {Record<string,any>}
805
+ */
806
+ extras = []
807
+
808
+ /**
809
+ * @param {any} data
810
+ */
811
+ static deserialize(data) {
812
+ const { uri, bufferView, mimeType, name, extensions, extras } = data
813
+ const result = new GLTFImage()
814
+
815
+ if (typeof uri === 'string') {
816
+ result.uri = uri
817
+ }
818
+
819
+ if (typeof bufferView === 'number') {
820
+ result.bufferView = bufferView
821
+ }
822
+ if (typeof mimeType === 'string') {
823
+ result.mimeType = mimeType
824
+ }
825
+ if (typeof name === 'string') {
826
+ result.name = name
827
+ }
828
+ if (extensions instanceof Object) {
829
+ result.extensions = extensions
830
+ } else {
831
+ result.extensions = {}
832
+ }
833
+ if (extras instanceof Object) {
834
+ result.extras = extras
835
+ } else {
836
+ result.extras = {}
837
+ }
838
+
839
+ return result
840
+ }
841
+ }
842
+
843
+ class GLFTSampler {
844
+ /**
845
+ * @type {number | undefined}
846
+ */
847
+ magFilter
848
+ /**
849
+ * @type {number | undefined}
850
+ */
851
+ minFilter
852
+ /**
853
+ * @type {number | undefined}
854
+ */
855
+ wrapS
856
+ /**
857
+ * @type {number | undefined}
858
+ */
859
+ wrapT
860
+ /**
861
+ * @type {string}
862
+ */
863
+ name = ''
864
+ /**
865
+ * @type {Record<string,any>}
866
+ */
867
+ extensions = {}
868
+ /**
869
+ * @type {Record<string,any>}
870
+ */
871
+ extras = []
872
+ /**
873
+ * @param {any} data
874
+ */
875
+ static deserialize(data) {
876
+ const { magFilter, minFilter, wrapS, wrapT, name, extensions, extras } = data
877
+ const result = new GLFTSampler()
878
+
879
+ if (typeof magFilter === 'number') {
880
+ result.magFilter = magFilter
881
+ }
882
+
883
+ if (typeof minFilter === 'number') {
884
+ result.minFilter = minFilter
885
+ }
886
+
887
+ if (typeof wrapS === 'number') {
888
+ result.wrapS = wrapS
889
+ }
890
+
891
+ if (typeof wrapT === 'number') {
892
+ result.wrapT = wrapT
893
+ }
894
+
895
+ if (typeof name === 'string') {
896
+ result.name = name
897
+ }
898
+
899
+ if (extensions instanceof Object) {
900
+ result.extensions = extensions
901
+ } else {
902
+ result.extensions = {}
903
+ }
904
+ if (extras instanceof Object) {
905
+ result.extras = extras
906
+ } else {
907
+ result.extras = {}
908
+ }
909
+
910
+ return result
911
+ }
912
+ }
913
+
914
+ class GLFTTexture {
915
+ /**
916
+ * @type {number | undefined}
917
+ */
918
+ sampler
919
+
920
+ /**
921
+ * @type {number}
922
+ */
923
+ source
924
+
925
+ /**
926
+ * @type {string}
927
+ */
928
+ name = ''
929
+ /**
930
+ * @type {Record<string,any>}
931
+ */
932
+ extensions = {}
933
+ /**
934
+ * @type {Record<string,any>}
935
+ */
936
+ extras = []
937
+
938
+ /**
939
+ * @param {number} source
940
+ */
941
+ constructor(source) {
942
+ this.source = source
943
+ }
944
+ /**
945
+ * @param {any} data
946
+ */
947
+ static deserialize(data) {
948
+ const { source, sampler, name, extensions, extras } = data
949
+
950
+ if (typeof source !== 'number') {
951
+ throw 'No source for the texture.'
952
+ }
953
+
954
+ const result = new GLFTTexture(source)
955
+
956
+ if (typeof sampler === 'number') {
957
+ result.sampler = sampler
958
+ }
959
+
960
+ if (typeof name === 'string') {
961
+ result.name = name
962
+ }
963
+
964
+ if (extensions instanceof Object) {
965
+ result.extensions = extensions
966
+ } else {
967
+ result.extensions = {}
968
+ }
969
+
970
+ if (extras instanceof Object) {
971
+ result.extras = extras
972
+ } else {
973
+ result.extras = {}
974
+ }
975
+
976
+ return result
977
+ }
978
+ }
979
+
980
+ class GLTFSkin {
981
+ /**
982
+ * @type {number}
983
+ */
984
+ inverseBindMatrices
985
+
986
+ /**
987
+ * @type {number | undefined}
988
+ */
989
+ skeleton
990
+ /**
991
+ * @type {number[]}
992
+ */
993
+ joints
994
+
995
+ /**
996
+ * @param {number[]} joints
997
+ * @param {number} inverseBindMatrices
998
+ */
999
+ constructor(joints, inverseBindMatrices) {
1000
+ this.inverseBindMatrices = inverseBindMatrices
1001
+ this.joints = joints
1002
+ }
1003
+
1004
+ /**
1005
+
1006
+ * @param {any} data
1007
+ */
1008
+ static deserialize(data) {
1009
+ const { joints, inverseBindMatrices, skeleton } = data
1010
+
1011
+ if (
1012
+ !(joints instanceof Array) ||
1013
+ typeof inverseBindMatrices !== 'number'
1014
+ ) {
1015
+ throw 'Invalid skin'
1016
+ }
1017
+ const object = new GLTFSkin(
1018
+ joints.filter(e => typeof e === 'number'),
1019
+ inverseBindMatrices
1020
+ )
1021
+
1022
+ if (typeof skeleton === 'number') {
1023
+ object.skeleton = skeleton
1024
+ }
1025
+ return object
1026
+ }
1027
+ }
1028
+
1029
+ class GLTFBufferView {
1030
+ /**
1031
+ * @type {string}
1032
+ */
1033
+ name = ''
1034
+ /**
1035
+ * @type {Record<string,any>}
1036
+ */
1037
+ extensions = {}
1038
+ /**
1039
+ * @type {Record<string,any>}
1040
+ */
1041
+ extras = []
1042
+ /**
1043
+ * @type {number}
1044
+ */
1045
+ buffer
1046
+ /**
1047
+ * @type {number}
1048
+ */
1049
+ offset = 0
1050
+ /**
1051
+ * @type {number}
1052
+ */
1053
+ length
1054
+ /**
1055
+ * @type {number}
1056
+ */
1057
+ stride = 0
1058
+ /**
1059
+ * @type {number | undefined}
1060
+ */
1061
+ target
1062
+
1063
+ /**
1064
+ * @param {number} buffer
1065
+ * @param {number} length
1066
+ */
1067
+ constructor(buffer, length) {
1068
+ this.buffer = buffer
1069
+ this.length = length
1070
+ }
1071
+
1072
+ /**
1073
+ * @param {any} data
1074
+ */
1075
+ static deserialize(data) {
1076
+ const {
1077
+ buffer,
1078
+ byteOffset,
1079
+ byteLength,
1080
+ target,
1081
+ byteStride,
1082
+ name,
1083
+ extensions,
1084
+ extras
1085
+ } = data
1086
+
1087
+ if (
1088
+ typeof buffer !== "number" ||
1089
+ typeof byteLength !== "number"
1090
+ ) {
1091
+ throw "Invalid buffer view provided"
1092
+ }
1093
+
1094
+ const struct = new GLTFBufferView(buffer, byteLength)
1095
+
1096
+ if (typeof byteOffset === "number") {
1097
+ struct.offset = byteOffset
1098
+ } else {
1099
+ struct.offset = 0
1100
+ }
1101
+
1102
+ if (typeof byteStride === "number") {
1103
+ struct.stride = byteStride
1104
+ } else {
1105
+ struct.stride = 0
1106
+ }
1107
+
1108
+ if (typeof target === "number") {
1109
+ struct.target = target
1110
+ }
1111
+
1112
+ if (typeof name === 'string') {
1113
+ struct.name = name
1114
+ } else {
1115
+ struct.name = ""
1116
+ }
1117
+ if (extensions instanceof Object) {
1118
+ struct.extensions = extensions
1119
+ } else {
1120
+ struct.extensions = {}
1121
+ }
1122
+ if (extras instanceof Object) {
1123
+ struct.extras = extras
1124
+ } else {
1125
+ struct.extras = {}
1126
+ }
1127
+ return struct
1128
+ }
1129
+ }
1130
+
1131
+ class GLTFAccessor {
1132
+ /**
1133
+ * @type {string}
1134
+ */
1135
+ name = ''
1136
+ /**
1137
+ * @type {Record<string,any>}
1138
+ */
1139
+ extensions = {}
1140
+ /**
1141
+ * @type {Record<string,any>}
1142
+ */
1143
+ extras = {}
1144
+ /**
1145
+ * @type {boolean}
1146
+ */
1147
+ normalized = false
1148
+ /**
1149
+ * @type {number}
1150
+ */
1151
+ view = 0
1152
+ /**
1153
+ * @type {number}
1154
+ */
1155
+ offset = 0
1156
+ /**
1157
+ * @type {GLTFComponentType}
1158
+ */
1159
+ componentType
1160
+ /**
1161
+ * @type {number}
1162
+ */
1163
+ count
1164
+ /**
1165
+ * @type {GLTFAccessorType}
1166
+ */
1167
+ type
1168
+ /**
1169
+ * @type {number[] | undefined}
1170
+ */
1171
+ max
1172
+ /**
1173
+ * @type {number[] | undefined}
1174
+ */
1175
+ min
1176
+
1177
+ /**
1178
+ * @param {number} type
1179
+ * @param {number} componentType
1180
+ * @param {number} count
1181
+ */
1182
+ constructor(type, componentType, count) {
1183
+ this.type = type
1184
+ this.componentType = componentType
1185
+ this.count = count
1186
+ }
1187
+ /**
1188
+ * @param {any} data
1189
+ */
1190
+ static deserialize(data) {
1191
+ const {
1192
+ bufferView,
1193
+ byteOffset,
1194
+ componentType,
1195
+ count,
1196
+ type,
1197
+ max,
1198
+ min,
1199
+ normalized,
1200
+ sparse,
1201
+ name,
1202
+ extensions,
1203
+ extras
1204
+ } = data
1205
+
1206
+ if (
1207
+ typeof componentType !== "number" ||
1208
+ typeof type !== "string" ||
1209
+ typeof count !== "number"
1210
+ ) {
1211
+ throw "Invalid accessor"
1212
+ }
1213
+ const struct = new GLTFAccessor(
1214
+ mapAccessorType(type),
1215
+ mapComponentType(componentType),
1216
+ count
1217
+ )
1218
+
1219
+ if (typeof bufferView === "number") {
1220
+ struct.view = bufferView
1221
+ } else {
1222
+ if (sparse instanceof Object) {
1223
+ throw "Sparse accessors are not yet supported"
1224
+ } else {
1225
+ throw "No buffer view to index into for accessor"
1226
+ }
1227
+ }
1228
+
1229
+ if (typeof byteOffset === "number") {
1230
+ struct.offset = byteOffset
1231
+ } else {
1232
+ struct.offset = 0
1233
+ }
1234
+
1235
+ if (typeof normalized === "boolean") {
1236
+ struct.normalized = normalized
1237
+ } else {
1238
+ struct.normalized = false
1239
+ }
1240
+
1241
+ if (max instanceof Array) {
1242
+ struct.max = max
1243
+ }
1244
+
1245
+ if (min instanceof Array) {
1246
+ struct.min = min
1247
+ }
1248
+
1249
+ if (typeof name === 'string') {
1250
+ struct.name = name
1251
+ } else {
1252
+ struct.name = ""
1253
+ }
1254
+ if (extensions instanceof Object) {
1255
+ struct.extensions = extensions
1256
+ } else {
1257
+ struct.extensions = {}
1258
+ }
1259
+ if (extras instanceof Object) {
1260
+ struct.extras = extras
1261
+ } else {
1262
+ struct.extras = {}
1263
+ }
1264
+ return struct
1265
+ }
1266
+ }
1267
+
1268
+ class GLTFMetaData {
1269
+ /**
1270
+ * @type {string}
1271
+ */
1272
+ version
1273
+ /**
1274
+ * @type {string | undefined}
1275
+ */
1276
+ generator
1277
+
1278
+ /**
1279
+ * @param {string} version
1280
+ */
1281
+ constructor(version) {
1282
+ this.version = version
1283
+ }
1284
+ /**
1285
+ * @param {any} data
1286
+ */
1287
+ static deserialize(data) {
1288
+ const { version, generator } = data
1289
+
1290
+ if (typeof version !== "string") {
1291
+ throw "GLTF asset version is required"
1292
+ }
1293
+
1294
+ const meta = new GLTFMetaData(version)
1295
+ if (typeof generator === "string") {
1296
+ meta.generator = generator
1297
+ }
1298
+ return meta
1299
+ }
1300
+ }
1301
+
1302
+ class GLTFPrimitive {
1303
+ /**
1304
+ * @type {Map<GLTFAttributeName,number>}
1305
+ */
1306
+ attributes = new Map()
1307
+ /**
1308
+ * @type {number | undefined}
1309
+ */
1310
+ indices
1311
+ /**
1312
+ * @type {number | undefined}
1313
+ */
1314
+ material
1315
+ /**
1316
+ * @type {GLTFPrimitiveMode}
1317
+ */
1318
+ mode = GLTFPrimitiveMode.Triangles
1319
+ /**
1320
+ * @param {any} data
1321
+ */
1322
+ static deserialize(data) {
1323
+ const { attributes, material, indices, mode } = data
1324
+ const primitive = new GLTFPrimitive()
1325
+
1326
+ if (typeof indices === "number") {
1327
+ primitive.indices = indices
1328
+ }
1329
+
1330
+ if (typeof material === "number") {
1331
+ primitive.material = material
1332
+ }
1333
+
1334
+ if (attributes instanceof Object) {
1335
+ for (const key in attributes) {
1336
+ const value = attributes[key]
1337
+ if (typeof value === "number") {
1338
+ primitive.attributes.set(key, value)
1339
+ }
1340
+ }
1341
+ }
1342
+ if (typeof mode === "number") {
1343
+ primitive.mode = mapPrimitiveMode(mode)
1344
+ } else {
1345
+ primitive.mode = GLTFPrimitiveMode.Triangles
1346
+ }
1347
+ return primitive
1348
+ }
1349
+ }
1350
+
1351
+ class GLTFPBRetallicRoughness {
1352
+ /**
1353
+ * @type {Record<string,any>}
1354
+ */
1355
+ extensions = {}
1356
+
1357
+ /**
1358
+ * @type {Record<string,any>}
1359
+ */
1360
+ extras = {}
1361
+
1362
+ /**
1363
+ * @type {[number, number, number, number]}
1364
+ */
1365
+ baseColorFactor = [1, 1, 1, 1]
1366
+
1367
+ /**
1368
+ * @type { GLFTTextureInfo | undefined }
1369
+ */
1370
+ baseColorTexture
1371
+
1372
+ /**
1373
+ * @type {number}
1374
+ */
1375
+ metallicFactor = 1
1376
+
1377
+ /**
1378
+ * @type {number}
1379
+ */
1380
+ roughnessFactor = 1
1381
+
1382
+ /**
1383
+ * @type {GLFTTextureInfo | undefined}
1384
+ */
1385
+ metallicRoughnessTexture
1386
+
1387
+ /**
1388
+ * @param {any} data
1389
+ */
1390
+ static deserialize(data) {
1391
+ const {
1392
+ baseColorFactor,
1393
+ baseColorTexture,
1394
+ metallicFactor,
1395
+ roughnessFactor,
1396
+ metallicRoughnessTexture,
1397
+ extensions,
1398
+ extras
1399
+ } = data
1400
+
1401
+ const result = new GLTFPBRetallicRoughness()
1402
+
1403
+ if (typeof metallicFactor === 'number') {
1404
+ result.metallicFactor = metallicFactor
1405
+ }
1406
+
1407
+ if (typeof roughnessFactor === 'number') {
1408
+ result.roughnessFactor = roughnessFactor
1409
+ }
1410
+
1411
+ if (baseColorFactor instanceof Array && baseColorFactor.length === 4) [
1412
+ result.baseColorFactor = /**@type {[number,number,number,number]}*/(baseColorFactor)
1413
+ ]
1414
+
1415
+ if (baseColorTexture) {
1416
+ result.baseColorTexture = GLFTTextureInfo.deserialize(baseColorTexture)
1417
+ }
1418
+
1419
+ if (metallicRoughnessTexture) {
1420
+ result.metallicRoughnessTexture = GLFTTextureInfo.deserialize(metallicRoughnessTexture)
1421
+ }
1422
+
1423
+ if (extensions instanceof Object) {
1424
+ result.extensions = extensions
1425
+ } else {
1426
+ result.extensions = {}
1427
+ }
1428
+ if (extras instanceof Object) {
1429
+ result.extras = extras
1430
+ } else {
1431
+ result.extras = {}
1432
+ }
1433
+
1434
+ return result
1435
+ }
1436
+ }
1437
+
1438
+ class GLFTTextureInfo {
1439
+ /**
1440
+ * @type {number}
1441
+ */
1442
+ index
1443
+
1444
+ /**
1445
+ * @type {number}
1446
+ */
1447
+ texCoord = 0
1448
+
1449
+ /**
1450
+ * @type {number}
1451
+ */
1452
+ scale = 1
1453
+
1454
+ /**
1455
+ * @type {number}
1456
+ */
1457
+ strength = 1
1458
+
1459
+ /**
1460
+ * @type {Record<string, any>}
1461
+ */
1462
+ extensions = {}
1463
+
1464
+ /**
1465
+ * @type {Record<string, any>}
1466
+ */
1467
+ extras = {}
1468
+
1469
+ /**
1470
+ * @param {number} index
1471
+ */
1472
+ constructor(index) {
1473
+ this.index = index
1474
+ }
1475
+ /**
1476
+ * @param {any} data
1477
+ */
1478
+ static deserialize(data) {
1479
+ const { index, texCoord, scale, strength, extensions, extras } = data
1480
+
1481
+ if (typeof index !== 'number') {
1482
+ throw 'Texture info index is not type of number'
1483
+ }
1484
+ const result = new GLFTTextureInfo(index)
1485
+
1486
+ if (typeof texCoord === 'number') [
1487
+ result.texCoord = texCoord
1488
+ ]
1489
+
1490
+ if (typeof scale === 'number') [
1491
+ result.scale = scale
1492
+ ]
1493
+
1494
+ if (typeof strength === 'number') [
1495
+ result.strength = strength
1496
+ ]
1497
+
1498
+ if (extensions instanceof Object) {
1499
+ result.extensions = extensions
1500
+ } else {
1501
+ result.extensions = {}
1502
+ }
1503
+ if (extras instanceof Object) {
1504
+ result.extras = extras
1505
+ } else {
1506
+ result.extras = {}
1507
+ }
1508
+
1509
+ return result
1510
+ }
1511
+ }
1512
+
1513
+ /**
1514
+ * Enum of GLTF's semantic mesh attribute names.
1515
+ * @enum {string}
1516
+ */
1517
+ export const GLTFAttributeName = /**@type {const}*/({
1518
+ /** Vertex positions */
1519
+ Position: "POSITION",
1520
+ /** Vertex normals */
1521
+ Normal: "NORMAL",
1522
+ /** Vertex tangents */
1523
+ Tangent: "TANGENT",
1524
+ /** Vertex texture coordinates set 0 */
1525
+ TexCoord0: "TEXCOORD_0",
1526
+ /** Vertex texture coordinates set 1 */
1527
+ TexCoord1: "TEXCOORD_1",
1528
+ /** Vertex colors set 0 */
1529
+ Color0: "COLOR_0",
1530
+ /** Joint indices for skinning set 0 */
1531
+ Joints0: "JOINTS_0",
1532
+ /** Joint weights for skinning set 0 */
1533
+ Weights0: "WEIGHTS_0"
1534
+ })
1535
+
1536
+ /**
1537
+ * @enum {number}
1538
+ */
1539
+ export const GLTFComponentType = /**@type {const}*/({
1540
+ Byte: 0x1400,
1541
+ UnsignedByte: 0x1401,
1542
+ Short: 0x1402,
1543
+ UnsignedShort: 0x1403,
1544
+ Int: 0x1404,
1545
+ UnsignedInt: 0x1405,
1546
+ Float: 0x1406
1547
+ })
1548
+
1549
+ /**
1550
+ * @enum {number}
1551
+ */
1552
+ export const GLTFAccessorType = /**@type {const}*/({
1553
+ Scalar: 0,
1554
+ Vec2: 1,
1555
+ Vec3: 2,
1556
+ Vec4: 3,
1557
+ Mat2: 4,
1558
+ Mat3: 5,
1559
+ Mat4: 6
1560
+ })
1561
+
1562
+ /**
1563
+ * @enum {number}
1564
+ */
1565
+ export const GLTFPrimitiveMode = /**@type {const}*/({
1566
+ Points: 0,
1567
+ Lines: 1,
1568
+ LineLoop: 2,
1569
+ LineStrip: 3,
1570
+ Triangles: 4,
1571
+ TriangleStrip: 5,
1572
+ TriangleFan: 6
1573
+ })
1574
+
1575
+ /**
1576
+ * @enum {string}
1577
+ */
1578
+ export const GLFTAlphaMode = /**@type {const}*/({
1579
+ Opaque: "OPAQUE",
1580
+ Mask: "MASK",
1581
+ Blend: "BLEND"
1582
+ })
1583
+
1584
+ /**
1585
+ * Maps a raw glTF accessor type string to a valid AccessorType enum value.
1586
+ * @param {string} typeString - Raw type from the glTF JSON (e.g. "VEC3", "MAT4").
1587
+ * @returns {GLTFAccessorType} One of the AccessorType values.
1588
+ * @throws {Error} If the type is not recognized.
1589
+ */
1590
+ function mapAccessorType(typeString) {
1591
+ switch (typeString.toUpperCase()) {
1592
+ case "SCALAR": return GLTFAccessorType.Scalar;
1593
+ case "VEC2": return GLTFAccessorType.Vec2;
1594
+ case "VEC3": return GLTFAccessorType.Vec3;
1595
+ case "VEC4": return GLTFAccessorType.Vec4;
1596
+ case "MAT2": return GLTFAccessorType.Mat2;
1597
+ case "MAT3": return GLTFAccessorType.Mat3;
1598
+ case "MAT4": return GLTFAccessorType.Mat4;
1599
+ default:
1600
+ throw new Error(`Unknown accessor type: ${typeString}`);
1601
+ }
1602
+ }
1603
+
1604
+ /**
1605
+ * Maps a raw glTF accessor component type string to a valid AccessorComponentType enum value.
1606
+ * @param {number} value - Raw type from the glTF JSON (e.g. "VEC3", "MAT4").
1607
+ * @returns {GLTFAccessorType} One of the AccessorType values.
1608
+ * @throws {Error} If the component type is not recognized.
1609
+ */
1610
+ function mapComponentType(value) {
1611
+ switch (value) {
1612
+ case 0x1400: return GLTFComponentType.Byte;
1613
+ case 0x1401: return GLTFComponentType.UnsignedByte;
1614
+ case 0x1402: return GLTFComponentType.Short;
1615
+ case 0x1403: return GLTFComponentType.UnsignedShort;
1616
+ case 0x1404: return GLTFComponentType.Int;
1617
+ case 0x1405: return GLTFComponentType.UnsignedInt;
1618
+ case 0x1406: return GLTFComponentType.Float;
1619
+ default:
1620
+ throw new Error(`Unknown accessor component type: ${value}`);
1621
+ }
1622
+ }
1623
+
1624
+ /**
1625
+ * @param {number} mode
1626
+ */
1627
+ export function mapPrimitiveMode(mode) {
1628
+ switch (mode) {
1629
+ case 0: return GLTFPrimitiveMode.Points;
1630
+ case 1: return GLTFPrimitiveMode.Lines;
1631
+ case 2: return GLTFPrimitiveMode.LineLoop;
1632
+ case 3: return GLTFPrimitiveMode.LineStrip;
1633
+ case 4: return GLTFPrimitiveMode.Triangles;
1634
+ case 5: return GLTFPrimitiveMode.TriangleStrip;
1635
+ case 6: return GLTFPrimitiveMode.TriangleFan;
1636
+ default: throw "Unrecognized primitive mode: " + mode
1637
+ }
1638
+ }
1639
+
1640
+ class TRSTransform {
1641
+ /**
1642
+ * @type {[number,number,number]}
1643
+ */
1644
+ translation
1645
+ /**
1646
+ * @type {[number,number,number,number]}
1647
+ */
1648
+ rotation
1649
+ /**
1650
+ * @type {[number,number,number]}
1651
+ */
1652
+ scale
1653
+ /**
1654
+ * @param {[number, number, number]} [translation]
1655
+ * @param {[number, number, number, number]} [rotation]
1656
+ * @param {[number, number, number]} [scale]
1657
+ */
1658
+ constructor(
1659
+ translation = [0, 0, 0],
1660
+ rotation = [0, 0, 0, 1],
1661
+ scale = [1, 1, 1]
1662
+ ) {
1663
+ this.translation = translation
1664
+ this.rotation = rotation
1665
+ this.scale = scale
1666
+ }
1667
+ /**
1668
+ * @param {any} translation
1669
+ * @param {any} rotation
1670
+ * @param {any} scale
1671
+ */
1672
+ static deserialize(translation, rotation, scale) {
1673
+ const transform = new TRSTransform()
1674
+
1675
+ if (
1676
+ !(translation instanceof Array) ||
1677
+ !(rotation instanceof Array) ||
1678
+ !(scale instanceof Array)
1679
+ ) {
1680
+ throw "Invalid transform"
1681
+ }
1682
+
1683
+ //@ts-ignore
1684
+ transform.translation = translation.filter((data) => typeof data === "number")
1685
+ //@ts-ignore
1686
+ transform.rotation = rotation.filter((data) => typeof data === "number")
1687
+ //@ts-ignore
1688
+ transform.scale = scale.filter((data) => typeof data === "number")
1689
+ return transform
1690
+ }
1691
+ }
1692
+
1693
+ class MatrixTransform {
1694
+ /**
1695
+ * @type {MatrixArray}
1696
+ */
1697
+ value
1698
+
1699
+ /**
1700
+ * @param {MatrixArray} value
1701
+ */
1702
+ constructor(value) {
1703
+ this.value = value
1704
+ }
1705
+ /**
1706
+ * @param {any} data
1707
+ */
1708
+ static deserialize(data) {
1709
+
1710
+ if (
1711
+ !(data instanceof Array)
1712
+ ) {
1713
+ throw "Invalid transform"
1714
+ }
1715
+ const t = data.filter((data) => typeof data === "number")
1716
+
1717
+ if (t.length !== 16) {
1718
+ throw "invalid matrix transform"
1719
+ }
1720
+ const transform = new MatrixTransform(/**@type {MatrixArray}*/(t))
1721
+
1722
+ return transform
1723
+ }
1724
+ }
1725
+
1726
+ /**
1727
+ *
1728
+ * @param {number} index
1729
+ * @param {GLTF} gltf
1730
+ * @returns {[DataView,GLTFAccessor]}
1731
+ */
1732
+ function getAccessorData(index, gltf) {
1733
+ const { accessors, bufferViews, buffers } = gltf
1734
+ const accessor = accessors[index]
1735
+ if (!accessor) throw "Invalid access to accessors"
1736
+
1737
+ const view = bufferViews[accessor.view]
1738
+
1739
+ if (!view) throw "Invalid access to buffer views"
1740
+
1741
+ const buffer = buffers[view.buffer]
1742
+
1743
+ if (!buffer) throw "Invalid access to buffer"
1744
+
1745
+ const byteLength = accessor.count * getComponentSize(accessor.componentType) * getElementSize(accessor.type)
1746
+
1747
+ return [
1748
+ new DataView(buffer, view.offset + accessor.offset, byteLength),
1749
+ accessor
1750
+ ]
1751
+ }
1752
+
1753
+ /**
1754
+ * @param {GLTFAccessor} accessor
1755
+ * @param {DataView} view
1756
+ */
1757
+ function mapToIndices(accessor, view) {
1758
+ switch (accessor.componentType) {
1759
+ case GLTFComponentType.UnsignedByte:
1760
+ return new Uint8Array(
1761
+ view.buffer,
1762
+ view.byteOffset,
1763
+ view.byteLength / Uint8Array.BYTES_PER_ELEMENT
1764
+ )
1765
+ case GLTFComponentType.UnsignedShort:
1766
+ return new Uint16Array(
1767
+ view.buffer,
1768
+ view.byteOffset,
1769
+ view.byteLength / Uint16Array.BYTES_PER_ELEMENT
1770
+ )
1771
+ case GLTFComponentType.UnsignedInt:
1772
+ return new Uint32Array(
1773
+ view.buffer,
1774
+ view.byteOffset,
1775
+ view.byteLength / Uint32Array.BYTES_PER_ELEMENT
1776
+ )
1777
+ default:
1778
+ throw "Indices provided on a mesh is not valid"
1779
+ }
1780
+ }
1781
+
1782
+ /**
1783
+ * @param {string} name
1784
+ * @param {GLTFAccessor} accessor
1785
+ * @param {DataView} buffer
1786
+ * @returns {[string, DataView] | undefined}
1787
+ */
1788
+ function mapAccessorTypeToAttribute(name, accessor, buffer) {
1789
+ const { componentType: type } = accessor
1790
+ switch (name) {
1791
+ case GLTFAttributeName.Position:
1792
+ if (type !== mapToGLTFComponentType(Attribute.Position.format))
1793
+ throw "Attribute types do not match"
1794
+ return [Attribute.Position.name, buffer]
1795
+ case GLTFAttributeName.TexCoord0:
1796
+ if (type !== mapToGLTFComponentType(Attribute.UV.format))
1797
+ throw "Attribute types do not match"
1798
+ return [Attribute.UV.name, buffer]
1799
+ case GLTFAttributeName.TexCoord1:
1800
+ if (type !== mapToGLTFComponentType(Attribute.UVB.format))
1801
+ throw "Attribute types do not match"
1802
+ return [Attribute.UVB.name, buffer]
1803
+ case GLTFAttributeName.Normal:
1804
+ if (type !== mapToGLTFComponentType(Attribute.Normal.format))
1805
+ throw "Attribute types do not match"
1806
+ return [Attribute.Normal.name, buffer]
1807
+ case GLTFAttributeName.Tangent:
1808
+ if (type !== mapToGLTFComponentType(Attribute.Tangent.format))
1809
+ throw "Attribute types do not match"
1810
+ return [Attribute.Tangent.name, buffer]
1811
+ case GLTFAttributeName.Color0:
1812
+ if (type !== mapToGLTFComponentType(Attribute.Color.format))
1813
+ throw "Attribute types do not match"
1814
+ return [Attribute.Color.name, buffer]
1815
+ case GLTFAttributeName.Weights0:
1816
+ if (type !== mapToGLTFComponentType(Attribute.JointWeight.format))
1817
+ throw "Attribute types do not match"
1818
+ return [Attribute.JointWeight.name, buffer]
1819
+ case GLTFAttributeName.Joints0:
1820
+ if (type === mapToGLTFComponentType(Attribute.JointIndex.format)) {
1821
+ return [Attribute.JointIndex.name, buffer]
1822
+ } else if (type === GlDataType.UnsignedByte) {
1823
+ const newBuffer = widenTypedArray(
1824
+ new Uint8Array(buffer.buffer, buffer.byteOffset, buffer.byteLength),
1825
+ Uint16Array
1826
+ )
1827
+ return [Attribute.JointIndex.name, new DataView(newBuffer.buffer)]
1828
+ } else {
1829
+ throw "Attribute types do not match"
1830
+ }
1831
+ default:
1832
+ return undefined;
1833
+ }
1834
+ }
1835
+
1836
+
1837
+ /**
1838
+ * @param {GLTFComponentType} componentType
1839
+ */
1840
+ function getComponentSize(componentType) {
1841
+ switch (componentType) {
1842
+ case GLTFComponentType.Byte: // 0x1400
1843
+ return 1;
1844
+ case GLTFComponentType.UnsignedByte: // 0x1401
1845
+ return 1;
1846
+ case GLTFComponentType.Short: // 0x1402
1847
+ return 2;
1848
+ case GLTFComponentType.UnsignedShort: // 0x1403
1849
+ return 2;
1850
+ case GLTFComponentType.Int: // 0x1404
1851
+ return 4;
1852
+ case GLTFComponentType.UnsignedInt: // 0x1405
1853
+ return 4;
1854
+ case GLTFComponentType.Float: // 0x1406
1855
+ return 4;
1856
+ default:
1857
+ return 0; // Return 0 if componentType is unknown
1858
+ }
1859
+ }
1860
+
1861
+
1862
+ /**
1863
+ * @param {GLTFAccessorType} type
1864
+ */
1865
+ function getElementSize(type) {
1866
+ switch (type) {
1867
+ case GLTFAccessorType.Scalar:
1868
+ return 1;
1869
+ case GLTFAccessorType.Vec2:
1870
+ return 2;
1871
+ case GLTFAccessorType.Vec3:
1872
+ return 3;
1873
+ case GLTFAccessorType.Vec4:
1874
+ return 4;
1875
+ case GLTFAccessorType.Mat2:
1876
+ return 4;
1877
+ case GLTFAccessorType.Mat3:
1878
+ return 9;
1879
+ case GLTFAccessorType.Mat4:
1880
+ return 16;
1881
+ default:
1882
+ return 0;;
1883
+ }
1884
+ }
1885
+
1886
+ /**
1887
+ * @param {number} mesh
1888
+ * @param {GLTFMesh[]} meshes
1889
+ * @param {[Mesh,number | undefined][][]} geometries
1890
+ * @param {StandardMaterial[]} materials
1891
+ */
1892
+ function parseMeshObject(mesh, meshes, geometries, materials) {
1893
+ const meshData = meshes[mesh]
1894
+ const geometry = geometries[mesh]
1895
+
1896
+ if (!meshData || !geometry) {
1897
+ throw "Invalid mesh index on node"
1898
+ }
1899
+ if (geometry.length === 1) {
1900
+ const item = /**@type {[Mesh,number | undefined]}*/(geometry[0])
1901
+ const material = item[1] !== undefined ? materials[item[1]] : defaultMaterial
1902
+
1903
+ return new MeshMaterial3D(item[0], material || defaultMaterial)
1904
+ }
1905
+ const root = new Object3D()
1906
+ for (let i = 0; i < geometry.length; i++) {
1907
+ const item = /**@type {[Mesh,number | undefined]}*/(geometry[i])
1908
+ const material = item[1] !== undefined ? materials[item[1]] : defaultMaterial
1909
+ const object = new MeshMaterial3D(item[0], material || defaultMaterial)
1910
+
1911
+ root.add(object)
1912
+ }
1913
+
1914
+ return root
1915
+ }
1916
+
1917
+ /**
1918
+ * @param {GLTFMesh} gltfMesh
1919
+ * @param {GLTF} gltf
1920
+ * @returns {[Mesh, number | undefined][]}
1921
+ */
1922
+ function parseGeometry(gltfMesh, gltf) {
1923
+ /**@type {[Mesh, number | undefined][]}*/
1924
+ const results = []
1925
+ for (let i = 0; i < gltfMesh.primitives.length; i++) {
1926
+ const primitive = /**@type {GLTFPrimitive} */ (gltfMesh.primitives[i])
1927
+ const attributes = new SeparateAttributeData()
1928
+ const mesh = new Mesh(attributes)
1929
+ if (primitive.indices !== undefined) {
1930
+ const [dataView, accessor] = getAccessorData(
1931
+ primitive.indices,
1932
+ gltf
1933
+ )
1934
+ mesh.indices = mapToIndices(accessor, dataView)
1935
+ }
1936
+ for (const [name, location] of primitive.attributes) {
1937
+ const [buffer, accessor] = getAccessorData(
1938
+ location,
1939
+ gltf
1940
+ )
1941
+ const attribute = mapAccessorTypeToAttribute(name, accessor, buffer)
1942
+ if (!attribute) continue
1943
+ const [attributeName, attributeBuffer] = attribute
1944
+ attributes.set(
1945
+ attributeName,
1946
+ attributeBuffer
1947
+ )
1948
+ }
1949
+
1950
+ mesh.normalizeJointWeights()
1951
+ results.push([mesh, primitive.material])
1952
+ }
1953
+ return results
1954
+ }
1955
+
1956
+ /**
1957
+ * @param {GLTFSkin} gltfSkin
1958
+ * @param {GLTF} gltf
1959
+ * @param {Map<number, Object3D>} entityMap
1960
+ * @returns {Skin}
1961
+ */
1962
+ function parseSkin(gltfSkin, gltf, entityMap) {
1963
+ const [bindPoseData] = getAccessorData(gltfSkin.inverseBindMatrices, gltf)
1964
+ const bindPose = convertToInverseBindPose(bindPoseData)
1965
+ const skin = new Skin()
1966
+
1967
+ if (bindPose.length !== gltfSkin.joints.length) {
1968
+ console.warn(
1969
+ "GLTF skin inverse bind matrix count does not match joint count",
1970
+ bindPose.length,
1971
+ gltfSkin.joints.length
1972
+ )
1973
+ }
1974
+
1975
+ skin.inverseBindPose = bindPose
1976
+ skin.bones = gltfSkin.joints.map(joint => {
1977
+ const entity = entityMap.get(joint)
1978
+ if (!(entity instanceof Bone3D)) {
1979
+ throw "One of the bones is not a `Bone3D`"
1980
+ }
1981
+
1982
+ return entity
1983
+ })
1984
+
1985
+ return skin
1986
+ }
1987
+
1988
+ /**
1989
+ *
1990
+ * @param {DataView} poseData
1991
+ * @returns {Affine3[]}
1992
+ */
1993
+ function convertToInverseBindPose(poseData) {
1994
+ const results = []
1995
+ const data = new Float32Array(
1996
+ poseData.buffer,
1997
+ poseData.byteOffset,
1998
+ poseData.byteLength / Float32Array.BYTES_PER_ELEMENT
1999
+ )
2000
+
2001
+ for (let offset = 0; offset < data.length; offset += 16) {
2002
+ // glTF stores matrices in column-major order. Affine3 expects the same
2003
+ // 3x4 affine components, with translation coming from the last column.
2004
+ const affine = new Affine3(
2005
+ data[offset + 0], data[offset + 4], data[offset + 8], data[offset + 12],
2006
+ data[offset + 1], data[offset + 5], data[offset + 9], data[offset + 13],
2007
+ data[offset + 2], data[offset + 6], data[offset + 10], data[offset + 14],
2008
+ )
2009
+
2010
+ results.push(affine)
2011
+ }
2012
+
2013
+ return results
2014
+ }
2015
+
2016
+ /**
2017
+ * @param {number} index
2018
+ * @param {GLTFNode} node
2019
+ * @param {GLTF} gltf
2020
+ * @param {[Mesh,number | undefined][][]} geometries
2021
+ * @param {StandardMaterial[]} materials
2022
+ */
2023
+ function parseObject(index, node, gltf, geometries, materials) {
2024
+ const { mesh, transform, name } = node
2025
+
2026
+ let object
2027
+ if (mesh !== undefined) {
2028
+ object = parseMeshObject(mesh, gltf.meshes, geometries, materials)
2029
+ } else {
2030
+ const bone = parseBone(index, gltf)
2031
+
2032
+ if (bone) {
2033
+ object = bone
2034
+ } else {
2035
+ object = new Object3D()
2036
+ }
2037
+ }
2038
+
2039
+ if (transform) {
2040
+ transferTransform(object, transform)
2041
+ }
2042
+
2043
+ object.name = name
2044
+
2045
+ return object
2046
+ }
2047
+
2048
+ /**
2049
+ * @param {number} index
2050
+ * @param {GLTF} gltf
2051
+ * @returns {Bone3D | undefined}
2052
+ */
2053
+ function parseBone(index, gltf) {
2054
+ for (const skin of gltf.skins) {
2055
+ const boneIndex = skin.joints.findIndex((v) => v === index)
2056
+ if (boneIndex !== -1) {
2057
+ const bone = new Bone3D()
2058
+ bone.index = boneIndex
2059
+ return bone
2060
+ }
2061
+ }
2062
+ return undefined
2063
+ }
2064
+
2065
+ /**
2066
+ * @param {Object3D} object
2067
+ * @param {TRSTransform | MatrixTransform} transform
2068
+ */
2069
+ function transferTransform(object, transform) {
2070
+ if (transform instanceof TRSTransform) {
2071
+ object.transform.position.x = transform.translation[0]
2072
+ object.transform.position.y = transform.translation[1]
2073
+ object.transform.position.z = transform.translation[2]
2074
+ object.transform.orientation.x = transform.rotation[0]
2075
+ object.transform.orientation.y = transform.rotation[1]
2076
+ object.transform.orientation.z = transform.rotation[2]
2077
+ object.transform.orientation.w = transform.rotation[3]
2078
+ object.transform.scale.x = transform.scale[0]
2079
+ object.transform.scale.y = transform.scale[1]
2080
+ object.transform.scale.z = transform.scale[2]
2081
+ }
2082
+ if (transform instanceof MatrixTransform) {
2083
+ throw "matrix transform not yet supported"
2084
+ }
2085
+ }
2086
+
2087
+ /**
2088
+ *
2089
+ * @param {TypedArray} from
2090
+ * @param {new (...args:any[])=>TypedArray} to
2091
+ * @returns
2092
+ */
2093
+ function widenTypedArray(from, to) {
2094
+ const result = new to(from.length);
2095
+ for (let i = 0; i < from.length; i++) {
2096
+ result[i] = /**@type {bigint | number}*/(from[i])
2097
+ }
2098
+ return result;
2099
+ }
2100
+
2101
+ /**
2102
+ * @param {VertexFormat} vertexFormat
2103
+ */
2104
+ function mapToGLTFComponentType(vertexFormat) {
2105
+ switch (vertexFormat) {
2106
+ case VertexFormat.Uint8:
2107
+ case VertexFormat.Uint8x2:
2108
+ case VertexFormat.Uint8x3:
2109
+ case VertexFormat.Uint8x4:
2110
+ case VertexFormat.Unorm8:
2111
+ case VertexFormat.Unorm8x2:
2112
+ case VertexFormat.Unorm8x3:
2113
+ case VertexFormat.Unorm8x4:
2114
+ return GLTFComponentType.UnsignedByte;
2115
+ case VertexFormat.Snorm8:
2116
+ case VertexFormat.Snorm8x2:
2117
+ case VertexFormat.Snorm8x3:
2118
+ case VertexFormat.Snorm8x4:
2119
+ case VertexFormat.Sint8:
2120
+ case VertexFormat.Sint8x2:
2121
+ case VertexFormat.Sint8x3:
2122
+ case VertexFormat.Sint8x4:
2123
+ return GLTFComponentType.Byte;
2124
+ case VertexFormat.Uint16:
2125
+ case VertexFormat.Uint16x2:
2126
+ case VertexFormat.Uint16x3:
2127
+ case VertexFormat.Uint16x4:
2128
+ case VertexFormat.Unorm16:
2129
+ case VertexFormat.Unorm16x2:
2130
+ case VertexFormat.Unorm16x3:
2131
+ case VertexFormat.Unorm16x4:
2132
+ return GLTFComponentType.UnsignedShort;
2133
+ case VertexFormat.Snorm16:
2134
+ case VertexFormat.Snorm16x2:
2135
+ case VertexFormat.Snorm16x3:
2136
+ case VertexFormat.Snorm16x4:
2137
+ case VertexFormat.Sint16:
2138
+ case VertexFormat.Sint16x2:
2139
+ case VertexFormat.Sint16x3:
2140
+ case VertexFormat.Sint16x4:
2141
+ return GLTFComponentType.Short;
2142
+ // 32-bit unsigned ints
2143
+ case VertexFormat.Uint32:
2144
+ case VertexFormat.Uint32x2:
2145
+ case VertexFormat.Uint32x3:
2146
+ case VertexFormat.Uint32x4:
2147
+ return GLTFComponentType.UnsignedInt;
2148
+
2149
+ // 32-bit signed ints
2150
+ case VertexFormat.Sint32:
2151
+ case VertexFormat.Sint32x2:
2152
+ case VertexFormat.Sint32x3:
2153
+ case VertexFormat.Sint32x4:
2154
+ return GLTFComponentType.Int;
2155
+ case VertexFormat.Float32:
2156
+ case VertexFormat.Float32x2:
2157
+ case VertexFormat.Float32x3:
2158
+ case VertexFormat.Float32x4:
2159
+ return GLTFComponentType.Float
2160
+ default:
2161
+ throw new Error('Unsupported vertex format: ' + vertexFormat);
2162
+ }
2163
+ }
2164
+
2165
+
2166
+ /**
2167
+ *@typedef {Int8Array | Uint8Array | Uint8ClampedArray | Int16Array | Uint16Array | Int32Array | Uint32Array | Float32Array | Float64Array | BigInt64Array | BigUint64Array} TypedArray
2168
+ */
2169
+
2170
+ /**
2171
+ * @typedef {[number, number, number, number, number, number, number, number, number, number, number, number, number, number, number, number]} MatrixArray
2172
+ */