s3m-three 0.2.0 → 0.3.1
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/README.md +2 -2
- package/dist/browser/s3m-three.iife.ext-three.js +585 -0
- package/dist/browser/s3m-three.iife.js +4419 -0
- package/dist/browser.d.ts +3 -0
- package/dist/browser.d.ts.map +1 -0
- package/dist/browser.js +21 -0
- package/dist/browser.js.map +1 -0
- package/dist/core/AtlasAlpha.d.ts +31 -0
- package/dist/core/AtlasAlpha.d.ts.map +1 -0
- package/dist/core/AtlasAlpha.js +82 -0
- package/dist/core/AtlasAlpha.js.map +1 -0
- package/dist/core/AtlasPack.d.ts +57 -0
- package/dist/core/AtlasPack.d.ts.map +1 -0
- package/dist/core/AtlasPack.js +81 -0
- package/dist/core/AtlasPack.js.map +1 -0
- package/dist/core/AtlasUpgrade.d.ts +68 -0
- package/dist/core/AtlasUpgrade.d.ts.map +1 -0
- package/dist/core/AtlasUpgrade.js +154 -0
- package/dist/core/AtlasUpgrade.js.map +1 -0
- package/dist/core/DXTTextureDecode.d.ts.map +1 -1
- package/dist/core/DXTTextureDecode.js +28 -6
- package/dist/core/DXTTextureDecode.js.map +1 -1
- package/dist/core/Draco.d.ts +52 -0
- package/dist/core/Draco.d.ts.map +1 -0
- package/dist/core/Draco.js +323 -0
- package/dist/core/Draco.js.map +1 -0
- package/dist/core/MeshOpt.d.ts +14 -3
- package/dist/core/MeshOpt.d.ts.map +1 -1
- package/dist/core/MeshOpt.js +101 -18
- package/dist/core/MeshOpt.js.map +1 -1
- package/dist/core/S3M1Parser.d.ts +16 -0
- package/dist/core/S3M1Parser.d.ts.map +1 -0
- package/dist/core/S3M1Parser.js +367 -0
- package/dist/core/S3M1Parser.js.map +1 -0
- package/dist/core/S3MBParser.d.ts +43 -1
- package/dist/core/S3MBParser.d.ts.map +1 -1
- package/dist/core/S3MBParser.js +101 -23
- package/dist/core/S3MBParser.js.map +1 -1
- package/dist/core/S3MBlockParser.d.ts +209 -0
- package/dist/core/S3MBlockParser.d.ts.map +1 -0
- package/dist/core/S3MBlockParser.js +789 -0
- package/dist/core/S3MBlockParser.js.map +1 -0
- package/dist/core/TextureFormat.d.ts +0 -1
- package/dist/core/TextureFormat.d.ts.map +1 -1
- package/dist/core/TextureFormat.js +19 -2
- package/dist/core/TextureFormat.js.map +1 -1
- package/dist/core/types.d.ts +65 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/render/DatasetManager.d.ts.map +1 -1
- package/dist/render/DatasetManager.js +5 -3
- package/dist/render/DatasetManager.js.map +1 -1
- package/dist/render/GeometryBuilder.d.ts +2 -0
- package/dist/render/GeometryBuilder.d.ts.map +1 -1
- package/dist/render/GeometryBuilder.js +185 -16
- package/dist/render/GeometryBuilder.js.map +1 -1
- package/dist/render/GroundManager.d.ts +57 -1
- package/dist/render/GroundManager.d.ts.map +1 -1
- package/dist/render/GroundManager.js +149 -21
- package/dist/render/GroundManager.js.map +1 -1
- package/dist/render/Picker.d.ts.map +1 -1
- package/dist/render/Picker.js +12 -4
- package/dist/render/Picker.js.map +1 -1
- package/dist/render/PointCloudMaterial.d.ts +36 -0
- package/dist/render/PointCloudMaterial.d.ts.map +1 -0
- package/dist/render/PointCloudMaterial.js +159 -0
- package/dist/render/PointCloudMaterial.js.map +1 -0
- package/dist/render/S3MViewer.d.ts +19 -0
- package/dist/render/S3MViewer.d.ts.map +1 -1
- package/dist/render/S3MViewer.js +143 -22
- package/dist/render/S3MViewer.js.map +1 -1
- package/dist/render/StyleMaterial.d.ts +6 -0
- package/dist/render/StyleMaterial.d.ts.map +1 -1
- package/dist/render/StyleMaterial.js +125 -2
- package/dist/render/StyleMaterial.js.map +1 -1
- package/dist/render/TextureFactory.d.ts.map +1 -1
- package/dist/render/TextureFactory.js +64 -10
- package/dist/render/TextureFactory.js.map +1 -1
- package/dist/tileset/S3MTileset.d.ts +152 -1
- package/dist/tileset/S3MTileset.d.ts.map +1 -1
- package/dist/tileset/S3MTileset.js +672 -54
- package/dist/tileset/S3MTileset.js.map +1 -1
- package/dist/vendor/crunch_decoder.module.js +12 -18
- package/dist/vendor/draco_decoder.module.js +3178 -0
- package/docs/API.md +112 -11
- package/package.json +5 -3
- package/src/browser.ts +21 -0
- package/src/core/AtlasAlpha.ts +82 -0
- package/src/core/AtlasPack.ts +127 -0
- package/src/core/AtlasUpgrade.ts +182 -0
- package/src/core/DXTTextureDecode.ts +28 -6
- package/src/core/Draco.ts +409 -0
- package/src/core/MeshOpt.ts +124 -18
- package/src/core/S3M1Parser.ts +430 -0
- package/src/core/S3MBParser.ts +112 -21
- package/src/core/S3MBlockParser.ts +953 -0
- package/src/core/TextureFormat.ts +20 -2
- package/src/core/types.ts +63 -0
- package/src/index.ts +2 -1
- package/src/render/DatasetManager.ts +5 -5
- package/src/render/GeometryBuilder.ts +207 -15
- package/src/render/GroundManager.ts +174 -20
- package/src/render/Picker.ts +13 -4
- package/src/render/PointCloudMaterial.ts +174 -0
- package/src/render/S3MViewer.ts +140 -24
- package/src/render/StyleMaterial.ts +135 -2
- package/src/render/TextureFactory.ts +67 -11
- package/src/tileset/S3MTileset.ts +704 -59
- package/src/vendor/crunch_decoder.module.js +12 -18
- package/src/vendor/draco_decoder.module.d.ts +128 -0
- package/src/vendor/draco_decoder.module.js +3178 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAmBA,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/browser.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 浏览器直引包的入口(由 vite.browser.config.ts 使用)。
|
|
3
|
+
*
|
|
4
|
+
* 做两件事:
|
|
5
|
+
* 1. 页面里还没有全局 THREE 时,把本包用到的那份挂上去(内置版就是打进来那份,
|
|
6
|
+
* 外置版就是页面原本那个)——所以用户不需要、也不应该再引第二份;
|
|
7
|
+
* 2. 显式把 API 挂到 window.S3M。
|
|
8
|
+
*
|
|
9
|
+
* 第 2 步不能省:vite 生成的 `var S3M = (function(){…})()` 在被 `import()` 当模块加载时
|
|
10
|
+
* 只存在于模块作用域,不会变成 window.S3M。classic script 和动态 import 两种加载方式
|
|
11
|
+
* 都要能用,所以自己赋值一次。
|
|
12
|
+
*/
|
|
13
|
+
import * as THREE from 'three';
|
|
14
|
+
import * as api from './index.js';
|
|
15
|
+
const g = globalThis;
|
|
16
|
+
if (!g.THREE)
|
|
17
|
+
g.THREE = THREE;
|
|
18
|
+
g.S3M = api;
|
|
19
|
+
export * from './index.js';
|
|
20
|
+
export { default } from './index.js';
|
|
21
|
+
//# sourceMappingURL=browser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,KAAK,GAAG,MAAM,YAAY,CAAC;AAElC,MAAM,CAAC,GAAG,UAAoE,CAAC;AAC/E,IAAI,CAAC,CAAC,CAAC,KAAK;IAAE,CAAC,CAAC,KAAK,GAAG,KAAK,CAAC;AAC9B,CAAC,CAAC,GAAG,GAAG,GAAG,CAAC;AAEZ,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 解出图集的 alpha 掩码(1 B/像素)。只对 DXT 图集做,其它格式返回 null。
|
|
3
|
+
*
|
|
4
|
+
* 用途:图集里的每个精灵是「建筑立面 + 上方天空」的一整块照片,天空是 alpha=0。
|
|
5
|
+
* 官方材质 alphaMode 全是 opaque,说明它拿到的精灵本来就没有天空 —— 也就是
|
|
6
|
+
* **rect 只框立面本体**。我们手里的 rect 是"照片块",所以用掩码把它收缩到
|
|
7
|
+
* 不透明包围盒,等价于官方那份裁好的 rect。
|
|
8
|
+
*/
|
|
9
|
+
export declare function atlasAlphaMask(tex: {
|
|
10
|
+
width: number;
|
|
11
|
+
height: number;
|
|
12
|
+
pixelFormat: number;
|
|
13
|
+
compressType: number;
|
|
14
|
+
data: Uint8Array | null;
|
|
15
|
+
}): Uint8Array | null;
|
|
16
|
+
/**
|
|
17
|
+
* 把 rect(uv 空间、y 向上的归一化矩形)收缩到掩码里的不透明包围盒。
|
|
18
|
+
* 找不到不透明像素时原样返回,避免把合法 rect 弄成退化矩形。
|
|
19
|
+
*/
|
|
20
|
+
export declare function shrinkRectToOpaque(rect: {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
w: number;
|
|
24
|
+
h: number;
|
|
25
|
+
}, mask: Uint8Array | null, W: number, H: number): {
|
|
26
|
+
x: number;
|
|
27
|
+
y: number;
|
|
28
|
+
w: number;
|
|
29
|
+
h: number;
|
|
30
|
+
};
|
|
31
|
+
//# sourceMappingURL=AtlasAlpha.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AtlasAlpha.d.ts","sourceRoot":"","sources":["../../src/core/AtlasAlpha.ts"],"names":[],"mappings":"AAEA;;;;;;;GAOG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE;IAClC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;CACzB,GAAG,UAAU,GAAG,IAAI,CAmBpB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,IAAI,EAAE;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EACpD,IAAI,EAAE,UAAU,GAAG,IAAI,EACvB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,GACR;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,CAmChD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import DXTTextureDecode from './DXTTextureDecode.js';
|
|
2
|
+
/**
|
|
3
|
+
* 解出图集的 alpha 掩码(1 B/像素)。只对 DXT 图集做,其它格式返回 null。
|
|
4
|
+
*
|
|
5
|
+
* 用途:图集里的每个精灵是「建筑立面 + 上方天空」的一整块照片,天空是 alpha=0。
|
|
6
|
+
* 官方材质 alphaMode 全是 opaque,说明它拿到的精灵本来就没有天空 —— 也就是
|
|
7
|
+
* **rect 只框立面本体**。我们手里的 rect 是"照片块",所以用掩码把它收缩到
|
|
8
|
+
* 不透明包围盒,等价于官方那份裁好的 rect。
|
|
9
|
+
*/
|
|
10
|
+
export function atlasAlphaMask(tex) {
|
|
11
|
+
if (!tex.data || !tex.width || !tex.height)
|
|
12
|
+
return null;
|
|
13
|
+
const ct = tex.compressType;
|
|
14
|
+
const isDxt = ct === 14 || ct === 13 || ct === 12 || ct === 17 || ct === 19 || ct === 20 || ct === 21 || tex.pixelFormat >= 17;
|
|
15
|
+
if (!isDxt)
|
|
16
|
+
return null;
|
|
17
|
+
// compressType 14 → DXT5(pixelFormat 13),见 TextureFormat.ts 的说明
|
|
18
|
+
const pf = ct === 14 ? 21 : tex.pixelFormat;
|
|
19
|
+
if (pf !== 19 && pf !== 20 && pf !== 21)
|
|
20
|
+
return null; // 只有带 alpha 的格式值得做
|
|
21
|
+
const w = tex.width;
|
|
22
|
+
const h = tex.height;
|
|
23
|
+
const rgba = new Uint8Array(w * h * 4);
|
|
24
|
+
try {
|
|
25
|
+
DXTTextureDecode.decode(rgba, w, h, tex.data, pf);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
const mask = new Uint8Array(w * h);
|
|
31
|
+
for (let i = 0; i < w * h; i++)
|
|
32
|
+
mask[i] = rgba[i * 4 + 3];
|
|
33
|
+
return mask;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* 把 rect(uv 空间、y 向上的归一化矩形)收缩到掩码里的不透明包围盒。
|
|
37
|
+
* 找不到不透明像素时原样返回,避免把合法 rect 弄成退化矩形。
|
|
38
|
+
*/
|
|
39
|
+
export function shrinkRectToOpaque(rect, mask, W, H) {
|
|
40
|
+
if (!mask)
|
|
41
|
+
return rect;
|
|
42
|
+
const px0 = Math.max(0, Math.floor(rect.x * W));
|
|
43
|
+
const px1 = Math.min(W, Math.ceil((rect.x + rect.w) * W));
|
|
44
|
+
// rect.y 是 uv 空间(0 在底部),掩码是图像空间(0 在顶部)
|
|
45
|
+
const py0 = Math.max(0, Math.floor(rect.y * H));
|
|
46
|
+
const py1 = Math.min(H, Math.ceil((rect.y + rect.h) * H));
|
|
47
|
+
if (px1 <= px0 || py1 <= py0)
|
|
48
|
+
return rect;
|
|
49
|
+
let bx0 = Infinity, bx1 = -Infinity, by0 = Infinity, by1 = -Infinity;
|
|
50
|
+
for (let py = py0; py < py1; py++) {
|
|
51
|
+
const iy = H - 1 - py;
|
|
52
|
+
if (iy < 0)
|
|
53
|
+
continue;
|
|
54
|
+
for (let px = px0; px < px1; px++) {
|
|
55
|
+
if (mask[iy * W + px] <= 8)
|
|
56
|
+
continue;
|
|
57
|
+
if (px < bx0)
|
|
58
|
+
bx0 = px;
|
|
59
|
+
if (px > bx1)
|
|
60
|
+
bx1 = px;
|
|
61
|
+
if (py < by0)
|
|
62
|
+
by0 = py;
|
|
63
|
+
if (py > by1)
|
|
64
|
+
by1 = py;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
if (!(bx1 >= bx0) || !(by1 >= by0))
|
|
68
|
+
return rect;
|
|
69
|
+
// 内缩半像素,避开边缘的混色 alpha
|
|
70
|
+
const x0 = bx0;
|
|
71
|
+
const x1 = bx1 + 1;
|
|
72
|
+
const y0 = by0;
|
|
73
|
+
const y1 = by1 + 1;
|
|
74
|
+
const eps = 0.5;
|
|
75
|
+
return {
|
|
76
|
+
x: (x0 + eps) / W,
|
|
77
|
+
w: Math.max(1 / W, (x1 - x0 - 2 * eps) / W),
|
|
78
|
+
y: (y0 + eps) / H,
|
|
79
|
+
h: Math.max(1 / H, (y1 - y0 - 2 * eps) / H),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=AtlasAlpha.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AtlasAlpha.js","sourceRoot":"","sources":["../../src/core/AtlasAlpha.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 把「一个块里的多张图集」合并成一张。
|
|
3
|
+
*
|
|
4
|
+
* 为什么必须合并:S3MBLOCK 的一个 geo(= 一个网格)里,不同顶点区间可以绑定到**不同的图集**
|
|
5
|
+
* (实测 41_00.s3mblock 里 6 张图集,尺寸 120x144 / 192x128 / 216x288 …,各自的 subTexInfo
|
|
6
|
+
* 绑定不同的 vertexOffset 区间)。而我们的材质只有一个 `map`,只能喂一张图 ——
|
|
7
|
+
* 其它图集那部分顶点就会拿着「自己图集里的归一化坐标」去采另一张图集,采到的是完全无关的
|
|
8
|
+
* 内容(表现就是墙上贴着别处的立面照)。
|
|
9
|
+
*
|
|
10
|
+
* 官方用的是纹理数组(着色器里 `atlas_batchTable_xywh(batchId, batchTextureAtlas, …)` +
|
|
11
|
+
* `uTexAtlasDim` 复数形式),每个 batch 自己带图集序号。这里用等价但更省事的做法:
|
|
12
|
+
* 解析阶段把所有图集按「货架」拼进一张大图,rect 全部换算到这张大图的坐标系,
|
|
13
|
+
* 于是单张 map 就够用了。
|
|
14
|
+
*
|
|
15
|
+
* 坐标系约定:拼图按**自上而下**的行序存放,并让纹理 `flipY = false`,
|
|
16
|
+
* 也就是 UV 的 v=0 对应图片顶行 —— 这样 rect 的 y 直接用 `offsetY / height` 即可。
|
|
17
|
+
*/
|
|
18
|
+
interface AtlasLike {
|
|
19
|
+
id?: string;
|
|
20
|
+
width: number;
|
|
21
|
+
height: number;
|
|
22
|
+
pixelFormat: number;
|
|
23
|
+
compressType: number;
|
|
24
|
+
data?: Uint8Array | null;
|
|
25
|
+
}
|
|
26
|
+
export interface PackedAtlases {
|
|
27
|
+
width: number;
|
|
28
|
+
height: number;
|
|
29
|
+
data: Uint8Array;
|
|
30
|
+
/** 图集 id → 它在拼图里的左上角像素坐标 */
|
|
31
|
+
offsets: Map<string, {
|
|
32
|
+
x: number;
|
|
33
|
+
y: number;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
/** 解码出的图集图像 + 行序约定 */
|
|
37
|
+
export interface DecodedAtlasImage {
|
|
38
|
+
rgba: Uint8Array;
|
|
39
|
+
/**
|
|
40
|
+
* `true` = 缓冲已是自上而下(v=0 顶行),直接拷;
|
|
41
|
+
* `false` = 底朝上(DXT 解码输出即是:源第 sy 行写到 height-1-sy),贴进画布要逐行倒序。
|
|
42
|
+
*/
|
|
43
|
+
topDown: boolean;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* 解出图集图像。非 DXT 且非「已经是解好的 RGBA」时返回 null。
|
|
47
|
+
*
|
|
48
|
+
* - `compressType=0 + pixelFormat=28`(leaf 组合画布 / 拼图产物):本来就是自上而下 RGBA,原样返回;
|
|
49
|
+
* - DXT 族:走 `DXTTextureDecode`,输出按仓库约定是**底朝上**的(见 packAtlases 的行序注释)。
|
|
50
|
+
*/
|
|
51
|
+
export declare function decodeAtlasImage(tex: AtlasLike): DecodedAtlasImage | null;
|
|
52
|
+
/**
|
|
53
|
+
* 合并一个块里的全部图集。只有一张图集时返回 null(没必要合并,也避免多一次解码)。
|
|
54
|
+
*/
|
|
55
|
+
export declare function packAtlases(tp: Record<string, AtlasLike>): PackedAtlases | null;
|
|
56
|
+
export {};
|
|
57
|
+
//# sourceMappingURL=AtlasPack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AtlasPack.d.ts","sourceRoot":"","sources":["../../src/core/AtlasPack.ts"],"names":[],"mappings":"AAEA;;;;;;;;;;;;;;;;GAgBG;AAEH,UAAU,SAAS;IACjB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,UAAU,GAAG,IAAI,CAAC;CAC1B;AAED,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;IACjB,4BAA4B;IAC5B,OAAO,EAAE,GAAG,CAAC,MAAM,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;CAChD;AAED,sBAAsB;AACtB,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,UAAU,CAAC;IACjB;;;OAGG;IACH,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,SAAS,GAAG,iBAAiB,GAAG,IAAI,CAgBzE;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,aAAa,GAAG,IAAI,CAoD/E"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import DXTTextureDecode from './DXTTextureDecode.js';
|
|
2
|
+
/**
|
|
3
|
+
* 解出图集图像。非 DXT 且非「已经是解好的 RGBA」时返回 null。
|
|
4
|
+
*
|
|
5
|
+
* - `compressType=0 + pixelFormat=28`(leaf 组合画布 / 拼图产物):本来就是自上而下 RGBA,原样返回;
|
|
6
|
+
* - DXT 族:走 `DXTTextureDecode`,输出按仓库约定是**底朝上**的(见 packAtlases 的行序注释)。
|
|
7
|
+
*/
|
|
8
|
+
export function decodeAtlasImage(tex) {
|
|
9
|
+
if (!tex.data || !tex.width || !tex.height)
|
|
10
|
+
return null;
|
|
11
|
+
const ct = tex.compressType;
|
|
12
|
+
if ((ct === 0 || ct === undefined) && tex.pixelFormat === 28 && tex.data.length === tex.width * tex.height * 4) {
|
|
13
|
+
return { rgba: tex.data, topDown: true };
|
|
14
|
+
}
|
|
15
|
+
const isDxt = ct === 12 || ct === 13 || ct === 14 || ct === 17 || ct === 19 || ct === 20 || ct === 21 || tex.pixelFormat >= 17;
|
|
16
|
+
if (!isDxt)
|
|
17
|
+
return null;
|
|
18
|
+
const out = new Uint8Array(tex.width * tex.height * 4);
|
|
19
|
+
try {
|
|
20
|
+
DXTTextureDecode.decode(out, tex.width, tex.height, tex.data, tex.pixelFormat);
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
return { rgba: out, topDown: false };
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* 合并一个块里的全部图集。只有一张图集时返回 null(没必要合并,也避免多一次解码)。
|
|
29
|
+
*/
|
|
30
|
+
export function packAtlases(tp) {
|
|
31
|
+
const entries = Object.entries(tp).filter(([, t]) => t.data && t.width > 0 && t.height > 0);
|
|
32
|
+
if (entries.length < 2)
|
|
33
|
+
return null;
|
|
34
|
+
const images = new Map();
|
|
35
|
+
for (const [key, tex] of entries) {
|
|
36
|
+
const img = decodeAtlasImage(tex);
|
|
37
|
+
if (!img)
|
|
38
|
+
return null; // 有一张解不出来就整体放弃,保持原样比拼错强
|
|
39
|
+
images.set(key, { w: tex.width, h: tex.height, rgba: img.rgba, topDown: img.topDown });
|
|
40
|
+
}
|
|
41
|
+
// 货架式装箱:按宽度累加,超宽换行。图集都是小块,这样做足够紧凑。
|
|
42
|
+
const MAX_W = 1024;
|
|
43
|
+
let x = 0;
|
|
44
|
+
let y = 0;
|
|
45
|
+
let rowH = 0;
|
|
46
|
+
let usedW = 0;
|
|
47
|
+
const offsets = new Map();
|
|
48
|
+
for (const [id, img] of images) {
|
|
49
|
+
if (x > 0 && x + img.w > MAX_W) {
|
|
50
|
+
x = 0;
|
|
51
|
+
y += rowH;
|
|
52
|
+
rowH = 0;
|
|
53
|
+
}
|
|
54
|
+
offsets.set(id, { x, y });
|
|
55
|
+
x += img.w;
|
|
56
|
+
rowH = Math.max(rowH, img.h);
|
|
57
|
+
usedW = Math.max(usedW, x);
|
|
58
|
+
}
|
|
59
|
+
const W = Math.max(1, usedW);
|
|
60
|
+
const H = Math.max(1, y + rowH);
|
|
61
|
+
const data = new Uint8Array(W * H * 4);
|
|
62
|
+
for (const [id, img] of images) {
|
|
63
|
+
const off = offsets.get(id);
|
|
64
|
+
// ★ DXT 解码缓冲必须逐行**倒序**拷贝(topDown=false 时)。
|
|
65
|
+
//
|
|
66
|
+
// DXTTextureDecode 输出的是「源图上下颠倒」的缓冲(源第 sy 行写到 height-1-sy),
|
|
67
|
+
// 而 rect 的 y 是按源图**自上而下**的 offsetY 算的。原样拷贝会让拼图的行序和
|
|
68
|
+
// rect 的约定相反;更糟的是同一块里各图集高度不同(192 / 184 / 64 / 128),
|
|
69
|
+
// 颠倒量随图集而异,于是「哪些精灵对、哪些精灵错」取决于它属于哪张图集 ——
|
|
70
|
+
// 表现为同一面墙一半正常一半贴到别处。
|
|
71
|
+
// 倒序拷进来之后,拼图行 0 就对应源图顶行,rect.y = (off.y + offsetY) / H 对全部图集统一成立。
|
|
72
|
+
// 已经是自上而下的缓冲(leaf 组合画布,topDown=true)则原样拷贝,不能再翻一次。
|
|
73
|
+
for (let row = 0; row < img.h; row++) {
|
|
74
|
+
const srcRow = img.topDown ? row : img.h - 1 - row;
|
|
75
|
+
const src = srcRow * img.w * 4;
|
|
76
|
+
data.set(img.rgba.subarray(src, src + img.w * 4), ((off.y + row) * W + off.x) * 4);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { width: W, height: H, data, offsets };
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=AtlasPack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AtlasPack.js","sourceRoot":"","sources":["../../src/core/AtlasPack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部图集文件(`requestNames` 指向的 `.texblock`)能不能顶替块里自带的那份?
|
|
3
|
+
* —— **先验证,再替换**。
|
|
4
|
+
*
|
|
5
|
+
* 官方 `createTexture` 的判定(SuperMap3D.js,`lM.prototype.createTexture`):
|
|
6
|
+
*
|
|
7
|
+
* ```js
|
|
8
|
+
* if (!n || !E) { // 非根瓦片,或没开 textureLod
|
|
9
|
+
* this._subRequestNames = [];
|
|
10
|
+
* for (...) this._subRequestNames.push(yke(h.requestNames[D])); // 只取 requestNames
|
|
11
|
+
* }
|
|
12
|
+
* return this.isLeaf = (!n || !E) && !(h.requestNames.length === 1 && h.requestNames[0] === a);
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* 关键两点:
|
|
16
|
+
* 1. **只认 `requestNames`**。`childTexNames` 是**下一级 LOD 的图集指针**(官方 `_ancestorTexture`
|
|
17
|
+
* 只用它继承 batchTable 的 rect),同一个精灵在父级叫 `1460_3` 96×64、子级叫 `1460_2` 192×128,
|
|
18
|
+
* 排布完全不同。拿父级的 rect 去套子级像素必然整张错位 —— 这是曾经踩过的坑。
|
|
19
|
+
* 2. `requestNames.length === 1 && requestNames[0] === 自身 id` → `isLeaf = false` → **整张替换**;
|
|
20
|
+
* 否则是 leaf → 逐精灵贴进图集(那条路要解析多精灵容器,见 HANDOFF)。
|
|
21
|
+
*
|
|
22
|
+
* 本模块只负责「整张替换」这一支的判据:替换前后必须是**同一套排布**,否则 rect 全错。
|
|
23
|
+
*
|
|
24
|
+
* | 缩略图 | 外部文件 | 长宽比偏差 | 下采样后色差 | 结论 |
|
|
25
|
+
* |---|---|---|---|---|
|
|
26
|
+
* | 96×64 | 192×128 | 0.0% | **8.5** | 同一张图,换对了 |
|
|
27
|
+
* | 108×192 | 204×384 | −5.6% | 43.3 | 不是同一张 |
|
|
28
|
+
* | 96×192 | 192×128 | +200% | 63.4 | 根本不是这张 |
|
|
29
|
+
*
|
|
30
|
+
* 判据(三条全过才允许换):
|
|
31
|
+
* 1. 长宽比偏差 ≤ 2%
|
|
32
|
+
* 2. 两轴必须是**同一个整数倍**(`subTexInfos` 的像素 offset 要能精确换算,见 rectScale)
|
|
33
|
+
* 3. 面积平均缩到缩略图尺寸后,不透明区域 RGB 平均绝对误差 ≤ 24/255
|
|
34
|
+
* 纯色/全透明图集无法判定,一律不换(宁可不换,不能换错)。
|
|
35
|
+
*/
|
|
36
|
+
export interface AtlasPixels {
|
|
37
|
+
width: number;
|
|
38
|
+
height: number;
|
|
39
|
+
data: Uint8Array;
|
|
40
|
+
/** 文件里声明的格式;DXT 族的真实块格式以 compressType 为准(pf 常是 13/ABGR 的错标签) */
|
|
41
|
+
compressType: number;
|
|
42
|
+
pixelFormat: number;
|
|
43
|
+
}
|
|
44
|
+
export interface UpgradeVerdict {
|
|
45
|
+
ok: boolean;
|
|
46
|
+
reason: 'ok' | 'aspect' | 'scale' | 'content' | 'undecodable' | 'empty';
|
|
47
|
+
/** |hi.aspect / lo.aspect - 1|,0 表示完全等比 */
|
|
48
|
+
aspectDelta: number;
|
|
49
|
+
/** 等比倍数(hi / lo)。只有 ok 时才保证是**整数**且两轴相同 */
|
|
50
|
+
scale: number;
|
|
51
|
+
/** 不透明区域 RGB 的平均绝对误差(0..255);无法比较时为 NaN */
|
|
52
|
+
meanAbsError: number;
|
|
53
|
+
}
|
|
54
|
+
export declare const DEFAULT_MAX_ASPECT_DELTA = 0.02;
|
|
55
|
+
export declare const DEFAULT_MAX_MEAN_ERROR = 24;
|
|
56
|
+
/** 面积平均缩小到 dw×dh(最近邻会在比较时引入大量假误差,必须用面积平均) */
|
|
57
|
+
export declare function boxDownsample(src: Uint8Array, sw: number, sh: number, dw: number, dh: number): Uint8Array;
|
|
58
|
+
/**
|
|
59
|
+
* 判断 `hi` 是否可以顶替 `lo`。
|
|
60
|
+
*
|
|
61
|
+
* @param lo 块内嵌的缩略图(`subTexInfos` 的坐标就是按它算的)
|
|
62
|
+
* @param hi `.texblock` 里解析出来的高清图
|
|
63
|
+
*/
|
|
64
|
+
export declare function evaluateAtlasUpgrade(lo: AtlasPixels, hi: AtlasPixels, opts?: {
|
|
65
|
+
maxAspectDelta?: number;
|
|
66
|
+
maxMeanError?: number;
|
|
67
|
+
}): UpgradeVerdict;
|
|
68
|
+
//# sourceMappingURL=AtlasUpgrade.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AtlasUpgrade.d.ts","sourceRoot":"","sources":["../../src/core/AtlasUpgrade.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAkCG;AAKH,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,UAAU,CAAC;IACjB,gEAAgE;IAChE,YAAY,EAAE,MAAM,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,OAAO,CAAC;IACZ,MAAM,EAAE,IAAI,GAAG,QAAQ,GAAG,OAAO,GAAG,SAAS,GAAG,aAAa,GAAG,OAAO,CAAC;IACxE,2CAA2C;IAC3C,WAAW,EAAE,MAAM,CAAC;IACpB,2CAA2C;IAC3C,KAAK,EAAE,MAAM,CAAC;IACd,2CAA2C;IAC3C,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,eAAO,MAAM,wBAAwB,OAAO,CAAC;AAC7C,eAAO,MAAM,sBAAsB,KAAK,CAAC;AAwBzC,6CAA6C;AAC7C,wBAAgB,aAAa,CAC3B,GAAG,EAAE,UAAU,EACf,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,EACV,EAAE,EAAE,MAAM,GACT,UAAU,CA6BZ;AAED;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,EAAE,EAAE,WAAW,EACf,EAAE,EAAE,WAAW,EACf,IAAI,GAAE;IAAE,cAAc,CAAC,EAAE,MAAM,CAAC;IAAC,YAAY,CAAC,EAAE,MAAM,CAAA;CAAO,GAC5D,cAAc,CAiDhB"}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 外部图集文件(`requestNames` 指向的 `.texblock`)能不能顶替块里自带的那份?
|
|
3
|
+
* —— **先验证,再替换**。
|
|
4
|
+
*
|
|
5
|
+
* 官方 `createTexture` 的判定(SuperMap3D.js,`lM.prototype.createTexture`):
|
|
6
|
+
*
|
|
7
|
+
* ```js
|
|
8
|
+
* if (!n || !E) { // 非根瓦片,或没开 textureLod
|
|
9
|
+
* this._subRequestNames = [];
|
|
10
|
+
* for (...) this._subRequestNames.push(yke(h.requestNames[D])); // 只取 requestNames
|
|
11
|
+
* }
|
|
12
|
+
* return this.isLeaf = (!n || !E) && !(h.requestNames.length === 1 && h.requestNames[0] === a);
|
|
13
|
+
* ```
|
|
14
|
+
*
|
|
15
|
+
* 关键两点:
|
|
16
|
+
* 1. **只认 `requestNames`**。`childTexNames` 是**下一级 LOD 的图集指针**(官方 `_ancestorTexture`
|
|
17
|
+
* 只用它继承 batchTable 的 rect),同一个精灵在父级叫 `1460_3` 96×64、子级叫 `1460_2` 192×128,
|
|
18
|
+
* 排布完全不同。拿父级的 rect 去套子级像素必然整张错位 —— 这是曾经踩过的坑。
|
|
19
|
+
* 2. `requestNames.length === 1 && requestNames[0] === 自身 id` → `isLeaf = false` → **整张替换**;
|
|
20
|
+
* 否则是 leaf → 逐精灵贴进图集(那条路要解析多精灵容器,见 HANDOFF)。
|
|
21
|
+
*
|
|
22
|
+
* 本模块只负责「整张替换」这一支的判据:替换前后必须是**同一套排布**,否则 rect 全错。
|
|
23
|
+
*
|
|
24
|
+
* | 缩略图 | 外部文件 | 长宽比偏差 | 下采样后色差 | 结论 |
|
|
25
|
+
* |---|---|---|---|---|
|
|
26
|
+
* | 96×64 | 192×128 | 0.0% | **8.5** | 同一张图,换对了 |
|
|
27
|
+
* | 108×192 | 204×384 | −5.6% | 43.3 | 不是同一张 |
|
|
28
|
+
* | 96×192 | 192×128 | +200% | 63.4 | 根本不是这张 |
|
|
29
|
+
*
|
|
30
|
+
* 判据(三条全过才允许换):
|
|
31
|
+
* 1. 长宽比偏差 ≤ 2%
|
|
32
|
+
* 2. 两轴必须是**同一个整数倍**(`subTexInfos` 的像素 offset 要能精确换算,见 rectScale)
|
|
33
|
+
* 3. 面积平均缩到缩略图尺寸后,不透明区域 RGB 平均绝对误差 ≤ 24/255
|
|
34
|
+
* 纯色/全透明图集无法判定,一律不换(宁可不换,不能换错)。
|
|
35
|
+
*/
|
|
36
|
+
import DXTTextureDecode from './DXTTextureDecode.js';
|
|
37
|
+
import { dxtPixelFormatOf, resolveTextureKind } from './TextureFormat.js';
|
|
38
|
+
export const DEFAULT_MAX_ASPECT_DELTA = 0.02;
|
|
39
|
+
export const DEFAULT_MAX_MEAN_ERROR = 24;
|
|
40
|
+
/**
|
|
41
|
+
* 解成 RGBA。**不翻行**:比较双方都用同一套方向,翻不翻不影响结论。
|
|
42
|
+
* 非 DXT / 解不出来返回 null。
|
|
43
|
+
*/
|
|
44
|
+
function decodeRgba(tex) {
|
|
45
|
+
if (!tex.data?.length || !tex.width || !tex.height)
|
|
46
|
+
return null;
|
|
47
|
+
// 已经是 RGBA(AtlasPack 拼图、或某些服务端直接给 RGBA 的 .texblock)
|
|
48
|
+
const need = tex.width * tex.height * 4;
|
|
49
|
+
if (tex.compressType === 0 && tex.pixelFormat === 28 && tex.data.length >= need) {
|
|
50
|
+
return tex.data.subarray(0, need);
|
|
51
|
+
}
|
|
52
|
+
const kind = resolveTextureKind(tex.compressType, tex.pixelFormat);
|
|
53
|
+
if (!kind.startsWith('dxt'))
|
|
54
|
+
return null;
|
|
55
|
+
const out = new Uint8Array(tex.width * tex.height * 4);
|
|
56
|
+
try {
|
|
57
|
+
DXTTextureDecode.decode(out, tex.width, tex.height, tex.data, dxtPixelFormatOf(kind));
|
|
58
|
+
}
|
|
59
|
+
catch {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
return out;
|
|
63
|
+
}
|
|
64
|
+
/** 面积平均缩小到 dw×dh(最近邻会在比较时引入大量假误差,必须用面积平均) */
|
|
65
|
+
export function boxDownsample(src, sw, sh, dw, dh) {
|
|
66
|
+
const out = new Uint8Array(dw * dh * 4);
|
|
67
|
+
for (let ty = 0; ty < dh; ty++) {
|
|
68
|
+
const y0 = (ty * sh) / dh;
|
|
69
|
+
const y1 = ((ty + 1) * sh) / dh;
|
|
70
|
+
for (let tx = 0; tx < dw; tx++) {
|
|
71
|
+
const x0 = (tx * sw) / dw;
|
|
72
|
+
const x1 = ((tx + 1) * sw) / dw;
|
|
73
|
+
let r = 0, g = 0, b = 0, a = 0, n = 0;
|
|
74
|
+
for (let y = Math.floor(y0); y < Math.ceil(y1); y++) {
|
|
75
|
+
for (let x = Math.floor(x0); x < Math.ceil(x1); x++) {
|
|
76
|
+
const cx = Math.min(sw - 1, x);
|
|
77
|
+
const cy = Math.min(sh - 1, y);
|
|
78
|
+
const o = (cy * sw + cx) * 4;
|
|
79
|
+
r += src[o];
|
|
80
|
+
g += src[o + 1];
|
|
81
|
+
b += src[o + 2];
|
|
82
|
+
a += src[o + 3];
|
|
83
|
+
n++;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const o = (ty * dw + tx) * 4;
|
|
87
|
+
out[o] = r / n;
|
|
88
|
+
out[o + 1] = g / n;
|
|
89
|
+
out[o + 2] = b / n;
|
|
90
|
+
out[o + 3] = a / n;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return out;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* 判断 `hi` 是否可以顶替 `lo`。
|
|
97
|
+
*
|
|
98
|
+
* @param lo 块内嵌的缩略图(`subTexInfos` 的坐标就是按它算的)
|
|
99
|
+
* @param hi `.texblock` 里解析出来的高清图
|
|
100
|
+
*/
|
|
101
|
+
export function evaluateAtlasUpgrade(lo, hi, opts = {}) {
|
|
102
|
+
const maxAspect = opts.maxAspectDelta ?? DEFAULT_MAX_ASPECT_DELTA;
|
|
103
|
+
const maxErr = opts.maxMeanError ?? DEFAULT_MAX_MEAN_ERROR;
|
|
104
|
+
const loAspect = lo.width / lo.height;
|
|
105
|
+
const hiAspect = hi.width / hi.height;
|
|
106
|
+
const aspectDelta = Math.abs(hiAspect / loAspect - 1);
|
|
107
|
+
const scale = hi.width / lo.width;
|
|
108
|
+
const scaleY = hi.height / lo.height;
|
|
109
|
+
const fail = (reason) => ({
|
|
110
|
+
ok: false,
|
|
111
|
+
reason,
|
|
112
|
+
aspectDelta,
|
|
113
|
+
scale,
|
|
114
|
+
meanAbsError: NaN,
|
|
115
|
+
});
|
|
116
|
+
if (!Number.isFinite(aspectDelta))
|
|
117
|
+
return fail('aspect');
|
|
118
|
+
if (aspectDelta > maxAspect)
|
|
119
|
+
return fail('aspect');
|
|
120
|
+
// 高清版必须真的更大,否则换了没意义
|
|
121
|
+
if (hi.width * hi.height <= lo.width * lo.height)
|
|
122
|
+
return fail('content');
|
|
123
|
+
// ★ 必须**整数等比**:subTexInfos 的 offset/width 是缩略图像素坐标,换图后要按倍数
|
|
124
|
+
// 精确换算(见 S3MBlockTexture.rectScale)。非整数倍会让 rect 落到半个纹素上,
|
|
125
|
+
// 平铺时逐格漂移 —— 宁可不换。
|
|
126
|
+
if (scale !== scaleY || !Number.isInteger(scale))
|
|
127
|
+
return fail('scale');
|
|
128
|
+
const loPx = decodeRgba(lo);
|
|
129
|
+
const hiPx = decodeRgba(hi);
|
|
130
|
+
if (!loPx || !hiPx)
|
|
131
|
+
return fail('undecodable');
|
|
132
|
+
const down = boxDownsample(hiPx, hi.width, hi.height, lo.width, lo.height);
|
|
133
|
+
let err = 0;
|
|
134
|
+
let n = 0;
|
|
135
|
+
for (let i = 0; i < lo.width * lo.height; i++) {
|
|
136
|
+
// 只比不透明区域:透明填充的色值没有意义
|
|
137
|
+
if (loPx[i * 4 + 3] < 8)
|
|
138
|
+
continue;
|
|
139
|
+
for (let c = 0; c < 3; c++)
|
|
140
|
+
err += Math.abs(loPx[i * 4 + c] - down[i * 4 + c]);
|
|
141
|
+
n += 3;
|
|
142
|
+
}
|
|
143
|
+
if (n === 0)
|
|
144
|
+
return fail('empty');
|
|
145
|
+
const meanAbsError = err / n;
|
|
146
|
+
return {
|
|
147
|
+
ok: meanAbsError <= maxErr,
|
|
148
|
+
reason: meanAbsError <= maxErr ? 'ok' : 'content',
|
|
149
|
+
aspectDelta,
|
|
150
|
+
scale,
|
|
151
|
+
meanAbsError,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
//# sourceMappingURL=AtlasUpgrade.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"AtlasUpgrade.js","sourceRoot":"","sources":["../../src/core/AtlasUpgrade.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DXTTextureDecode.d.ts","sourceRoot":"","sources":["../../src/core/DXTTextureDecode.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;
|
|
1
|
+
{"version":3,"file":"DXTTextureDecode.d.ts","sourceRoot":"","sources":["../../src/core/DXTTextureDecode.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAsOH,QAAA,MAAM,gBAAgB;IACpB;;;;;;OAMG;gBACS,UAAU,SAAS,MAAM,UAAU,MAAM,SAAS,UAAU,UAAU,MAAM,GAAG,IAAI;CAiChG,CAAC;AAEF,eAAe,gBAAgB,CAAC"}
|
|
@@ -195,8 +195,10 @@ function DecompressImage(rgba, width, height, blocks, flags) {
|
|
|
195
195
|
const sx = x + px;
|
|
196
196
|
const sy = y + py;
|
|
197
197
|
if (sx < width && sy < height) {
|
|
198
|
-
// flip Y
|
|
199
|
-
|
|
198
|
+
// flip Y:squish 的原式是 height - 1 - sy。写成 height - sy 会让 sy = 0
|
|
199
|
+
// 落到 row = height 越界(TypedArray 越界写是静默丢弃),于是缓冲区第 0 行
|
|
200
|
+
// 永远是全 0(透明黑),其余行整体错位一行。
|
|
201
|
+
let nBegin = 4 * (width * (height - 1 - sy) + sx);
|
|
200
202
|
for (let i = 0; i < 4; ++i)
|
|
201
203
|
rgba[nBegin++] = targetRgba[nOffsetTarget++];
|
|
202
204
|
}
|
|
@@ -221,10 +223,30 @@ const DXTTextureDecode = {
|
|
|
221
223
|
decode(out, width, height, block, format) {
|
|
222
224
|
if (out == null || block == null || height === 0 || width === 0)
|
|
223
225
|
return;
|
|
224
|
-
//
|
|
225
|
-
//
|
|
226
|
-
|
|
227
|
-
|
|
226
|
+
// 块大小与 alpha 编码只由压缩格式决定:DXT1 = 8 B/块,DXT3/4/5 = 16 B/块。
|
|
227
|
+
//
|
|
228
|
+
// 不能再靠「format > 11」判有没有 alpha:S3MPixelFormat 里 DXT1 = 17 也 > 11,
|
|
229
|
+
// 那样会把 DXT1 当 16 字节块读——512×512 的 DXT1 实际只有 131072 B(0.5 B/px),
|
|
230
|
+
// 按 16 字节块要 262144 B,正好差一倍,越界部分解成全 0。
|
|
231
|
+
// 官方 JS 那个判断是在「无 alpha 时纹理标成 RGB(10)/BGR(11)」的前提下才成立。
|
|
232
|
+
let flags;
|
|
233
|
+
switch (format) {
|
|
234
|
+
case 17: // DXT1
|
|
235
|
+
flags = kDxt1;
|
|
236
|
+
break;
|
|
237
|
+
case 18:
|
|
238
|
+
case 19: // DXT3
|
|
239
|
+
flags = kDxt3;
|
|
240
|
+
break;
|
|
241
|
+
case 20: // DXT4
|
|
242
|
+
case 21: // DXT5
|
|
243
|
+
flags = kDxt5;
|
|
244
|
+
break;
|
|
245
|
+
default:
|
|
246
|
+
// 老数据只在 RGB / BGR / LUMINANCE_ALPHA 里出现:无 alpha 时走 DXT1 + rgb565 快路径
|
|
247
|
+
flags = format > 11 || format === 5 ? kDxt5 : kDxt1 | krgb565;
|
|
248
|
+
}
|
|
249
|
+
if ((flags & kDxt1) !== 0 && (flags & krgb565) !== 0) {
|
|
228
250
|
DecompressImage565(asU16(out), width, height, asU16(block));
|
|
229
251
|
}
|
|
230
252
|
else {
|