From 38ed378179efb813e0d4bfc666c082edfc0296ab Mon Sep 17 00:00:00 2001 From: ddenysiuk Date: Fri, 16 Feb 2024 17:52:50 +0100 Subject: [PATCH] Compressed textures generator --- package-lock.json | 946 +++++++++++++++++- packages/compressed-textures/README.md | 45 + packages/compressed-textures/jest.config.js | 10 + packages/compressed-textures/package.json | 47 + .../compressed-textures/rollup.config.mjs | 7 + packages/compressed-textures/src/index.ts | 336 +++++++ packages/compressed-textures/src/types.ts | 58 ++ .../compressed-textures/test/Compress.test.ts | 216 ++++ .../test/resources/sp-1.png | Bin 0 -> 40706 bytes .../test/resources/sp-2.png | Bin 0 -> 47004 bytes .../test/resources/sp-3.jpg | Bin 0 -> 7672 bytes packages/compressed-textures/tsconfig.json | 4 + packages/manifest/test/Manifest.test.ts | 64 +- 13 files changed, 1692 insertions(+), 41 deletions(-) create mode 100644 packages/compressed-textures/README.md create mode 100644 packages/compressed-textures/jest.config.js create mode 100644 packages/compressed-textures/package.json create mode 100644 packages/compressed-textures/rollup.config.mjs create mode 100644 packages/compressed-textures/src/index.ts create mode 100644 packages/compressed-textures/src/types.ts create mode 100644 packages/compressed-textures/test/Compress.test.ts create mode 100644 packages/compressed-textures/test/resources/sp-1.png create mode 100644 packages/compressed-textures/test/resources/sp-2.png create mode 100644 packages/compressed-textures/test/resources/sp-3.jpg create mode 100644 packages/compressed-textures/tsconfig.json diff --git a/package-lock.json b/package-lock.json index 796c2ff..fa82256 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,6 +57,10 @@ "resolved": "packages/compress", "link": true }, + "node_modules/@assetpack/plugin-compressed-textures": { + "resolved": "packages/compressed-textures", + "link": true + }, "node_modules/@assetpack/plugin-ffmpeg": { "resolved": "packages/ffmpeg", "link": true @@ -712,6 +716,15 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@emnapi/runtime": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.45.0.tgz", + "integrity": "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@eslint/eslintrc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", @@ -879,6 +892,53 @@ "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, + "node_modules/@gpu-tex-enc/astc": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@gpu-tex-enc/astc/-/astc-4.7.0.tgz", + "integrity": "sha512-YBeXSYM/WP71hAxLgFxpaF6VEe2dwkS9rjTtKMPRDJEJoja/NIHWrqScwJC600UyxY7kLsjFTek7W6WtYzyi8A==", + "dependencies": { + "cpu-features": "^0.0.9" + }, + "bin": { + "astcenc-darwin-arm64-avx2": "bin/darwin/astcenc", + "astcenc-darwin-arm64-sse2": "bin/darwin/astcenc", + "astcenc-darwin-arm64-sse4.1": "bin/darwin/astcenc", + "astcenc-darwin-x64-avx2": "bin/darwin/astcenc", + "astcenc-darwin-x64-sse2": "bin/darwin/astcenc", + "astcenc-darwin-x64-sse4.1": "bin/darwin/astcenc", + "astcenc-linux-x64-avx2": "bin/linux-x64/astcenc-avx2", + "astcenc-linux-x64-sse2": "bin/linux-x64/astcenc-sse2", + "astcenc-linux-x64-sse4.1": "bin/linux-x64/astcenc-sse4.1", + "astcenc-win32-arm64-avx2": "bin/win32-arm64/astcenc-neon.exe", + "astcenc-win32-arm64-sse2": "bin/win32-arm64/astcenc-neon.exe", + "astcenc-win32-arm64-sse4.1": "bin/win32-arm64/astcenc-neon.exe", + "astcenc-win32-x64-avx2": "bin/win32-x64/astcenc-avx2.exe", + "astcenc-win32-x64-sse2": "bin/win32-x64/astcenc-sse2.exe", + "astcenc-win32-x64-sse4.1": "bin/win32-x64/astcenc-sse4.1.exe" + } + }, + "node_modules/@gpu-tex-enc/bc": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@gpu-tex-enc/bc/-/bc-1.0.11.tgz", + "integrity": "sha512-Nxp3uUS3MG02XMA28uwey9aLNltW0lxRV4gKqrckYGEC4V5R8MG29LXQcW7hJ3xIqhUG2kvt0E80tbq6WzO9Cg==", + "bin": { + "bc7enc-darwin-arm64": "bin/darwin-arm64/bc7enc", + "bc7enc-darwin-x64": "bin/darwin-x64/bc7enc", + "bc7enc-linux": "bin/linux/bc7enc", + "bc7enc-win32": "bin/win32/bc7enc.exe" + } + }, + "node_modules/@gpu-tex-enc/etc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@gpu-tex-enc/etc/-/etc-1.0.3.tgz", + "integrity": "sha512-KRGP0qua3bzj1wdNlkFxg/TV3beGCW5iOlFjVJ90+osDVqYBLd1BsEqRSlqxd3b/gG1S7dL/gX4igqZtUDobKQ==", + "bin": { + "etc2comp-darwin-arm64": "bin/darwin-arm64/EtcTool", + "etc2comp-darwin-x64": "bin/darwin-x64/EtcTool", + "etc2comp-linux": "bin/linux/EtcTool", + "etc2comp-win32": "bin/win32/EtcTool.exe" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -943,6 +1003,437 @@ "node": ">=6.9.0" } }, + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.2.tgz", + "integrity": "sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.0.1" + } + }, + "node_modules/@img/sharp-darwin-x64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.2.tgz", + "integrity": "sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.0.1" + } + }, + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.1.tgz", + "integrity": "sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=11", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.1.tgz", + "integrity": "sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "macos": ">=10.13", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.1.tgz", + "integrity": "sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.1.tgz", + "integrity": "sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.1.tgz", + "integrity": "sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.1.tgz", + "integrity": "sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.1.tgz", + "integrity": "sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.1.tgz", + "integrity": "sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-linux-arm": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.2.tgz", + "integrity": "sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.0.1" + } + }, + "node_modules/@img/sharp-linux-arm64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.2.tgz", + "integrity": "sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.0.1" + } + }, + "node_modules/@img/sharp-linux-s390x": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.2.tgz", + "integrity": "sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.28", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.0.1" + } + }, + "node_modules/@img/sharp-linux-x64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.2.tgz", + "integrity": "sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "glibc": ">=2.26", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.0.1" + } + }, + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.2.tgz", + "integrity": "sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.1" + } + }, + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.2.tgz", + "integrity": "sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "musl": ">=1.2.2", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.1" + } + }, + "node_modules/@img/sharp-wasm32": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.2.tgz", + "integrity": "sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==", + "cpu": [ + "wasm32" + ], + "optional": true, + "dependencies": { + "@emnapi/runtime": "^0.45.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-ia32": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.2.tgz", + "integrity": "sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/@img/sharp-win32-x64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.2.tgz", + "integrity": "sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0", + "npm": ">=9.6.5", + "pnpm": ">=7.1.0", + "yarn": ">=3.2.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, "node_modules/@isaacs/string-locale-compare": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", @@ -5011,6 +5502,14 @@ "node": ">=8.12.0" } }, + "node_modules/buildcheck": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz", + "integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==", + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -5868,6 +6367,19 @@ "node": ">=10" } }, + "node_modules/cpu-features": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.9.tgz", + "integrity": "sha512-AKjgn2rP2yJyfbepsmLfiYcmtNn/2eUvocUyM/09yB0YDiz39HteK/5/T4Onf0pmdYDMgkBoGvRLvEguzyL7wQ==", + "hasInstallScript": true, + "dependencies": { + "buildcheck": "~0.0.6", + "nan": "^2.17.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -6149,9 +6661,9 @@ } }, "node_modules/detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==", "engines": { "node": ">=8" } @@ -6423,7 +6935,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true, "engines": { "node": ">=6" } @@ -7163,7 +7674,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true, "engines": { "node": "6.* || 8.* || >= 10.*" } @@ -7585,6 +8095,66 @@ "node": ">=4" } }, + "node_modules/gpu-tex-enc": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gpu-tex-enc/-/gpu-tex-enc-1.1.3.tgz", + "integrity": "sha512-Y6kJNTOOCU9mL3Ge/T6jbSa5KX1hiW5UJea3zHWk8CTY6SuBpnJvRSGQUFvk+wPGAmsVDwE8avoMG4+9IjWhoA==", + "dependencies": { + "@gpu-tex-enc/astc": "^4.7.0", + "@gpu-tex-enc/bc": "^1.0.11", + "@gpu-tex-enc/etc": "^1.0.3", + "yargs": "^17.7.2" + }, + "bin": { + "gputexenc": "src/cli.js" + }, + "engines": { + "node": ">=18.0.0" + }, + "optionalDependencies": { + "sharp": "^0.33.0" + } + }, + "node_modules/gpu-tex-enc/node_modules/sharp": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.2.tgz", + "integrity": "sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "semver": "^7.5.4" + }, + "engines": { + "libvips": ">=8.15.1", + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.33.2", + "@img/sharp-darwin-x64": "0.33.2", + "@img/sharp-libvips-darwin-arm64": "1.0.1", + "@img/sharp-libvips-darwin-x64": "1.0.1", + "@img/sharp-libvips-linux-arm": "1.0.1", + "@img/sharp-libvips-linux-arm64": "1.0.1", + "@img/sharp-libvips-linux-s390x": "1.0.1", + "@img/sharp-libvips-linux-x64": "1.0.1", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.1", + "@img/sharp-libvips-linuxmusl-x64": "1.0.1", + "@img/sharp-linux-arm": "0.33.2", + "@img/sharp-linux-arm64": "0.33.2", + "@img/sharp-linux-s390x": "0.33.2", + "@img/sharp-linux-x64": "0.33.2", + "@img/sharp-linuxmusl-arm64": "0.33.2", + "@img/sharp-linuxmusl-x64": "0.33.2", + "@img/sharp-wasm32": "0.33.2", + "@img/sharp-win32-ia32": "0.33.2", + "@img/sharp-win32-x64": "0.33.2" + } + }, "node_modules/graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -12914,7 +13484,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -13147,9 +13716,9 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "dependencies": { "lru-cache": "^6.0.0" }, @@ -14894,7 +15463,6 @@ "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true, "engines": { "node": ">=10" } @@ -14915,10 +15483,9 @@ } }, "node_modules/yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", - "dev": true, + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -14936,7 +15503,6 @@ "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, "engines": { "node": ">=12" } @@ -14945,7 +15511,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -15027,6 +15592,42 @@ "@assetpack/core": ">=0.0.0" } }, + "packages/compressed-textures": { + "name": "@assetpack/plugin-compressed-textures", + "version": "0.8.0", + "license": "MIT", + "dependencies": { + "fs-extra": "^11.1.0", + "gpu-tex-enc": "^1.1.3" + }, + "devDependencies": { + "@assetpack/core": "0.8.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@assetpack/core": ">=0.0.0" + } + }, + "packages/compressed-textures": { + "name": "@assetpack/plugin-compressed-textures", + "version": "0.8.0", + "license": "MIT", + "dependencies": { + "fs-extra": "^11.1.0", + "gpu-tex-enc": "^1.1.3" + }, + "devDependencies": { + "@assetpack/core": "0.8.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@assetpack/core": ">=0.0.0" + } + }, "packages/core": { "name": "@assetpack/core", "version": "0.8.0", @@ -15295,6 +15896,14 @@ "sharp": "^0.32.0" } }, + "@assetpack/plugin-compressed-textures": { + "version": "file:packages/compressed-textures", + "requires": { + "@assetpack/core": "0.8.0", + "fs-extra": "^11.1.0", + "gpu-tex-enc": "^1.1.3" + } + }, "@assetpack/plugin-ffmpeg": { "version": "file:packages/ffmpeg", "requires": { @@ -15859,6 +16468,15 @@ } } }, + "@emnapi/runtime": { + "version": "0.45.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-0.45.0.tgz", + "integrity": "sha512-Txumi3td7J4A/xTTwlssKieHKTGl3j4A1tglBx72auZ49YK7ePY6XZricgIg9mnZT4xPfA+UPCUdnhRuEFDL+w==", + "optional": true, + "requires": { + "tslib": "^2.4.0" + } + }, "@eslint/eslintrc": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", @@ -15965,6 +16583,24 @@ "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==" }, + "@gpu-tex-enc/astc": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/@gpu-tex-enc/astc/-/astc-4.7.0.tgz", + "integrity": "sha512-YBeXSYM/WP71hAxLgFxpaF6VEe2dwkS9rjTtKMPRDJEJoja/NIHWrqScwJC600UyxY7kLsjFTek7W6WtYzyi8A==", + "requires": { + "cpu-features": "^0.0.9" + } + }, + "@gpu-tex-enc/bc": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@gpu-tex-enc/bc/-/bc-1.0.11.tgz", + "integrity": "sha512-Nxp3uUS3MG02XMA28uwey9aLNltW0lxRV4gKqrckYGEC4V5R8MG29LXQcW7hJ3xIqhUG2kvt0E80tbq6WzO9Cg==" + }, + "@gpu-tex-enc/etc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@gpu-tex-enc/etc/-/etc-1.0.3.tgz", + "integrity": "sha512-KRGP0qua3bzj1wdNlkFxg/TV3beGCW5iOlFjVJ90+osDVqYBLd1BsEqRSlqxd3b/gG1S7dL/gX4igqZtUDobKQ==" + }, "@humanwhocodes/config-array": { "version": "0.11.8", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", @@ -16015,6 +16651,147 @@ "integrity": "sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q==", "dev": true }, + "@img/sharp-darwin-arm64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.2.tgz", + "integrity": "sha512-itHBs1rPmsmGF9p4qRe++CzCgd+kFYktnsoR1sbIAfsRMrJZau0Tt1AH9KVnufc2/tU02Gf6Ibujx+15qRE03w==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-arm64": "1.0.1" + } + }, + "@img/sharp-darwin-x64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.2.tgz", + "integrity": "sha512-/rK/69Rrp9x5kaWBjVN07KixZanRr+W1OiyKdXcbjQD6KbW+obaTeBBtLUAtbBsnlTTmWthw99xqoOS7SsySDg==", + "optional": true, + "requires": { + "@img/sharp-libvips-darwin-x64": "1.0.1" + } + }, + "@img/sharp-libvips-darwin-arm64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.1.tgz", + "integrity": "sha512-kQyrSNd6lmBV7O0BUiyu/OEw9yeNGFbQhbxswS1i6rMDwBBSX+e+rPzu3S+MwAiGU3HdLze3PanQ4Xkfemgzcw==", + "optional": true + }, + "@img/sharp-libvips-darwin-x64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.1.tgz", + "integrity": "sha512-eVU/JYLPVjhhrd8Tk6gosl5pVlvsqiFlt50wotCvdkFGf+mDNBJxMh+bvav+Wt3EBnNZWq8Sp2I7XfSjm8siog==", + "optional": true + }, + "@img/sharp-libvips-linux-arm": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.1.tgz", + "integrity": "sha512-FtdMvR4R99FTsD53IA3LxYGghQ82t3yt0ZQ93WMZ2xV3dqrb0E8zq4VHaTOuLEAuA83oDawHV3fd+BsAPadHIQ==", + "optional": true + }, + "@img/sharp-libvips-linux-arm64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.1.tgz", + "integrity": "sha512-bnGG+MJjdX70mAQcSLxgeJco11G+MxTz+ebxlz8Y3dxyeb3Nkl7LgLI0mXupoO+u1wRNx/iRj5yHtzA4sde1yA==", + "optional": true + }, + "@img/sharp-libvips-linux-s390x": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.1.tgz", + "integrity": "sha512-3+rzfAR1YpMOeA2zZNp+aYEzGNWK4zF3+sdMxuCS3ey9HhDbJ66w6hDSHDMoap32DueFwhhs3vwooAB2MaK4XQ==", + "optional": true + }, + "@img/sharp-libvips-linux-x64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.1.tgz", + "integrity": "sha512-3NR1mxFsaSgMMzz1bAnnKbSAI+lHXVTqAHgc1bgzjHuXjo4hlscpUxc0vFSAPKI3yuzdzcZOkq7nDPrP2F8Jgw==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.1.tgz", + "integrity": "sha512-5aBRcjHDG/T6jwC3Edl3lP8nl9U2Yo8+oTl5drd1dh9Z1EBfzUKAJFUDTDisDjUwc7N4AjnPGfCA3jl3hY8uDg==", + "optional": true + }, + "@img/sharp-libvips-linuxmusl-x64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.1.tgz", + "integrity": "sha512-dcT7inI9DBFK6ovfeWRe3hG30h51cBAP5JXlZfx6pzc/Mnf9HFCQDLtYf4MCBjxaaTfjCCjkBxcy3XzOAo5txw==", + "optional": true + }, + "@img/sharp-linux-arm": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.2.tgz", + "integrity": "sha512-Fndk/4Zq3vAc4G/qyfXASbS3HBZbKrlnKZLEJzPLrXoJuipFNNwTes71+Ki1hwYW5lch26niRYoZFAtZVf3EGA==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm": "1.0.1" + } + }, + "@img/sharp-linux-arm64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.2.tgz", + "integrity": "sha512-pz0NNo882vVfqJ0yNInuG9YH71smP4gRSdeL09ukC2YLE6ZyZePAlWKEHgAzJGTiOh8Qkaov6mMIMlEhmLdKew==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-arm64": "1.0.1" + } + }, + "@img/sharp-linux-s390x": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.2.tgz", + "integrity": "sha512-MBoInDXDppMfhSzbMmOQtGfloVAflS2rP1qPcUIiITMi36Mm5YR7r0ASND99razjQUpHTzjrU1flO76hKvP5RA==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-s390x": "1.0.1" + } + }, + "@img/sharp-linux-x64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.2.tgz", + "integrity": "sha512-xUT82H5IbXewKkeF5aiooajoO1tQV4PnKfS/OZtb5DDdxS/FCI/uXTVZ35GQ97RZXsycojz/AJ0asoz6p2/H/A==", + "optional": true, + "requires": { + "@img/sharp-libvips-linux-x64": "1.0.1" + } + }, + "@img/sharp-linuxmusl-arm64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.2.tgz", + "integrity": "sha512-F+0z8JCu/UnMzg8IYW1TMeiViIWBVg7IWP6nE0p5S5EPQxlLd76c8jYemG21X99UzFwgkRo5yz2DS+zbrnxZeA==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-arm64": "1.0.1" + } + }, + "@img/sharp-linuxmusl-x64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.2.tgz", + "integrity": "sha512-+ZLE3SQmSL+Fn1gmSaM8uFusW5Y3J9VOf+wMGNnTtJUMUxFhv+P4UPaYEYT8tqnyYVaOVGgMN/zsOxn9pSsO2A==", + "optional": true, + "requires": { + "@img/sharp-libvips-linuxmusl-x64": "1.0.1" + } + }, + "@img/sharp-wasm32": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.2.tgz", + "integrity": "sha512-fLbTaESVKuQcpm8ffgBD7jLb/CQLcATju/jxtTXR1XCLwbOQt+OL5zPHSDMmp2JZIeq82e18yE0Vv7zh6+6BfQ==", + "optional": true, + "requires": { + "@emnapi/runtime": "^0.45.0" + } + }, + "@img/sharp-win32-ia32": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.2.tgz", + "integrity": "sha512-okBpql96hIGuZ4lN3+nsAjGeggxKm7hIRu9zyec0lnfB8E7Z6p95BuRZzDDXZOl2e8UmR4RhYt631i7mfmKU8g==", + "optional": true + }, + "@img/sharp-win32-x64": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.2.tgz", + "integrity": "sha512-E4magOks77DK47FwHUIGH0RYWSgRBfGdK56kIHSVeB9uIS4pPFr4N2kIVsXdQQo4LzOsENKV5KAhRlRL7eMAdg==", + "optional": true + }, "@isaacs/string-locale-compare": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@isaacs/string-locale-compare/-/string-locale-compare-1.1.0.tgz", @@ -19249,6 +20026,11 @@ "readable-stream": "^3.4.0" } }, + "buildcheck": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/buildcheck/-/buildcheck-0.0.6.tgz", + "integrity": "sha512-8f9ZJCUXyT1M35Jx7MkBgmBMo3oHTTBIPLiY9xyL0pl3T5RwcPEY8cUHr5LBNfu/fk6c2T4DJZuVM/8ZZT2D2A==" + }, "builtins": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", @@ -19893,6 +20675,15 @@ "yaml": "^1.10.0" } }, + "cpu-features": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/cpu-features/-/cpu-features-0.0.9.tgz", + "integrity": "sha512-AKjgn2rP2yJyfbepsmLfiYcmtNn/2eUvocUyM/09yB0YDiz39HteK/5/T4Onf0pmdYDMgkBoGvRLvEguzyL7wQ==", + "requires": { + "buildcheck": "~0.0.6", + "nan": "^2.17.0" + } + }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -20103,9 +20894,9 @@ "dev": true }, "detect-libc": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.1.tgz", - "integrity": "sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==" + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.2.tgz", + "integrity": "sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==" }, "detect-newline": { "version": "3.1.0", @@ -20323,8 +21114,7 @@ "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "dev": true + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" }, "escape-goat": { "version": "2.1.1", @@ -20889,8 +21679,7 @@ "get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, "get-intrinsic": { "version": "1.2.0", @@ -21222,6 +22011,94 @@ } } }, + "gpu-tex-enc": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gpu-tex-enc/-/gpu-tex-enc-1.1.3.tgz", + "integrity": "sha512-Y6kJNTOOCU9mL3Ge/T6jbSa5KX1hiW5UJea3zHWk8CTY6SuBpnJvRSGQUFvk+wPGAmsVDwE8avoMG4+9IjWhoA==", + "requires": { + "@gpu-tex-enc/astc": "^4.7.0", + "@gpu-tex-enc/bc": "^1.0.11", + "@gpu-tex-enc/etc": "^1.0.3", + "sharp": "^0.33.0", + "yargs": "^17.7.2" + }, + "dependencies": { + "sharp": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.2.tgz", + "integrity": "sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==", + "optional": true, + "requires": { + "@img/sharp-darwin-arm64": "0.33.2", + "@img/sharp-darwin-x64": "0.33.2", + "@img/sharp-libvips-darwin-arm64": "1.0.1", + "@img/sharp-libvips-darwin-x64": "1.0.1", + "@img/sharp-libvips-linux-arm": "1.0.1", + "@img/sharp-libvips-linux-arm64": "1.0.1", + "@img/sharp-libvips-linux-s390x": "1.0.1", + "@img/sharp-libvips-linux-x64": "1.0.1", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.1", + "@img/sharp-libvips-linuxmusl-x64": "1.0.1", + "@img/sharp-linux-arm": "0.33.2", + "@img/sharp-linux-arm64": "0.33.2", + "@img/sharp-linux-s390x": "0.33.2", + "@img/sharp-linux-x64": "0.33.2", + "@img/sharp-linuxmusl-arm64": "0.33.2", + "@img/sharp-linuxmusl-x64": "0.33.2", + "@img/sharp-wasm32": "0.33.2", + "@img/sharp-win32-ia32": "0.33.2", + "@img/sharp-win32-x64": "0.33.2", + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "semver": "^7.5.4" + } + } + } + }, + "gpu-tex-enc": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gpu-tex-enc/-/gpu-tex-enc-1.1.3.tgz", + "integrity": "sha512-Y6kJNTOOCU9mL3Ge/T6jbSa5KX1hiW5UJea3zHWk8CTY6SuBpnJvRSGQUFvk+wPGAmsVDwE8avoMG4+9IjWhoA==", + "requires": { + "@gpu-tex-enc/astc": "^4.7.0", + "@gpu-tex-enc/bc": "^1.0.11", + "@gpu-tex-enc/etc": "^1.0.3", + "sharp": "^0.33.0", + "yargs": "^17.7.2" + }, + "dependencies": { + "sharp": { + "version": "0.33.2", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.2.tgz", + "integrity": "sha512-WlYOPyyPDiiM07j/UO+E720ju6gtNtHjEGg5vovUk1Lgxyjm2LFO+37Nt/UI3MMh2l6hxTWQWi7qk3cXJTutcQ==", + "optional": true, + "requires": { + "@img/sharp-darwin-arm64": "0.33.2", + "@img/sharp-darwin-x64": "0.33.2", + "@img/sharp-libvips-darwin-arm64": "1.0.1", + "@img/sharp-libvips-darwin-x64": "1.0.1", + "@img/sharp-libvips-linux-arm": "1.0.1", + "@img/sharp-libvips-linux-arm64": "1.0.1", + "@img/sharp-libvips-linux-s390x": "1.0.1", + "@img/sharp-libvips-linux-x64": "1.0.1", + "@img/sharp-libvips-linuxmusl-arm64": "1.0.1", + "@img/sharp-libvips-linuxmusl-x64": "1.0.1", + "@img/sharp-linux-arm": "0.33.2", + "@img/sharp-linux-arm64": "0.33.2", + "@img/sharp-linux-s390x": "0.33.2", + "@img/sharp-linux-x64": "0.33.2", + "@img/sharp-linuxmusl-arm64": "0.33.2", + "@img/sharp-linuxmusl-x64": "0.33.2", + "@img/sharp-wasm32": "0.33.2", + "@img/sharp-win32-ia32": "0.33.2", + "@img/sharp-win32-x64": "0.33.2", + "color": "^4.2.3", + "detect-libc": "^2.0.2", + "semver": "^7.5.4" + } + } + } + }, "graceful-fs": { "version": "4.2.10", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", @@ -25222,8 +26099,7 @@ "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", - "dev": true + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==" }, "resolve": { "version": "1.22.1", @@ -25371,9 +26247,9 @@ "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==" }, "semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", "requires": { "lru-cache": "^6.0.0" }, @@ -26687,8 +27563,7 @@ "y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", - "dev": true + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" }, "yallist": { "version": "3.1.1", @@ -26703,10 +27578,9 @@ "dev": true }, "yargs": { - "version": "17.6.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.6.2.tgz", - "integrity": "sha512-1/9UrdHjDZc0eOU0HxOHoS78C69UD3JRMvzlJ7S79S2nTaWRA/whGCTV8o9e/N/1Va9YIV7Q4sOxD8VV4pCWOw==", - "dev": true, + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "requires": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -26721,7 +27595,6 @@ "version": "8.0.1", "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, "requires": { "string-width": "^4.2.0", "strip-ansi": "^6.0.1", @@ -26733,8 +27606,7 @@ "yargs-parser": { "version": "21.1.1", "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" }, "yn": { "version": "3.1.1", diff --git a/packages/compressed-textures/README.md b/packages/compressed-textures/README.md new file mode 100644 index 0000000..3606dfb --- /dev/null +++ b/packages/compressed-textures/README.md @@ -0,0 +1,45 @@ +# @assetpack/plugin-compressed-textures + +AssetPack plugin for generation compressed textures. + +## Installation + +```sh +npm install --save-dev @assetpack/plugin-compressed-textures +``` + +## Usage + +```js +import { generateAstc, generateBc, generateEtc } from '@assetpack/compressed-textures'; + +export default { + ... + plugins: { + ... + generateAstc: generateAstc(), + generateBc: generateBc(), + generateEtc: generateEtc(), + }, +}; +``` + +## Options + +### generateAstc + +- compression: Any settings supported by [@gpu-tex-enc/astc](https://www.npmjs.com/package/@gpu-tex-enc/astc) +- `tags` - An object containing the tags to use for the plugin. Defaults to `{ nc: "nc" }`. + - `nc` - The tag used to denote that the image should not be compressed. Can be placed on a folder or file. + +### generateBc + +- compression: Any settings supported by [@gpu-tex-enc/bc](https://www.npmjs.com/package/@gpu-tex-enc/bc) +- `tags` - An object containing the tags to use for the plugin. Defaults to `{ nc: "nc" }`. + - `nc` - The tag used to denote that the image should not be compressed. Can be placed on a folder or file. + +### generateEtc + +- compression: Any settings supported by [@gpu-tex-enc/etc](https://www.npmjs.com/package/@gpu-tex-enc/etc) +- `tags` - An object containing the tags to use for the plugin. Defaults to `{ nc: "nc" }`. + - `nc` - The tag used to denote that the image should not be compressed. Can be placed on a folder or file. diff --git a/packages/compressed-textures/jest.config.js b/packages/compressed-textures/jest.config.js new file mode 100644 index 0000000..2a52343 --- /dev/null +++ b/packages/compressed-textures/jest.config.js @@ -0,0 +1,10 @@ +const sharedConfig = require('../../jest.config'); + +module.exports = { + ...sharedConfig, + rootDir: './', + moduleNameMapper: { + '^@assetpack/plugin-(.*)$': '/../$1/src', + '^@assetpack/(.*)$': '/../$1/src', + }, +}; diff --git a/packages/compressed-textures/package.json b/packages/compressed-textures/package.json new file mode 100644 index 0000000..16f4295 --- /dev/null +++ b/packages/compressed-textures/package.json @@ -0,0 +1,47 @@ +{ + "name": "@assetpack/plugin-compressed-textures", + "version": "0.8.0", + "description": "", + "homepage": "https://github.com/pixijs/assetpack/tree/master/packages/compressed-textures/#readme", + "bugs": "https://github.com/pixijs/assetpack/issues", + "repository": { + "url": "pixijs/assetpack", + "directory": "packages/compressed-textures" + }, + "license": "MIT", + "author": "ddenysiuk", + "exports": { + "import": "./dist/es/index.js", + "types": "./dist/types/index.d.ts", + "default": "./dist/cjs/index.js" + }, + "main": "./dist/cjs/index.js", + "module": "./dist/es/index.js", + "types": "./dist/types/index.d.ts", + "files": [ + "dist", + "*.d.ts" + ], + "scripts": { + "prebuild": "rimraf dist", + "build": "rollup -c", + "test": "npx jest --config ./jest.config.js", + "test:types": "tsc --noEmit" + }, + "dependencies": { + "fs-extra": "^11.1.0", + "gpu-tex-enc": "^1.1.3" + }, + "devDependencies": { + "@assetpack/core": "0.8.0" + }, + "peerDependencies": { + "@assetpack/core": ">=0.0.0" + }, + "engines": { + "node": ">=16.0.0" + }, + "publishConfig": { + "access": "public" + } +} diff --git a/packages/compressed-textures/rollup.config.mjs b/packages/compressed-textures/rollup.config.mjs new file mode 100644 index 0000000..d68789d --- /dev/null +++ b/packages/compressed-textures/rollup.config.mjs @@ -0,0 +1,7 @@ +import { readFileSync } from 'fs'; + +import { createConfig } from '../../shared/rollup.config.mjs'; + +export default createConfig({ + pkg: JSON.parse(readFileSync(new URL('./package.json', import.meta.url), 'utf8')) +}); diff --git a/packages/compressed-textures/src/index.ts b/packages/compressed-textures/src/index.ts new file mode 100644 index 0000000..a2e796d --- /dev/null +++ b/packages/compressed-textures/src/index.ts @@ -0,0 +1,336 @@ +import type { Plugin, PluginOptions, Processor, RootTree, TransformedTree } from '@assetpack/core'; +import { SavableAssetCache, checkExt, hasTag, path } from '@assetpack/core'; +import * as TEX from 'gpu-tex-enc'; +import fs from 'fs-extra'; +import { sep } from 'path'; +import { tmpdir } from 'os'; +import type { + AstcTexOptions, + BcTexOptions, + CompressAstcOptions, + CompressBcOptions, + CompressedTexOptions, + CompressEtcOptions, + EtcTexOptions, +} from './types'; + +export const astcDefaults: AstcTexOptions = { + blocksize: '4x4', + quality: 'exhaustive', + colorProfile: 'cl', + formatName: 'astc', +}; + +export const bcDefaults: BcTexOptions = { + type: 'BC7', + formatName: 'bc7', + adjustSize: true, +}; + +export const etcDefaults: EtcTexOptions = { + format: 'RGBA8', + errormetric: 'rgbx', + effort: 100, + formatName: 'etc', +}; + +// converts png to ETC in ktx +export function generateEtc(options?: Partial): Plugin +{ + const defaultOptions: Required = { + compression: { + ...etcDefaults, + ...options?.compression, + }, + tags: { + nc: 'nc', + ...options?.tags, + }, + }; + + return { + folder: false, + test(tree, _p, opts) + { + return test(tree, defaultOptions, opts, '.png'); + }, + async post(tree, processor, options) + { + const etc = buildCompressionOptions(defaultOptions, options); + + try + { + await generateTex(tree, processor, etc.formatName, + TEX.generateETC, etc.format, etc.effort, etc.errormetric, etc.options); + } + catch (error) + { + throw new Error(`[compressEtc] Failed to compress file to etc: + ${tree.path} - ${(error as Error).message}`); + } + }, + }; +} + +// converts png to BCn in dds +export function generateBc(options?: Partial): Plugin +{ + const defaultOptions: Required = { + compression: { + ...bcDefaults, + ...options?.compression, + }, + tags: { + nc: 'nc', + ...options?.tags, + }, + }; + + return { + folder: false, + test(tree, _p, opts) + { + return test(tree, defaultOptions, opts, '.png'); + }, + async post(tree, processor, options) + { + const bc = buildCompressionOptions(defaultOptions, options); + + try + { + await generateTex(tree, processor, bc.formatName, TEX.generateBC, bc.type, bc.adjustSize, bc.options); + } + catch (error) + { + throw new Error(`[compressBc] Failed to compress file to ${bc.type}: + ${tree.path} - ${(error as Error).message}`); + } + }, + }; +} + +// converts png to astc in ktx +export function generateAstc(options?: Partial): Plugin +{ + const defaultOptions: Required = { + compression: { + ...astcDefaults, + ...options?.compression, + }, + tags: { + nc: 'nc', + ...options?.tags, + }, + }; + + return { + folder: false, + test(tree, _p, opts) + { + return test(tree, defaultOptions, opts, '.png', '.jpg', '.jpeg'); + }, + async post(tree, processor, options) + { + const astc = buildCompressionOptions(defaultOptions, options); + + try + { + await generateTex(tree, processor, astc.formatName, TEX.generateASTC, + astc.blocksize, astc.quality, astc.colorProfile, astc.options); + } + catch (error) + { + throw new Error(`[compressAstc] Failed to compress file to astc: + ${tree.path} - ${(error as Error).message}`); + } + }, + }; +} + +export function generateCompressedTex(options?: Partial): Plugin +{ + const defaultEnabled = ['ASTC', 'BC7', 'RGBA8']; + + function combineOptions(type: keyof CompressedTexOptions, defaults: T): T | false + { + if (options?.[type] === false) return false; + if (!options?.[type] && !defaultEnabled.includes(type)) return false; + + return { + ...defaults, + ...options?.[type], + }; + } + + const defaultOptions: Required = { + ASTC: combineOptions('ASTC', astcDefaults), + + BC1: combineOptions('BC1', bcDefaults), + BC3: combineOptions('BC3', bcDefaults), + BC4: combineOptions('BC4', bcDefaults), + BC5: combineOptions('BC5', bcDefaults), + BC7: combineOptions('BC7', bcDefaults), + + ETC1: combineOptions('ETC1', etcDefaults), + RGB8: combineOptions('RGB8', etcDefaults), + SRGB8: combineOptions('SRGB8', etcDefaults), + RGBA8: combineOptions('RGBA8', etcDefaults), + SRGBA8: combineOptions('SRGBA8', etcDefaults), + RGB8A1: combineOptions('RGB8A1', etcDefaults), + SRGB8A1: combineOptions('SRGB8A1', etcDefaults), + R11: combineOptions('R11', etcDefaults), + SIGNED_R11: combineOptions('SIGNED_R11', etcDefaults), + RG11: combineOptions('RG11', etcDefaults), + SIGNED_RG11: combineOptions('SIGNED_RG11', etcDefaults), + tags: { + nc: 'nc', + ...options?.tags, + }, + }; + + return { + folder: false, + test(tree, _p, opts) + { + return test(tree, defaultOptions, opts, '.png'); + }, + async post(tree, processor, options) + { + const texturesOptions = {} as any; + + for (const tex in defaultOptions) + { + // skip if the plugin is disabled + if ( + options[tex as keyof typeof options] === false + || defaultOptions[tex as keyof typeof defaultOptions] === false + || tex === 'tags' + ) continue; + + texturesOptions[tex] = { + ...defaultOptions[tex as keyof typeof defaultOptions], + ...options[tex as keyof typeof options], + }; + } + + try + { + const output = await executeInTemporaryDir(tree.path, (input) => TEX.generate(input, texturesOptions)); + + for (const [key, value] of Object.entries(output)) + { + if (value) + { + const filePath = processor.saveToOutput({ + tree, + outputOptions: { + outputData: fs.readFileSync(value), + outputExtension: `.${texturesOptions[key].formatName}${path.extname(value)}`, + }, + }); + + addToSavableAssetCache(filePath, processor, tree); + } + } + } + catch (error) + { + throw new Error(`[compressEtc] Failed to compress file to etc: + ${tree.path} - ${(error as Error).message}`); + } + }, + }; +} + +export const generate = { + etc: async (input: string, etc?: Partial) => + await executeInTemporaryDir(input, + (p) => TEX.generateETC(p, etc?.format, etc?.effort, etc?.errormetric, etc?.options)), + astc: async (input: string, astc?: Partial) => + await executeInTemporaryDir(input, + (p) => TEX.generateASTC(p, astc?.blocksize, astc?.quality, astc?.colorProfile, astc?.options)), + bc: async (input: string, bc?: Partial) => + await executeInTemporaryDir(input, + (p) => TEX.generateBC(p, bc?.type, bc?.adjustSize, bc?.options)), +}; + +async function generateTex(tree: TransformedTree, processor: Processor, formatName: string, + generator: (input: string, ...args: any[]) => Promise, ...args: any[]) +{ + return executeInTemporaryDir(tree.path, + async (input) => + { + const output = await generator(input, ...args); + + const filePath = processor.saveToOutput({ + tree, + outputOptions: { + outputData: await fs.readFile(output), + outputExtension: `.${formatName}${path.extname(output)}`, + }, + }); + + addToSavableAssetCache(filePath, processor, tree); + + return output; + }); +} + +async function executeInTemporaryDir(filePath: string, fnk: (file: string) => Promise): Promise +{ + const dir = makeTmpDir(); + const fileName = path.basename(filePath); + const file = `${dir}${fileName}`; + + try + { + fs.copyFileSync(filePath, file); + + return fnk(file); + } + finally + { + fs.rmdirSync(dir); + } +} + +function makeTmpDir() +{ + return fs.mkdtempSync(`${tmpdir()}${sep}`); +} + +function test>(tree: RootTree | TransformedTree, + defaultOptions: Required, opts: Partial, ...ext: string[]): boolean +{ + const tags = { ...defaultOptions.tags, ...opts.tags } as Required['tags']>; + + return checkExt(tree.path, ...ext) && !hasTag(tree, 'path', tags.nc); +} + +function buildCompressionOptions(defaultOptions: T, + options?: T): Required +{ + return { + ...defaultOptions.compression, + ...options?.compression, + } as Required; +} + +function addToSavableAssetCache(output: string, processor: Processor, tree: TransformedTree) +{ + const asset = SavableAssetCache.get(tree.creator); + const trimmed = processor.trimOutputPath(output); + const trimmedSource = processor.trimOutputPath(path.trimExt(tree.path)); + + asset.transformData.files.forEach((f) => + { + const paths = f.paths.find((t) => t.includes(trimmedSource)); + + if (paths) + { + f.paths.push(trimmed); + } + }); + + SavableAssetCache.set(tree.creator, asset); +} diff --git a/packages/compressed-textures/src/types.ts b/packages/compressed-textures/src/types.ts new file mode 100644 index 0000000..df5215f --- /dev/null +++ b/packages/compressed-textures/src/types.ts @@ -0,0 +1,58 @@ +import type { PluginOptions } from '@assetpack/core'; +import type { AstcOptions, BcOptions, EtcOptions } from 'gpu-tex-enc'; +import type { Type } from '@gpu-tex-enc/bc'; +import type { Format } from '@gpu-tex-enc/etc'; + +export type AstcTexOptions = AstcOptions & { + formatName: string; +}; + +export interface CompressAstcOptions extends PluginOptions<'nc'> +{ + compression: Partial; +} + +export type BcTexOptions = BcOptions & { + type: Type; + formatName: string; + adjustSize: boolean +}; + +export interface CompressBcOptions extends PluginOptions<'nc'> +{ + compression: Partial; +} + +export type EtcTexOptions = EtcOptions & { + format: Format; + formatName: string; +}; + +export interface CompressEtcOptions extends PluginOptions<'nc'> +{ + compression: Partial; +} + +export interface CompressedTexOptions extends PluginOptions<'nc'> +{ + ASTC: Partial | false, + + BC1: Partial> | false, + BC3: Partial> | false, + BC4: Partial> | false, + BC5: Partial> | false, + BC7: Partial> | false, + + ETC1: Partial> | false, + RGB8: Partial> | false, + SRGB8: Partial> | false, + RGBA8: Partial> | false, + SRGBA8: Partial> | false, + RGB8A1: Partial> | false, + SRGB8A1: Partial> | false, + R11: Partial> | false, + SIGNED_R11: Partial> | false, + RG11: Partial> | false, + SIGNED_RG11: Partial> | false, +} + diff --git a/packages/compressed-textures/test/Compress.test.ts b/packages/compressed-textures/test/Compress.test.ts new file mode 100644 index 0000000..5dcc88d --- /dev/null +++ b/packages/compressed-textures/test/Compress.test.ts @@ -0,0 +1,216 @@ +import { AssetPack } from '@assetpack/core'; +import { existsSync } from 'fs-extra'; +import { assetPath, createFolder, getInputDir, getOutputDir } from '../../../shared/test'; +import { generateAstc, generateBc, generateCompressedTex, generateEtc } from '../src'; + +const pkg = 'compressed-textures'; + +describe('Compressed textures', () => +{ + it('should compress', async () => + { + const testName = 'compress-textures'; + const inputDir = getInputDir(pkg, testName); + const outputDir = getOutputDir(pkg, testName); + + createFolder( + pkg, + { + name: testName, + files: [ + { + name: 'testPng.png', + content: assetPath(pkg, 'sp-2.png'), + }, + { + name: 'testJpg.jpg', + content: assetPath(pkg, 'sp-3.jpg'), + }, + ], + folders: [], + }); + const pack = new AssetPack({ + entry: inputDir, + output: outputDir, + plugins: { + compressBc7: generateBc(), + compressBc3: generateBc({ + compression: { + type: 'BC3', + formatName: 's3tc', + }, + }), + compressEtc: generateEtc({ + compression: { + formatName: 'etc2', + }, + }), + compressAstc: generateAstc(), + }, + }); + + await pack.run(); + + expect(existsSync(`${outputDir}/testPng.astc.ktx`)) + .toBe(true); + expect(existsSync(`${outputDir}/testJpg.astc.ktx`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.etc2.ktx`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.bc7.dds`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.s3tc.dds`)) + .toBe(true); + }); + + it('should compress png with 1 plugin', async () => + { + const testName = 'compress-png-1-plugin'; + const inputDir = getInputDir(pkg, testName); + const outputDir = getOutputDir(pkg, testName); + + createFolder( + pkg, + { + name: testName, + files: [ + { + name: 'testPng.png', + content: assetPath(pkg, 'sp-2.png'), + }, + { + name: 'testJpg.jpg', + content: assetPath(pkg, 'sp-3.jpg'), + }, + ], + folders: [], + }); + const pack = new AssetPack({ + entry: inputDir, + output: outputDir, + plugins: { + tex: generateCompressedTex(), + }, + }); + + await pack.run(); + + expect(existsSync(`${outputDir}/testPng.astc.ktx`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.etc.ktx`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.bc7.dds`)) + .toBe(true); + + expect(existsSync(`${outputDir}/testJpg.astc.ktx`)) + .toBe(false); + expect(existsSync(`${outputDir}/testJpg.etc.ktx`)) + .toBe(false); + expect(existsSync(`${outputDir}/testJpg.bc7.dds`)) + .toBe(false); + }); + + it('should be able to turn off a compression', async () => + { + const testName = 'compress-off'; + const inputDir = getInputDir(pkg, testName); + const outputDir = getOutputDir(pkg, testName); + + createFolder( + pkg, + { + name: testName, + files: [ + { + name: 'testPng.png', + content: assetPath(pkg, 'sp-2.png'), + }, + { + name: 'testJpg.jpg', + content: assetPath(pkg, 'sp-3.jpg'), + }, + ], + folders: [], + }); + const pack = new AssetPack({ + entry: inputDir, + output: outputDir, + plugins: { + tex: generateCompressedTex({ + ASTC: false, + BC7: false, + }), + }, + }); + + await pack.run(); + + expect(existsSync(`${outputDir}/testPng.astc.ktx`)) + .toBe(false); + expect(existsSync(`${outputDir}/testPng.etc.ktx`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.bc7.dds`)) + .toBe(false); + }); + + it('should be able to override options', async () => + { + const testName = 'override-options'; + const inputDir = getInputDir(pkg, testName); + const outputDir = getOutputDir(pkg, testName); + + createFolder( + pkg, + { + name: testName, + files: [ + { + name: 'testPng.png', + content: assetPath(pkg, 'sp-2.png'), + }, + { + name: 'testJpg.jpg', + content: assetPath(pkg, 'sp-3.jpg'), + }, + ], + folders: [], + }); + const pack = new AssetPack({ + entry: inputDir, + output: outputDir, + plugins: { + tex: generateCompressedTex({ + ASTC: { + formatName: 'test', + }, + RGBA8: { + formatName: 'etc_RGBA8', + }, + BC1: { + formatName: 'dxt1', + }, + BC3: { + formatName: 'dxt5', + }, + }), + }, + }); + + await pack.run(); + + expect(existsSync(`${outputDir}/testPng.test.ktx`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.astc.ktx`)) + .toBe(false); + expect(existsSync(`${outputDir}/testPng.etc_RGBA8.ktx`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.etc.ktx`)) + .toBe(false); + expect(existsSync(`${outputDir}/testPng.bc7.dds`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.dxt1.dds`)) + .toBe(true); + expect(existsSync(`${outputDir}/testPng.dxt5.dds`)) + .toBe(true); + }); +}); diff --git a/packages/compressed-textures/test/resources/sp-1.png b/packages/compressed-textures/test/resources/sp-1.png new file mode 100644 index 0000000000000000000000000000000000000000..c51eef2d00fc04ec89b461b3b7d8cf7b1273c5e7 GIT binary patch literal 40706 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 literal 0 HcmV?d00001 diff --git a/packages/compressed-textures/test/resources/sp-2.png b/packages/compressed-textures/test/resources/sp-2.png new file mode 100644 index 0000000000000000000000000000000000000000..ec1dcc8998502a08e2e65531bc439fa9b09460f7 GIT binary patch literal 47004 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 literal 0 HcmV?d00001 diff --git a/packages/compressed-textures/tsconfig.json b/packages/compressed-textures/tsconfig.json new file mode 100644 index 0000000..10fc255 --- /dev/null +++ b/packages/compressed-textures/tsconfig.json @@ -0,0 +1,4 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*", "types/**/*", "test/**/*"], +} diff --git a/packages/manifest/test/Manifest.test.ts b/packages/manifest/test/Manifest.test.ts index 3bf7f2f..1313456 100644 --- a/packages/manifest/test/Manifest.test.ts +++ b/packages/manifest/test/Manifest.test.ts @@ -13,6 +13,7 @@ import { getInputDir, getOutputDir, } from '../../../shared/test'; +import { generateAstc, generateBc } from '@assetpack/plugin-compressed-textures'; const pkg = 'manifest'; @@ -120,6 +121,8 @@ describe('Manifest', () => spineAtlas: spineAtlasMipmap(), manifest: pixiManifest(), webp: compressWebp(), + astc: generateAstc(), + bc: generateBc() }, }); @@ -156,6 +159,10 @@ describe('Manifest', () => 'bundle/sprite@0.5x.png', 'bundle/sprite@0.5x.webp', 'bundle/sprite@1x.webp', + 'bundle/sprite@0.5x.astc.ktx', + 'bundle/sprite@1x.astc.ktx', + 'bundle/sprite@0.5x.bc7.dds', + 'bundle/sprite@1x.bc7.dds', ], data: { tags: { @@ -208,7 +215,16 @@ describe('Manifest', () => }, { alias: ['spine/dragon.png'], - src: ['spine/dragon@1x.png', 'spine/dragon@0.5x.png', 'spine/dragon@0.5x.webp', 'spine/dragon@1x.webp'], + src: [ + 'spine/dragon@1x.png', + 'spine/dragon@0.5x.png', + 'spine/dragon@0.5x.webp', + 'spine/dragon@1x.webp', + 'spine/dragon@0.5x.astc.ktx', + 'spine/dragon@1x.astc.ktx', + 'spine/dragon@0.5x.bc7.dds', + 'spine/dragon@1x.bc7.dds' + ], }, { alias: ['spine/dragon2.png'], @@ -217,6 +233,10 @@ describe('Manifest', () => 'spine/dragon2@0.5x.png', 'spine/dragon2@0.5x.webp', 'spine/dragon2@1x.webp', + 'spine/dragon2@0.5x.astc.ktx', + 'spine/dragon2@1x.astc.ktx', + 'spine/dragon2@0.5x.bc7.dds', + 'spine/dragon2@1x.bc7.dds' ], }, { @@ -323,6 +343,7 @@ describe('Manifest', () => trimExtensions: true, }), webp: compressWebp(), + astc: generateAstc(), }, }); @@ -354,6 +375,8 @@ describe('Manifest', () => 'folder/sprite@0.5x.png', 'folder/sprite@0.5x.webp', 'folder/sprite@1x.webp', + 'folder/sprite@0.5x.astc.ktx', + 'folder/sprite@1x.astc.ktx' ], }, { @@ -370,7 +393,14 @@ describe('Manifest', () => }, { alias: ['spine/dragon.png', 'dragon.png'], - src: ['spine/dragon@1x.png', 'spine/dragon@0.5x.png', 'spine/dragon@0.5x.webp', 'spine/dragon@1x.webp'], + src: [ + 'spine/dragon@1x.png', + 'spine/dragon@0.5x.png', + 'spine/dragon@0.5x.webp', + 'spine/dragon@1x.webp', + 'spine/dragon@0.5x.astc.ktx', + 'spine/dragon@1x.astc.ktx' + ], }, { alias: [ @@ -384,6 +414,8 @@ describe('Manifest', () => 'spine/dragon2@0.5x.png', 'spine/dragon2@0.5x.webp', 'spine/dragon2@1x.webp', + 'spine/dragon2@0.5x.astc.ktx', + 'spine/dragon2@1x.astc.ktx', ], }, { @@ -490,6 +522,7 @@ describe('Manifest', () => trimExtensions: false, }), webp: compressWebp(), + astc: generateAstc(), }, }); @@ -516,6 +549,8 @@ describe('Manifest', () => 'folder/sprite@0.5x.png', 'folder/sprite@0.5x.webp', 'folder/sprite@1x.webp', + 'folder/sprite@0.5x.astc.ktx', + 'folder/sprite@1x.astc.ktx' ], }, { @@ -532,7 +567,14 @@ describe('Manifest', () => }, { alias: ['spine/dragon.png', 'dragon.png'], - src: ['spine/dragon@1x.png', 'spine/dragon@0.5x.png', 'spine/dragon@0.5x.webp', 'spine/dragon@1x.webp'], + src: [ + 'spine/dragon@1x.png', + 'spine/dragon@0.5x.png', + 'spine/dragon@0.5x.webp', + 'spine/dragon@1x.webp', + 'spine/dragon@0.5x.astc.ktx', + 'spine/dragon@1x.astc.ktx' + ], }, { alias: ['spine/dragon2.png', 'dragon2.png'], @@ -541,6 +583,8 @@ describe('Manifest', () => 'spine/dragon2@0.5x.png', 'spine/dragon2@0.5x.webp', 'spine/dragon2@1x.webp', + 'spine/dragon2@0.5x.astc.ktx', + 'spine/dragon2@1x.astc.ktx', ], }, { @@ -647,6 +691,7 @@ describe('Manifest', () => trimExtensions: true, }), webp: compressWebp(), + astc: generateAstc(), }, }); @@ -676,6 +721,8 @@ describe('Manifest', () => 'folder/sprite@0.5x.png', 'folder/sprite@0.5x.webp', 'folder/sprite@1x.webp', + 'folder/sprite@0.5x.astc.ktx', + 'folder/sprite@1x.astc.ktx' ], }, { @@ -692,7 +739,14 @@ describe('Manifest', () => }, { alias: ['spine/dragon.png'], - src: ['spine/dragon@1x.png', 'spine/dragon@0.5x.png', 'spine/dragon@0.5x.webp', 'spine/dragon@1x.webp'], + src: [ + 'spine/dragon@1x.png', + 'spine/dragon@0.5x.png', + 'spine/dragon@0.5x.webp', + 'spine/dragon@1x.webp', + 'spine/dragon@0.5x.astc.ktx', + 'spine/dragon@1x.astc.ktx' + ], }, { alias: [ @@ -704,6 +758,8 @@ describe('Manifest', () => 'spine/dragon2@0.5x.png', 'spine/dragon2@0.5x.webp', 'spine/dragon2@1x.webp', + 'spine/dragon2@0.5x.astc.ktx', + 'spine/dragon2@1x.astc.ktx', ], }, {