@galacean/effects-plugin-ktx2 2.9.0-alpha.2 → 2.9.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.
package/dist/index.js CHANGED
@@ -3,7 +3,7 @@
3
3
  * Description: Galacean Effects player Khronos Texture 2.0 plugin
4
4
  * Author: Ant Group CO., Ltd.
5
5
  * Contributors: 澄弈
6
- * Version: v2.9.0-alpha.2
6
+ * Version: v2.9.0
7
7
  */
8
8
 
9
9
  'use strict';
@@ -59,6 +59,96 @@ function _async_to_generator(fn) {
59
59
  };
60
60
  }
61
61
 
62
+ function _set_prototype_of(o, p) {
63
+ _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
64
+ o.__proto__ = p;
65
+ return o;
66
+ };
67
+ return _set_prototype_of(o, p);
68
+ }
69
+
70
+ function _inherits(subClass, superClass) {
71
+ if (typeof superClass !== "function" && superClass !== null) {
72
+ throw new TypeError("Super expression must either be null or a function");
73
+ }
74
+ subClass.prototype = Object.create(superClass && superClass.prototype, {
75
+ constructor: {
76
+ value: subClass,
77
+ writable: true,
78
+ configurable: true
79
+ }
80
+ });
81
+ if (superClass) _set_prototype_of(subClass, superClass);
82
+ }
83
+
84
+ function _is_native_reflect_construct() {
85
+ // Since Reflect.construct can't be properly polyfilled, some
86
+ // implementations (e.g. core-js@2) don't set the correct internal slots.
87
+ // Those polyfills don't allow us to subclass built-ins, so we need to
88
+ // use our fallback implementation.
89
+ try {
90
+ // If the internal slots aren't set, this throws an error similar to
91
+ // TypeError: this is not a Boolean object.
92
+ var result = !Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function() {}));
93
+ } catch (_) {}
94
+ return (_is_native_reflect_construct = function _is_native_reflect_construct() {
95
+ return !!result;
96
+ })();
97
+ }
98
+
99
+ function _construct(Parent, args, Class) {
100
+ if (_is_native_reflect_construct()) _construct = Reflect.construct;
101
+ else {
102
+ _construct = function construct(Parent, args, Class) {
103
+ var a = [
104
+ null
105
+ ];
106
+ a.push.apply(a, args);
107
+ var Constructor = Function.bind.apply(Parent, a);
108
+ var instance = new Constructor();
109
+ if (Class) _set_prototype_of(instance, Class.prototype);
110
+ return instance;
111
+ };
112
+ }
113
+ return _construct.apply(null, arguments);
114
+ }
115
+
116
+ function _get_prototype_of(o) {
117
+ _get_prototype_of = Object.setPrototypeOf ? Object.getPrototypeOf : function getPrototypeOf(o) {
118
+ return o.__proto__ || Object.getPrototypeOf(o);
119
+ };
120
+ return _get_prototype_of(o);
121
+ }
122
+
123
+ function _is_native_function(fn) {
124
+ return Function.toString.call(fn).indexOf("[native code]") !== -1;
125
+ }
126
+
127
+ function _wrap_native_super(Class) {
128
+ var _cache = typeof Map === "function" ? new Map() : undefined;
129
+ _wrap_native_super = function _wrap_native_super(Class) {
130
+ if (Class === null || !_is_native_function(Class)) return Class;
131
+ if (typeof Class !== "function") throw new TypeError("Super expression must either be null or a function");
132
+ if (typeof _cache !== "undefined") {
133
+ if (_cache.has(Class)) return _cache.get(Class);
134
+ _cache.set(Class, Wrapper);
135
+ }
136
+ function Wrapper() {
137
+ return _construct(Class, arguments, _get_prototype_of(this).constructor);
138
+ }
139
+ Wrapper.prototype = Object.create(Class.prototype, {
140
+ constructor: {
141
+ value: Wrapper,
142
+ enumerable: false,
143
+ writable: true,
144
+ configurable: true
145
+ }
146
+ });
147
+ return _set_prototype_of(Wrapper, Class);
148
+ };
149
+ return _wrap_native_super(Class);
150
+ }
151
+
62
152
  function __generator(thisArg, body) {
63
153
  var _ = {
64
154
  label: 0,
@@ -157,7 +247,6 @@ typeof SuppressedError === "function" ? SuppressedError : function _SuppressedEr
157
247
 
158
248
  /**
159
249
  * KTX2 transcode target format.
160
- * if you modify this file, please also modify KTX2TargetFormat in binomial-workercode.ts
161
250
  */ var KTX2TargetFormat;
162
251
  (function(KTX2TargetFormat) {
163
252
  /** RGB(A) compressed format, 128 bits per 4x4 pixel block. */ KTX2TargetFormat[KTX2TargetFormat["ASTC"] = 0] = "ASTC";
@@ -184,6 +273,41 @@ function _create_class(Constructor, protoProps, staticProps) {
184
273
  return Constructor;
185
274
  }
186
275
 
276
+ function _array_like_to_array(arr, len) {
277
+ if (len == null || len > arr.length) len = arr.length;
278
+ for(var i = 0, arr2 = new Array(len); i < len; i++)arr2[i] = arr[i];
279
+ return arr2;
280
+ }
281
+
282
+ function _unsupported_iterable_to_array(o, minLen) {
283
+ if (!o) return;
284
+ if (typeof o === "string") return _array_like_to_array(o, minLen);
285
+ var n = Object.prototype.toString.call(o).slice(8, -1);
286
+ if (n === "Object" && o.constructor) n = o.constructor.name;
287
+ if (n === "Map" || n === "Set") return Array.from(n);
288
+ if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _array_like_to_array(o, minLen);
289
+ }
290
+
291
+ function _create_for_of_iterator_helper_loose(o, allowArrayLike) {
292
+ var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"];
293
+ if (it) return (it = it.call(o)).next.bind(it);
294
+ // Fallback for engines without symbol support
295
+ if (Array.isArray(o) || (it = _unsupported_iterable_to_array(o)) || allowArrayLike && o && typeof o.length === "number") {
296
+ if (it) o = it;
297
+ var i = 0;
298
+ return function() {
299
+ if (i >= o.length) return {
300
+ done: true
301
+ };
302
+ return {
303
+ done: false,
304
+ value: o[i++]
305
+ };
306
+ };
307
+ }
308
+ throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.");
309
+ }
310
+
187
311
  /**
188
312
  * @internal
189
313
  * WorkerPool, T 为发送消息的类型,U 为返回值的类型。
@@ -204,7 +328,7 @@ function _create_class(Constructor, protoProps, staticProps) {
204
328
  var _proto = WorkerPool.prototype;
205
329
  _proto.prepareWorker = function prepareWorker() {
206
330
  var count = this.limitedCount;
207
- var promises = new Array(count);
331
+ var promises = [];
208
332
  for(var i = 0; i < count; i++){
209
333
  promises.push(this.ensureWorker(i));
210
334
  }
@@ -552,6 +676,16 @@ var KTX2Container = /*#__PURE__*/ function() {
552
676
  this.parse(buffer);
553
677
  }
554
678
  var _proto = KTX2Container.prototype;
679
+ /**
680
+ * 释放内部持有的原始二进制数据引用
681
+ */ _proto.clear = function clear() {
682
+ for(var _iterator = _create_for_of_iterator_helper_loose(this.levels), _step; !(_step = _iterator()).done;){
683
+ var level = _step.value;
684
+ level.levelData = null;
685
+ }
686
+ this.levels.length = 0;
687
+ this.globalData = null;
688
+ };
555
689
  _proto.parse = function parse(data) {
556
690
  var KTX2_IDENTIFIER = new Uint8Array([
557
691
  0xAB,
@@ -739,28 +873,6 @@ var KTX2Container = /*#__PURE__*/ function() {
739
873
  return KTX2Container;
740
874
  }();
741
875
 
742
- function _set_prototype_of(o, p) {
743
- _set_prototype_of = Object.setPrototypeOf || function setPrototypeOf(o, p) {
744
- o.__proto__ = p;
745
- return o;
746
- };
747
- return _set_prototype_of(o, p);
748
- }
749
-
750
- function _inherits(subClass, superClass) {
751
- if (typeof superClass !== "function" && superClass !== null) {
752
- throw new TypeError("Super expression must either be null or a function");
753
- }
754
- subClass.prototype = Object.create(superClass && superClass.prototype, {
755
- constructor: {
756
- value: subClass,
757
- writable: true,
758
- configurable: true
759
- }
760
- });
761
- if (superClass) _set_prototype_of(subClass, superClass);
762
- }
763
-
764
876
  /* eslint-disable compat/compat */ /* eslint-disable promise/no-nesting */ /**
765
877
  * 转码核心代码
766
878
  * 主线程调用时会返回 API 对象
@@ -770,27 +882,38 @@ function _inherits(subClass, superClass) {
770
882
  /**
771
883
  * ZSTD (Zstandard) decoder.
772
884
  */ var ZSTDDecoder = /*#__PURE__*/ function() {
773
- function ZSTDDecoder() {}
885
+ function ZSTDDecoder() {
886
+ var _this = this;
887
+ this.heap = new Uint8Array(0);
888
+ this.instance = null;
889
+ this.importObject = {
890
+ env: {
891
+ emscripten_notify_memory_growth: function() {
892
+ _this.heap = new Uint8Array(_this.instance.exports.memory.buffer);
893
+ }
894
+ }
895
+ };
896
+ }
774
897
  var _proto = ZSTDDecoder.prototype;
775
898
  _proto.init = function init(zstddecWasmModule) {
899
+ var _this = this;
776
900
  if (!this.initPromise) {
777
- this.initPromise = WebAssembly.instantiate(zstddecWasmModule, ZSTDDecoder.IMPORT_OBJECT).then(this.initInstance);
901
+ this.initPromise = WebAssembly.instantiate(zstddecWasmModule, this.importObject).then(function(result) {
902
+ _this.instance = result;
903
+ _this.importObject.env.emscripten_notify_memory_growth();
904
+ });
778
905
  }
779
906
  return this.initPromise;
780
907
  };
781
- _proto.initInstance = function initInstance(result) {
782
- ZSTDDecoder.instance = result;
783
- ZSTDDecoder.IMPORT_OBJECT.env.emscripten_notify_memory_growth();
784
- };
785
908
  _proto.decode = function decode(array, uncompressedSize) {
786
909
  if (uncompressedSize === void 0) uncompressedSize = 0;
787
- if (!ZSTDDecoder.instance) {
910
+ if (!this.instance) {
788
911
  throw new Error("ZSTDDecoder: Await .init() before decoding.");
789
912
  }
790
- var exports = ZSTDDecoder.instance.exports;
913
+ var exports = this.instance.exports;
791
914
  var compressedSize = array.byteLength;
792
915
  var compressedPtr = exports.malloc(compressedSize);
793
- ZSTDDecoder.heap.set(array, compressedPtr);
916
+ this.heap.set(array, compressedPtr);
794
917
  uncompressedSize = uncompressedSize || Number(exports.ZSTD_findDecompressedSize(compressedPtr, compressedSize));
795
918
  var uncompressedPtr = exports.malloc(uncompressedSize);
796
919
  var actualSize = exports.ZSTD_decompress(uncompressedPtr, uncompressedSize, compressedPtr, compressedSize);
@@ -800,20 +923,13 @@ function _inherits(subClass, superClass) {
800
923
  throw new Error("ZSTDDecoder: decompression failed.");
801
924
  }
802
925
  // Read decompressed data and free WASM memory
803
- var dec = ZSTDDecoder.heap.slice(uncompressedPtr, uncompressedPtr + actualSize);
926
+ var dec = this.heap.slice(uncompressedPtr, uncompressedPtr + actualSize);
804
927
  exports.free(compressedPtr);
805
928
  exports.free(uncompressedPtr);
806
929
  return dec;
807
930
  };
808
931
  return ZSTDDecoder;
809
932
  }();
810
- ZSTDDecoder.IMPORT_OBJECT = {
811
- env: {
812
- emscripten_notify_memory_growth: function emscripten_notify_memory_growth() {
813
- ZSTDDecoder.heap = new Uint8Array(ZSTDDecoder.instance.exports.memory.buffer);
814
- }
815
- }
816
- };
817
933
  function transcodeASTC(wasmTranscoder, compressedData, width, height) {
818
934
  var nBlocks = (width + 3 >> 2) * (height + 3 >> 2);
819
935
  var texMemoryPages = nBlocks * 16 + 65535 >> 16;
@@ -882,35 +998,45 @@ function _inherits(subClass, superClass) {
882
998
  return result;
883
999
  });
884
1000
  }
885
- self.onmessage = function onmessage(event) {
886
- var message = event.data;
887
- switch(message.type){
888
- case "init":
889
- initTranscoder(message.transcoderWasm).then(function() {
890
- self.postMessage("init-completed");
891
- }).catch(function(error) {
892
- self.postMessage({
893
- error: error
894
- });
895
- });
896
- break;
897
- case "transcode":
898
- wasmPromise.then(function(transcoderWasmModule) {
899
- transcode(message.data, message.needZstd, transcoderWasmModule, message.zstddecWasmModule).then(function(decodedData) {
900
- self.postMessage(decodedData);
1001
+ // 仅在 Worker 环境中注册消息处理,避免在主线程调用时污染 window.onmessage
1002
+ // Worker 环境中没有 window 对象
1003
+ if (typeof window === "undefined") {
1004
+ self.onmessage = function onmessage(event) {
1005
+ var message = event.data;
1006
+ switch(message.type){
1007
+ case "init":
1008
+ initTranscoder(message.transcoderWasm).then(function() {
1009
+ self.postMessage("init-completed");
901
1010
  }).catch(function(error) {
902
- return self.postMessage({
1011
+ self.postMessage({
903
1012
  error: error
904
1013
  });
905
1014
  });
906
- }).catch(function(error) {
907
- self.postMessage({
908
- error: error
1015
+ break;
1016
+ case "transcode":
1017
+ if (!wasmPromise) {
1018
+ self.postMessage({
1019
+ error: new Error("Transcoder not initialized.")
1020
+ });
1021
+ break;
1022
+ }
1023
+ wasmPromise.then(function(transcoderWasmModule) {
1024
+ transcode(message.data, message.needZstd, transcoderWasmModule, message.zstddecWasmModule).then(function(decodedData) {
1025
+ self.postMessage(decodedData);
1026
+ }).catch(function(error) {
1027
+ return self.postMessage({
1028
+ error: error
1029
+ });
1030
+ });
1031
+ }).catch(function(error) {
1032
+ self.postMessage({
1033
+ error: error
1034
+ });
909
1035
  });
910
- });
911
- break;
912
- }
913
- };
1036
+ break;
1037
+ }
1038
+ };
1039
+ }
914
1040
  // 主线程使用
915
1041
  return {
916
1042
  ZSTDDecoder: ZSTDDecoder,
@@ -1055,7 +1181,7 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1055
1181
  _proto.initTranscodeWorkerPool = function initTranscodeWorkerPool() {
1056
1182
  var _this = this;
1057
1183
  return _async_to_generator(function() {
1058
- var transcoderWasm, funcCode, funcBody, returnIndex, workerCode, workerURL;
1184
+ var transcoderWasm, workerEntryCode, workerURL;
1059
1185
  return __generator(this, function(_state) {
1060
1186
  switch(_state.label){
1061
1187
  case 0:
@@ -1081,13 +1207,10 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1081
1207
  ];
1082
1208
  case 3:
1083
1209
  transcoderWasm = _state.sent();
1084
- funcCode = TranscodeWorkerCode.toString();
1085
- funcBody = funcCode.substring(funcCode.indexOf("{") + 1, funcCode.lastIndexOf("}"));
1086
- // 移除主线程的 return 语句,添加 Worker 消息处理
1087
- returnIndex = funcBody.lastIndexOf("return {");
1088
- workerCode = funcBody.substring(0, returnIndex);
1210
+ // TranscodeWorkerCode 整体序列化
1211
+ workerEntryCode = "\n (" + TranscodeWorkerCode.toString() + ")();\n ";
1089
1212
  workerURL = URL.createObjectURL(new Blob([
1090
- workerCode
1213
+ workerEntryCode
1091
1214
  ], {
1092
1215
  type: "application/javascript"
1093
1216
  }));
@@ -1100,17 +1223,21 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1100
1223
  });
1101
1224
  })();
1102
1225
  };
1103
- _proto.transcode = function transcode(ktx2Container) {
1226
+ _proto.transcode = function transcode(ktx2Container, neededLevelCount) {
1104
1227
  var _this = this;
1105
1228
  return _async_to_generator(function() {
1106
- var needZstd, levelCount, faceCount, encodedData, faceIndex, mipmapData, mipmapIndex, level, levelWidth, levelHeight, originBuffer, originOffset, originByteLength, zstddecWasmModule, _tmp, faces, postMessageData;
1229
+ var needZstd, availableLevelCount, levelCount, faceCount, encodedData, faceIndex, mipmapData, mipmapIndex, level, levelWidth, levelHeight, originBuffer, originOffset, originByteLength, zstddecWasmModule, _tmp, faces, postMessageData;
1107
1230
  return __generator(this, function(_state) {
1108
1231
  switch(_state.label){
1109
1232
  case 0:
1110
1233
  needZstd = ktx2Container.supercompressionScheme === SupercompressionScheme.Zstd;
1111
- levelCount = ktx2Container.levels.length;
1234
+ availableLevelCount = ktx2Container.levels.length;
1235
+ levelCount = neededLevelCount != null ? neededLevelCount : availableLevelCount;
1236
+ if (levelCount < 1 || levelCount > availableLevelCount) {
1237
+ throw new Error("neededLevelCount " + levelCount + " is out of range [1, " + availableLevelCount + "].");
1238
+ }
1112
1239
  faceCount = ktx2Container.faceCount;
1113
- // 准备编码数据
1240
+ // 准备编码数据,只处理需要的 level,避免转码后丢弃多余结果
1114
1241
  encodedData = new Array(faceCount);
1115
1242
  for(faceIndex = 0; faceIndex < faceCount; faceIndex++){
1116
1243
  mipmapData = new Array(levelCount);
@@ -1165,6 +1292,9 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1165
1292
  ];
1166
1293
  case 5:
1167
1294
  // WebWorker 模式
1295
+ if (!_this.transcodeWorkerPool) {
1296
+ throw new Error("KhronosTranscoder: transcodeWorkerPool is not initialized.");
1297
+ }
1168
1298
  postMessageData = {
1169
1299
  type: "transcode",
1170
1300
  format: 0,
@@ -1210,14 +1340,32 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1210
1340
  }(TextureTranscoder);
1211
1341
 
1212
1342
  /**
1213
- * KTX2 加载器 - 专用于 UASTC 转 ASTC
1214
- */ var KTX2Loader = /*#__PURE__*/ function() {
1343
+ * KTX2 加载器插件
1344
+ */ var KTX2Loader = /*#__PURE__*/ function(Plugin) {
1345
+ _inherits(KTX2Loader, Plugin);
1215
1346
  function KTX2Loader(workerCount) {
1216
1347
  if (workerCount === void 0) workerCount = 0;
1217
- this.workerCount = workerCount;
1218
- this.khronosTranscoder = null;
1348
+ var _this;
1349
+ _this = Plugin.call(this) || this;
1350
+ _this.workerCount = workerCount;
1351
+ _this.khronosTranscoder = null;
1352
+ return _this;
1219
1353
  }
1220
1354
  var _proto = KTX2Loader.prototype;
1355
+ _proto.onAssetsLoadStart = function onAssetsLoadStart(_scene, _options) {
1356
+ var _this = this;
1357
+ return _async_to_generator(function() {
1358
+ return __generator(this, function(_state) {
1359
+ // 仅在未手动注册时才自动注册,避免覆盖用户通过 registerKTX2Loader(workerCount) 的自定义配置
1360
+ if (!EFFECTS.textureLoaderRegistry.has("ktx2")) {
1361
+ registerKTX2Loader(_this.workerCount);
1362
+ }
1363
+ return [
1364
+ 2
1365
+ ];
1366
+ });
1367
+ })();
1368
+ };
1221
1369
  /**
1222
1370
  * 初始化 Khronos Transcoder
1223
1371
  */ _proto.initKhronosTranscoder = function initKhronosTranscoder() {
@@ -1305,7 +1453,7 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1305
1453
  */ _proto.loadFromBuffer = function loadFromBuffer(arrBuffer) {
1306
1454
  var _this = this;
1307
1455
  return _async_to_generator(function() {
1308
- var buffer, _ref, ktx2Container, result;
1456
+ var buffer, _ref, ktx2Container, result, hasFullMipmapChain, textureOptions;
1309
1457
  return __generator(this, function(_state) {
1310
1458
  switch(_state.label){
1311
1459
  case 0:
@@ -1315,10 +1463,13 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1315
1463
  _this.parseBuffer(buffer)
1316
1464
  ];
1317
1465
  case 1:
1318
- _ref = _state.sent(), ktx2Container = _ref.ktx2Container, result = _ref.result;
1466
+ _ref = _state.sent(), ktx2Container = _ref.ktx2Container, result = _ref.result, hasFullMipmapChain = _ref.hasFullMipmapChain;
1467
+ textureOptions = _this.createTextureByBuffer(ktx2Container, result, hasFullMipmapChain);
1468
+ // 转码完成后释放原始 KTX2 数据
1469
+ ktx2Container.clear();
1319
1470
  return [
1320
1471
  2,
1321
- _this.createTextureByBuffer(ktx2Container, result)
1472
+ textureOptions
1322
1473
  ];
1323
1474
  }
1324
1475
  });
@@ -1329,7 +1480,7 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1329
1480
  */ _proto.loadFromURL = function loadFromURL(url) {
1330
1481
  var _this = this;
1331
1482
  return _async_to_generator(function() {
1332
- var buffer, _, _ref, ktx2Container, result;
1483
+ var buffer, _, _ref, ktx2Container, result, hasFullMipmapChain, textureOptions;
1333
1484
  return __generator(this, function(_state) {
1334
1485
  switch(_state.label){
1335
1486
  case 0:
@@ -1348,10 +1499,13 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1348
1499
  _this.parseBuffer(buffer)
1349
1500
  ];
1350
1501
  case 2:
1351
- _ref = _state.sent(), ktx2Container = _ref.ktx2Container, result = _ref.result;
1502
+ _ref = _state.sent(), ktx2Container = _ref.ktx2Container, result = _ref.result, hasFullMipmapChain = _ref.hasFullMipmapChain;
1503
+ textureOptions = _this.createTextureByBuffer(ktx2Container, result, hasFullMipmapChain);
1504
+ // 转码完成后释放原始 KTX2 数据
1505
+ ktx2Container.clear();
1352
1506
  return [
1353
1507
  2,
1354
- _this.createTextureByBuffer(ktx2Container, result)
1508
+ textureOptions
1355
1509
  ];
1356
1510
  }
1357
1511
  });
@@ -1359,11 +1513,11 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1359
1513
  };
1360
1514
  /**
1361
1515
  * @internal
1362
- * 解析并转码 KTX2 文件
1516
+ * 解析并转码 KTX2 文件 - 专用于 UASTC 转 ASTC
1363
1517
  */ _proto.parseBuffer = function parseBuffer(buffer) {
1364
1518
  var _this = this;
1365
1519
  return _async_to_generator(function() {
1366
- var ktx2Container, transcoder, result;
1520
+ var ktx2Container, pixelWidth, pixelHeight, maxDimension, availableLevelCount, fullChainCount, hasFullMipmapChain, neededLevelCount, transcoder, result;
1367
1521
  return __generator(this, function(_state) {
1368
1522
  switch(_state.label){
1369
1523
  case 0:
@@ -1372,6 +1526,13 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1372
1526
  if (!ktx2Container.isUASTC) {
1373
1527
  throw new Error("Unsupported KTX2: only UASTC format is supported");
1374
1528
  }
1529
+ // 提前判断需要转码的 level 数量,避免转码后丢弃多余结果
1530
+ pixelWidth = ktx2Container.pixelWidth, pixelHeight = ktx2Container.pixelHeight;
1531
+ maxDimension = Math.max(pixelWidth, pixelHeight);
1532
+ availableLevelCount = ktx2Container.levels.length;
1533
+ fullChainCount = maxDimension > 0 ? Math.floor(Math.log2(maxDimension)) + 1 : 1;
1534
+ hasFullMipmapChain = availableLevelCount > 1 && availableLevelCount >= fullChainCount;
1535
+ neededLevelCount = hasFullMipmapChain ? availableLevelCount : 1;
1375
1536
  return [
1376
1537
  4,
1377
1538
  _this.ensureKhronosTranscoder()
@@ -1380,7 +1541,7 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1380
1541
  transcoder = _state.sent();
1381
1542
  return [
1382
1543
  4,
1383
- transcoder.transcode(ktx2Container)
1544
+ transcoder.transcode(ktx2Container, neededLevelCount)
1384
1545
  ];
1385
1546
  case 2:
1386
1547
  result = _state.sent();
@@ -1388,7 +1549,8 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1388
1549
  2,
1389
1550
  {
1390
1551
  ktx2Container: ktx2Container,
1391
- result: result
1552
+ result: result,
1553
+ hasFullMipmapChain: hasFullMipmapChain
1392
1554
  }
1393
1555
  ];
1394
1556
  }
@@ -1398,21 +1560,19 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1398
1560
  /**
1399
1561
  * @internal
1400
1562
  * 根据转码结果创建引擎所需的压缩纹理源选项
1401
- */ _proto.createTextureByBuffer = function createTextureByBuffer(ktx2Container, transcodeResult) {
1563
+ * @param hasFullMipmapChain - 是否包含完整 mipmap 链(由 parseBuffer 提前判断)
1564
+ */ _proto.createTextureByBuffer = function createTextureByBuffer(ktx2Container, transcodeResult, hasFullMipmapChain) {
1402
1565
  var _faces_;
1403
1566
  var pixelWidth = ktx2Container.pixelWidth, pixelHeight = ktx2Container.pixelHeight, faceCount = ktx2Container.faceCount;
1404
1567
  var _this_getASTC4x4TextureDetail = this.getASTC4x4TextureDetail(), internalFormat = _this_getASTC4x4TextureDetail.internalFormat, format = _this_getASTC4x4TextureDetail.format, type = _this_getASTC4x4TextureDetail.type;
1568
+ if (Math.max(pixelWidth, pixelHeight) === 0) {
1569
+ throw new Error("Invalid KTX2 texture: both width and height are zero");
1570
+ }
1405
1571
  var target = faceCount === 6 ? EFFECTS.glContext.TEXTURE_CUBE_MAP : EFFECTS.glContext.TEXTURE_2D;
1406
1572
  var faces = transcodeResult.faces;
1407
1573
  var _faces__length;
1408
- var transLevels = (_faces__length = (_faces_ = faces[0]) == null ? void 0 : _faces_.length) != null ? _faces__length : 0;
1409
- var maxDimension = Math.max(pixelWidth, pixelHeight);
1410
- if (maxDimension === 0) {
1411
- throw new Error("Invalid KTX2 texture: both width and height are zero");
1412
- }
1413
- var fullChainCount = Math.floor(Math.log2(maxDimension)) + 1;
1414
- var useMipmaps = transLevels > 1 && transLevels >= fullChainCount;
1415
- var levelCount = useMipmaps ? transLevels : 1;
1574
+ // 转码时已按 neededLevelCount 截断,直接使用全部转码结果
1575
+ var levelCount = hasFullMipmapChain ? (_faces__length = (_faces_ = faces[0]) == null ? void 0 : _faces_.length) != null ? _faces__length : 0 : 1;
1416
1576
  var mipmaps = [];
1417
1577
  for(var level = 0; level < levelCount; level++){
1418
1578
  for(var face = 0; face < faceCount; face++){
@@ -1453,7 +1613,7 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1453
1613
  this.khronosInitPromise = undefined;
1454
1614
  };
1455
1615
  return KTX2Loader;
1456
- }();
1616
+ }(_wrap_native_super(EFFECTS.Plugin));
1457
1617
  /**
1458
1618
  * 注册 KTX2 加载器到全局注册表
1459
1619
  * @param workerCount - 大于 0 时使用 WebWorker,默认使用主线程
@@ -1471,8 +1631,8 @@ function zstddecWasm(imports){return _loadWasmModule(0, null, 'AGFzbQEAAAABpQEVY
1471
1631
 
1472
1632
  /**
1473
1633
  * 插件版本号
1474
- */ var version = "2.9.0-alpha.2";
1475
- registerKTX2Loader();
1634
+ */ var version = "2.9.0";
1635
+ EFFECTS.registerPlugin("ktx2", KTX2Loader);
1476
1636
  EFFECTS.logger.info("Plugin ktx2 version: " + version + ".");
1477
1637
  if (version !== EFFECTS__namespace.version) {
1478
1638
  console.error("注意:请统一 KTX2 插件与 Player 版本,不统一的版本混用会有不可预知的后果!", "\nAttention: Please ensure the KTX2 plugin is synchronized with the Player version. Mixing and matching incompatible versions may result in unpredictable consequences!");