XAvatarLoader.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357
  1. import Logger from "./Logger.js"
  2. const logger = new Logger('XAvatarLoader')
  3. export default class XAvatarLoader {
  4. constructor() {
  5. this.containers = new Map,
  6. this.meshes = new Map,
  7. this.animations = new Map,
  8. this.aniPath = new Map,
  9. this.binPath = new Map,
  10. this.texPath = new Map,
  11. this.matPath = new Map,
  12. this.mshPath = new Map,
  13. this.rootPath = new Map,
  14. this.meshTexList = new Map,
  15. this._enableIdb = !0,
  16. this._mappings = new Map,
  17. this._sharedTex = new Map,
  18. this.avaliableAnimation = new Map,
  19. this.enableShareTexture = !0,
  20. this.enableShareAnimation = !0,
  21. this.fillEmptyLod = !0,
  22. this.pendantMap = new Map;
  23. const e = new BABYLON.GLTFFileLoader;
  24. BABYLON.SceneLoader.RegisterPlugin(e),
  25. e.preprocessUrlAsync = function(i) {
  26. const o = avatarLoader._mappings.get(i);
  27. return o ? Promise.resolve(o) : Promise.resolve(i)
  28. }
  29. }
  30. _parsePendant(e, i) {
  31. if (!e || !i) {
  32. logger.error("[Engine] invalid id or url when loading pendant");
  33. return
  34. }
  35. const o = ".zip"
  36. , s = i.replace(o, "/");
  37. this.pendantMap.set(e, s)
  38. }
  39. pullAndLoadXObject(e, i) {
  40. const o = avatarLoader.pendantMap.get(i);
  41. return Tools.LoadFileAsync(o + `${i}.json`, !1).then(s=>{
  42. if (!(s instanceof ArrayBuffer))
  43. return LoadXObject(o, s).then(c=>c)
  44. }
  45. )
  46. }
  47. getParsedUrl(e, i, o, s="") {
  48. return new Promise((c,d)=>{
  49. if (!o || o.indexOf(".zip") === -1)
  50. return c(o);
  51. const _ = this.rootPath.get(o);
  52. if (_)
  53. return c(_);
  54. {
  55. const b = ".zip"
  56. , k = o.replace(b, "") + COMPONENT_LIST_PREFIX;
  57. e.urlTransformer(k, !0).then(j=>{
  58. if (!j)
  59. return d("Loading Failed");
  60. new Response(j).json().then($=>{
  61. var tt, rt, it, nt, ot, at, st;
  62. const _e = o.replace(b, "")
  63. , et = _e + ((tt = $ == null ? void 0 : $.components) == null ? void 0 : tt.url.replace("./", ""));
  64. if (this.rootPath.set(o, et),
  65. $.components ? ($.components.url && this.mshPath.set(i, _e + "/" + ((rt = $ == null ? void 0 : $.components) == null ? void 0 : rt.url.replace("./", ""))),
  66. $.components.url_lod2 && this.mshPath.set(i + "_" + avatarSetting.lod[1].level, _e + "/" + ((it = $ == null ? void 0 : $.components) == null ? void 0 : it.url_lod2.replace("./", ""))),
  67. $.components.url_lod4 && this.mshPath.set(i + "_" + avatarSetting.lod[2].level, _e + "/" + ((nt = $ == null ? void 0 : $.components) == null ? void 0 : nt.url_lod4.replace("./", "")))) : ($.meshes.url && this.mshPath.set(i, _e + "/" + ((ot = $ == null ? void 0 : $.meshes) == null ? void 0 : ot.url.replace("./", ""))),
  68. $.meshes.url_lod2 && this.mshPath.set(i + "_" + avatarSetting.lod[1].level, _e + "/" + ((at = $ == null ? void 0 : $.meshes) == null ? void 0 : at.url_lod2.replace("./", ""))),
  69. $.meshes.url_lod4 && this.mshPath.set(i + "_" + avatarSetting.lod[2].level, _e + "/" + ((st = $ == null ? void 0 : $.meshes) == null ? void 0 : st.url_lod4.replace("./", "")))),
  70. $.materials && $.materials.forEach(ut=>{
  71. const ct = _e + "/" + ut.url;
  72. this.matPath.set(ut.name, ct)
  73. }
  74. ),
  75. $.bin) {
  76. const ut = _e + "/" + $.bin.url;
  77. this.binPath.set(i, ut);
  78. const ct = _e + "/" + $.bin.url_lod2;
  79. this.binPath.set(i + "_" + avatarSetting.lod[1].level, ct);
  80. const lt = _e + "/" + $.bin.url_lod4;
  81. this.binPath.set(i + "_" + avatarSetting.lod[2].level, lt)
  82. }
  83. return $.textures && $.textures.forEach(ut=>{
  84. const ct = _e + "/" + ut.url;
  85. this.texPath.set(ut.url, ct);
  86. const lt = this.meshTexList.get($.components.url);
  87. ut.type === "png" && (lt ? lt.find(ft=>ft === ut.name) || lt.push(ut.url) : this.meshTexList.set(i, [ut.name]))
  88. }
  89. ),
  90. c(et)
  91. }
  92. ).catch($=>{
  93. d(`[Engine] parse json file error,${$}`)
  94. }
  95. )
  96. }
  97. ).catch(j=>{
  98. d(`[Engine] ulrtransform error, cannot find resource in db,${j}`)
  99. }
  100. )
  101. }
  102. }
  103. )
  104. }
  105. async parse(e, i) {
  106. const o = [];
  107. i.forEach(s=>{
  108. this._setAnimationList(s.id, s.animations),
  109. o.push(this.getParsedUrl(e, s.id, s.url)),
  110. s.components.forEach(c=>{
  111. c.name === "pendant" ? c.units.forEach(d=>{
  112. this._parsePendant(d.id, d.url)
  113. }
  114. ) : c.units.forEach(d=>{
  115. o.push(this.getParsedUrl(e, d.name, d.url))
  116. }
  117. )
  118. }
  119. )
  120. }
  121. ),
  122. await Promise.all(o)
  123. }
  124. _setAnimationList(e, i) {
  125. i ? i.forEach(o=>{
  126. this.aniPath.set(e + "_" + o.name, o.url)
  127. }
  128. ) : logger.error("[Engine] no animation list exist, please check config for details")
  129. }
  130. disposeContainer() {
  131. const e = [];
  132. this.containers.forEach((i,o)=>{
  133. if (i.xReferenceCount < 1) {
  134. if (this.enableShareTexture && i.textures.length > 0) {
  135. for (let s = 0; s < i.textures.length; ++s)
  136. i.textures[s].xReferenceCount != null ? i.textures[s].xReferenceCount-- : i.textures[s].xReferenceCount = 0,
  137. i.textures[s]._parentContainer = null;
  138. i.textures = []
  139. }
  140. e.push(o)
  141. }
  142. }
  143. ),
  144. e.forEach(i=>{
  145. var o, s;
  146. (o = this.containers.get(i)) == null || o.removeAllFromScene(),
  147. (s = this.containers.get(i)) == null || s.dispose(),
  148. this.containers.delete(i)
  149. }
  150. ),
  151. this._sharedTex.forEach((i,o)=>{
  152. i.xReferenceCount == 0 && (i.dispose(),
  153. this._sharedTex.delete(o))
  154. }
  155. )
  156. }
  157. set enableIdb(e) {
  158. this._enableIdb = e
  159. }
  160. getGlbPath(e) {
  161. return this.aniPath.get(e + ".glb")
  162. }
  163. getGltfPath(e) {
  164. return this.mshPath.get(e + ".gltf")
  165. }
  166. getPngUrl(e) {
  167. return this.texPath.get(e + ".png")
  168. }
  169. getMeshUrl(e) {
  170. return this.mshPath.get(e)
  171. }
  172. _getSourceKey(e, i) {
  173. return i && avatarSetting.lod[i] ? e + avatarSetting.lod[i].fileName.split(".")[0] : e
  174. }
  175. _getAnimPath(e, i) {
  176. let o = this.aniPath.get(i + "_animations_" + i.split("_")[1]);
  177. return o || (o = this.aniPath.get(i + "_" + e)),
  178. o
  179. }
  180. load(e, i, o, s) {
  181. return this.loadGlb(e, i, o).then(c=>c || Promise.reject("[Engine] container load failed")).catch(()=>Promise.reject("[Engine] container load failed"))
  182. }
  183. _searchAnimation(e, i) {
  184. let o;
  185. return this.containers.forEach((s,c)=>{
  186. const d = i.split("_")[0];
  187. c.indexOf(d) != -1 && c.indexOf(e) != -1 && (o = s)
  188. }
  189. ),
  190. o
  191. }
  192. loadAnimRes(e, i, o) {
  193. const s = this._getAnimPath(i, o)
  194. , c = getAnimationKey(i, o);
  195. return s && this.containers.get(s) ? Promise.resolve(this.containers.get(s)) : s ? this._loadGlbFromBlob(e, c, s).then(d=>d.animationGroups.length == 0 ? (this.containers.delete(c),
  196. d.dispose(),
  197. Promise.reject("container does not contains animation data")) : d) : Promise.reject("no such url")
  198. }
  199. loadGlb(e, i, o) {
  200. let s = this.getMeshUrl(this._getSourceKey(i, o));
  201. return !s && this.fillEmptyLod && (o = 0,
  202. s = this.getMeshUrl(this._getSourceKey(i, o))),
  203. s && this.containers.get(s) ? Promise.resolve(this.containers.get(s)) : s ? this._enableIdb ? this._loadGlbFromBlob(e, this._getSourceKey(i, o), s) : this._loadGlbFromUrl(e, this._getSourceKey(i, o), s) : Promise.reject("no such url")
  204. }
  205. loadGltf(e, i, o, s) {
  206. const c = this._getSourceKey(i, o || 0);
  207. let d = this.getGltfPath(c);
  208. return !d && this.fillEmptyLod && (d = this.getGltfPath(i)),
  209. d && this.containers.get(d) ? Promise.resolve(this.containers.get(d)) : this._enableIdb ? this._loadGltfFromBlob(e, i, o, s) : d ? this._loadGltfFromUrl(e, i, d.replace(i + ".gltf", "")) : Promise.reject()
  210. }
  211. loadSubsequence() {}
  212. loadVAT() {}
  213. getResourceName(e) {
  214. return this.meshTexList.get(e)
  215. }
  216. _loadGltfFromUrl(e, i, o) {
  217. return BABYLON.SceneLoader.LoadAssetContainerAsync(o, i + ".gltf", e.Scene, null, ".gltf")
  218. }
  219. _loadGlbFromBlob(e, i, o) {
  220. return e.urlTransformer(o).then(s=>BABYLON.SceneLoader.LoadAssetContainerAsync("", s, e.Scene, null, ".glb").then(c=>{
  221. if (c) {
  222. if (this.containers.get(o))
  223. return c.dispose(),
  224. this.containers.get(o);
  225. if (c.addAllToScene(),
  226. this.enableShareTexture && c.textures.length > 0) {
  227. const d = [];
  228. let _ = !1;
  229. c.meshes.forEach(b=>{
  230. if (b.material) {
  231. const k = b.material._albedoTexture;
  232. if (k) {
  233. let j = k.name;
  234. j = j.replace(" (Base Color)", "").split(".")[0];
  235. const $ = this._sharedTex.get(j);
  236. $ ? (_ = !0,
  237. b.material._albedoTexture = $,
  238. d.push($),
  239. $._parentContainer = c,
  240. $.xReferenceCount++) : (this._sharedTex.set(j, k),
  241. c.textures[0].xReferenceCount = 1)
  242. }
  243. }
  244. }
  245. ),
  246. _ && (c.textures.forEach(b=>{
  247. e.Scene.removeTexture(b),
  248. b.dispose()
  249. }
  250. ),
  251. c.textures = d)
  252. }
  253. return c.xReferenceCount = 0,
  254. c.meshes.forEach(d=>{
  255. d.setEnabled(!1)
  256. }
  257. ),
  258. this.containers.set(o, c),
  259. Promise.resolve(c)
  260. } else
  261. return Promise.reject("glb file load failed")
  262. }
  263. ))
  264. }
  265. _loadGlbFromUrl(e, i, o) {
  266. return BABYLON.SceneLoader.LoadAssetContainerAsync("", o, e.Scene, null, ".glb").then(s=>s ? (s.addAllToScene(),
  267. s.meshes.forEach(c=>{
  268. c.setEnabled(!1)
  269. }
  270. ),
  271. this.enableShareTexture && s.textures.length > 0 ? (s.meshes.forEach(c=>{
  272. if (c.material) {
  273. const d = c.material._albedoTexture;
  274. if (d) {
  275. let _ = d.name;
  276. _ = _.replace(" (Base Color)", "").split(".")[0];
  277. const b = this._sharedTex.get(_);
  278. b ? (c.material._albedoTexture = b,
  279. b.xReferenceCount++) : (this._sharedTex.set(_, d),
  280. s.textures[0].xReferenceCount = 1)
  281. }
  282. }
  283. }
  284. ),
  285. s.xReferenceCount = 0,
  286. this.containers.set(o, s),
  287. Promise.resolve(s)) : Promise.reject("glb file load failed"),
  288. s.xReferenceCount = 0,
  289. this.containers.set(o, s),
  290. Promise.resolve(s)) : Promise.reject("glb file load failed"))
  291. }
  292. _loadGltfFromBlob(e, i, o, s) {
  293. return new Promise((c,d)=>{
  294. const _ = [];
  295. let b = this._getSourceKey(i, o)
  296. , k = this.getGltfPath(b);
  297. if (!k && this.fillEmptyLod && (o = 0,
  298. b = this._getSourceKey(i, o),
  299. k = this.getGltfPath(b)),
  300. !k)
  301. return d(`[Engine] gltf path incorrect ${b},cancel.`);
  302. const j = this.mshPath.get(b + ".gltf");
  303. if (!j)
  304. return d("cannot find asset mshPath");
  305. const $ = this.binPath.get(b + ".bin");
  306. if (!$)
  307. return d("cannot find asset binPath");
  308. if (!s) {
  309. const tt = this.meshTexList.get(i);
  310. if (!tt || tt.length == 0)
  311. return d("cannot find texture");
  312. s = tt[0]
  313. }
  314. const _e = this.texPath.get(s + ".png");
  315. if (!_e)
  316. return d();
  317. const et = this.texPath.get(s + "-astc.ktx");
  318. if (!et)
  319. return d();
  320. _.push(this._blobMapping(e, j)),
  321. _.push(this._blobMapping(e, $)),
  322. _.push(this._blobMapping(e, _e)),
  323. _.push(this._blobMapping(e, et)),
  324. Promise.all(_).then(()=>{
  325. const tt = k.replace(b + ".gltf", "");
  326. BABYLON.SceneLoader.LoadAssetContainerAsync(tt, b + ".gltf", e.Scene, null, ".gltf").then(rt=>{
  327. var nt;
  328. this.containers.set(k, rt),
  329. rt.addAllToScene(),
  330. rt.meshes.forEach(ot=>{
  331. ot.setEnabled(!1)
  332. }
  333. );
  334. const it = this._sharedTex.get(i);
  335. it ? ((nt = rt.meshes[1].material._albedoTexture) == null || nt.dispose(),
  336. rt.meshes[1].material._albedoTexture = it) : this._sharedTex.set(i, rt.meshes[1].material._albedoTexture),
  337. c(rt)
  338. }
  339. )
  340. }
  341. )
  342. }
  343. )
  344. }
  345. _blobMapping(e, i) {
  346. return new Promise((o,s)=>{
  347. e.urlTransformer(i).then(c=>c ? (this._mappings.set(i, c),
  348. o(i)) : s(`[Engine] url urlTransformer parse error ${i}`))
  349. }
  350. )
  351. }
  352. }
  353. const avatarLoader = new XAvatarLoader();
  354. export { avatarLoader };