@ludicon/spark.js 0.0.3 → 0.0.5
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/LICENSE +0 -0
- package/README.md +2 -2
- package/dist/index.esm.js +11 -8
- package/dist/spark_astc_rgb-ylbf30mQ.js +0 -0
- package/dist/spark_astc_rgba-C4NuyfHw.js +0 -0
- package/dist/spark_bc1_rgb-CRQwJRCp.js +0 -0
- package/dist/spark_bc3_rgba-CyRcvC8t.js +0 -0
- package/dist/spark_bc4_r-BSB9VB_w.js +0 -0
- package/dist/spark_bc5_rg-NX_OBH9I.js +0 -0
- package/dist/spark_bc7_rgb-CYdL55pE.js +0 -0
- package/dist/spark_bc7_rgba-BFgOyqos.js +0 -0
- package/dist/spark_eac_r-BFwH430b.js +0 -0
- package/dist/spark_eac_rg--Gm5Gzmk.js +0 -0
- package/dist/spark_etc2_rgb-CWjBHhHQ.js +0 -0
- package/dist/spark_etc2_rgba-BRX5DwNI.js +0 -0
- package/dist/utils-CnL93Jcx.js +4 -0
- package/package.json +1 -1
- package/dist/utils-BybjJ-PV.js +0 -4
package/LICENSE
CHANGED
|
File without changes
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# spark.js⚡️
|
|
2
2
|
|
|
3
|
-
[](https://www.npmjs.com/package/@ludicon/spark.js) [](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API)
|
|
3
|
+
[](https://www.npmjs.com/package/@ludicon/spark.js) [](https://packagephobia.com/result?p=@ludicon/spark.js) [](https://developer.mozilla.org/en-US/docs/Web/API/WebGPU_API)
|
|
4
4
|
|
|
5
5
|
Real-time texture compression library for the Web.
|
|
6
6
|
|
|
@@ -37,7 +37,7 @@ const texture = await spark.encodeTexture("image.avif")
|
|
|
37
37
|
|
|
38
38
|
The main entry point is `spark.encodeTexture()`, which loads an image and transcodes it into a compressed `GPUTexture` using the selected format and options. The example above uses default settings, but `encodeTexture` supports additional parameters for mipmap generation, sRGB encoding, normal map processing, and more.
|
|
39
39
|
|
|
40
|
-
If the input image dimensions are not multiples of the block size, it will be resized to meet GPU format requirements. For best results, use
|
|
40
|
+
If the input image dimensions are not multiples of the block size, it will be resized to meet GPU format requirements. For best results, use images with dimensions that are multiples of 4.
|
|
41
41
|
|
|
42
42
|
|
|
43
43
|
## Development
|
package/dist/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const modules = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import("./spark_astc_rgb-ylbf30mQ.js"), "./spark_astc_rgba.wgsl": () => import("./spark_astc_rgba-C4NuyfHw.js"), "./spark_bc1_rgb.wgsl": () => import("./spark_bc1_rgb-CRQwJRCp.js"), "./spark_bc3_rgba.wgsl": () => import("./spark_bc3_rgba-CyRcvC8t.js"), "./spark_bc4_r.wgsl": () => import("./spark_bc4_r-BSB9VB_w.js"), "./spark_bc5_rg.wgsl": () => import("./spark_bc5_rg-NX_OBH9I.js"), "./spark_bc7_rgb.wgsl": () => import("./spark_bc7_rgb-CYdL55pE.js"), "./spark_bc7_rgba.wgsl": () => import("./spark_bc7_rgba-BFgOyqos.js"), "./spark_eac_r.wgsl": () => import("./spark_eac_r-BFwH430b.js"), "./spark_eac_rg.wgsl": () => import("./spark_eac_rg--Gm5Gzmk.js"), "./spark_etc2_rgb.wgsl": () => import("./spark_etc2_rgb-CWjBHhHQ.js"), "./spark_etc2_rgba.wgsl": () => import("./spark_etc2_rgba-BRX5DwNI.js"), "./utils.wgsl": () => import("./utils-
|
|
1
|
+
const modules = /* @__PURE__ */ Object.assign({ "./spark_astc_rgb.wgsl": () => import("./spark_astc_rgb-ylbf30mQ.js"), "./spark_astc_rgba.wgsl": () => import("./spark_astc_rgba-C4NuyfHw.js"), "./spark_bc1_rgb.wgsl": () => import("./spark_bc1_rgb-CRQwJRCp.js"), "./spark_bc3_rgba.wgsl": () => import("./spark_bc3_rgba-CyRcvC8t.js"), "./spark_bc4_r.wgsl": () => import("./spark_bc4_r-BSB9VB_w.js"), "./spark_bc5_rg.wgsl": () => import("./spark_bc5_rg-NX_OBH9I.js"), "./spark_bc7_rgb.wgsl": () => import("./spark_bc7_rgb-CYdL55pE.js"), "./spark_bc7_rgba.wgsl": () => import("./spark_bc7_rgba-BFgOyqos.js"), "./spark_eac_r.wgsl": () => import("./spark_eac_r-BFwH430b.js"), "./spark_eac_rg.wgsl": () => import("./spark_eac_rg--Gm5Gzmk.js"), "./spark_etc2_rgb.wgsl": () => import("./spark_etc2_rgb-CWjBHhHQ.js"), "./spark_etc2_rgba.wgsl": () => import("./spark_etc2_rgba-BRX5DwNI.js"), "./utils.wgsl": () => import("./utils-CnL93Jcx.js") });
|
|
2
2
|
const shaders = Object.fromEntries(
|
|
3
3
|
Object.entries(modules).map(([path, module]) => {
|
|
4
4
|
const name = path.replace("./", "");
|
|
@@ -794,7 +794,10 @@ class Spark {
|
|
|
794
794
|
const webkitVersion = getSafariVersion();
|
|
795
795
|
const firefoxVersion = getFirefoxVersion();
|
|
796
796
|
if ((!webkitVersion || webkitVersion >= 26) && !firefoxVersion) {
|
|
797
|
-
this.#querySet = this.#device.createQuerySet({
|
|
797
|
+
this.#querySet = this.#device.createQuerySet({
|
|
798
|
+
type: "timestamp",
|
|
799
|
+
count: 2
|
|
800
|
+
});
|
|
798
801
|
this.#queryBuffer = this.#device.createBuffer({
|
|
799
802
|
size: 16,
|
|
800
803
|
// 2 timestamps × 8 bytes each
|
|
@@ -952,18 +955,18 @@ class Spark {
|
|
|
952
955
|
}
|
|
953
956
|
const preferenceOrder = [
|
|
954
957
|
"bc4-r",
|
|
958
|
+
"eac-r",
|
|
955
959
|
"bc5-rg",
|
|
960
|
+
"eac-rg",
|
|
956
961
|
"bc7-rgb",
|
|
957
|
-
"bc7-rgba",
|
|
958
962
|
"bc1-rgb",
|
|
959
|
-
"bc3-rgba",
|
|
960
963
|
"astc-rgb",
|
|
961
964
|
"astc-4x4-rgb",
|
|
965
|
+
"etc2-rgb",
|
|
966
|
+
"bc7-rgba",
|
|
962
967
|
"astc-rgba",
|
|
963
968
|
"astc-4x4-rgba",
|
|
964
|
-
"
|
|
965
|
-
"eac-rg",
|
|
966
|
-
"etc2-rgb",
|
|
969
|
+
"bc3-rgba",
|
|
967
970
|
"etc2-rgba"
|
|
968
971
|
];
|
|
969
972
|
for (const key of preferenceOrder) {
|
|
@@ -994,7 +997,7 @@ class Spark {
|
|
|
994
997
|
}
|
|
995
998
|
if (!opaque) return 4;
|
|
996
999
|
if (grayscale) return 1;
|
|
997
|
-
if (4 * invalidNormalCount < count) return 2;
|
|
1000
|
+
if (4 * 4 * invalidNormalCount < count) return 2;
|
|
998
1001
|
return 3;
|
|
999
1002
|
}
|
|
1000
1003
|
async #detectChannelCountGPU(texture) {
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
const utils = "struct Params {\n to_srgb: u32,\n};\n\n@group(0) @binding(0) var src : texture_2d<f32>;\n@group(0) @binding(1) var dst : texture_storage_2d<rgba8unorm, write>;\n@group(0) @binding(2) var smp: sampler;\n@group(0) @binding(3) var<uniform> params: Params;\n\nfn linear_to_srgb_vec3(c: vec3<f32>) -> vec3<f32> {\n return select(\n 1.055 * pow(c, vec3<f32>(1.0 / 2.4)) - 0.055,\n c * 12.92,\n c <= vec3<f32>(0.0031308)\n );\n}\n\nfn linear_to_srgb_vec4(c: vec4<f32>) -> vec4<f32> {\n return vec4<f32>(linear_to_srgb_vec3(c.xyz), c.w);\n}\n\n@compute @workgroup_size(8, 8)\nfn mipmap(@builtin(global_invocation_id) id : vec3<u32>) {\n let dstSize = textureDimensions(dst).xy;\n if (id.x >= dstSize.x || id.y >= dstSize.y) {\n return;\n }\n\n let size_rcp = vec2f(1.0) / vec2f(dstSize);\n let uv0 = vec2f(id.xy) * size_rcp;\n let uv1 = uv0 + size_rcp;\n\n var color = vec4f(0.0);\n color += textureSampleLevel(src, smp, vec2f(uv0.x, uv0.y), 0);\n color += textureSampleLevel(src, smp, vec2f(uv1.x, uv0.y), 0);\n color += textureSampleLevel(src, smp, vec2f(uv0.x, uv1.y), 0);\n color += textureSampleLevel(src, smp, vec2f(uv1.x, uv1.y), 0);\n color *= 0.25; \n\n if (params.to_srgb != 0) {\n color = linear_to_srgb_vec4(color);\n }\n\n textureStore(dst, id.xy, color);\n}\n\n@compute @workgroup_size(8, 8)\nfn resize(@builtin(global_invocation_id) id : vec3<u32>) {\n let dstSize = textureDimensions(dst).xy;\n if (id.x >= dstSize.x || id.y >= dstSize.y) {\n return;\n }\n\n let uv = (vec2f(id.xy) + vec2f(0.5)) / vec2f(dstSize);\n var color = textureSampleLevel(src, smp, uv, 0);\n\n if (params.to_srgb != 0) {\n color = linear_to_srgb_vec4(color);\n }\n\n textureStore(dst, id.xy, color);\n}\n\n@compute @workgroup_size(8, 8)\nfn flipy(@builtin(global_invocation_id) id : vec3<u32>) {\n let dstSize = textureDimensions(dst).xy;\n if (id.x >= dstSize.x || id.y >= dstSize.y) {\n return;\n }\n\n let uv = (vec2f(f32(id.x), f32(dstSize.y - 1u - id.y)) + vec2f(0.5)) / vec2f(dstSize);\n var color = textureSampleLevel(src, smp, uv, 0);\n\n if (params.to_srgb != 0) {\n color = linear_to_srgb_vec4(color);\n }\n\n textureStore(dst, id.xy, color);\n}\n\n\n@group(0) @binding(1) var<storage, read_write> global_counters: array<atomic<u32>, 3>;\n\nvar<workgroup> local_opaque: atomic<u32>;\nvar<workgroup> local_grayscale: atomic<u32>;\nvar<workgroup> local_invalid_normals: atomic<u32>;\n\n@compute @workgroup_size(8, 8)\nfn detect_channel_count(@builtin(global_invocation_id) global_id: vec3<u32>,\n @builtin(local_invocation_index) local_id: u32) {\n \n if (local_id == 0u) {\n atomicStore(&local_opaque, 1u);\n atomicStore(&local_grayscale, 1u);\n atomicStore(&local_invalid_normals, 0u);\n }\n workgroupBarrier();\n\n let tex_size = textureDimensions(src);\n if (global_id.x < tex_size.x && global_id.y < tex_size.y) {\n\n let color = textureLoad(src, vec2<i32>(global_id.xy), 0);\n\n // Alpha check\n if (color.a < 1.0) {\n atomicStore(&local_opaque, 0u);\n }\n\n // Grayscale check\n if (color.r != color.g || color.g != color.b) {\n atomicStore(&local_grayscale, 0u);\n }\n\n // Normal check\n let n = color.rgb * 2.0 - vec3(1.0);\n let len = length(n);\n\n if (abs(len - 1.0) > 0.2 || n.z < -0.1) {\n atomicAdd(&local_invalid_normals, 1u);\n }\n }\n\n workgroupBarrier();\n\n if (local_id == 0u) {\n // If not opaque, write not-opaque flag.\n if (atomicLoad(&local_opaque) == 0u) {\n atomicStore(&global_counters[0], 1u);\n }\n\n // If not greyscale, write not greyscale flag.\n if (atomicLoad(&local_grayscale) == 0u) {\n atomicStore(&global_counters[1], 1u);\n }\n\n // Add number of texels that are not normal.\n atomicAdd(&global_counters[2], atomicLoad(&local_invalid_normals));\n }\n}\n\n\n// @@ Compute RMSE?\n\n\n";
|
|
2
|
+
export {
|
|
3
|
+
utils as default
|
|
4
|
+
};
|
package/package.json
CHANGED
package/dist/utils-BybjJ-PV.js
DELETED
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
const utils = "struct Params {\n to_srgb: u32,\n};\n\n@group(0) @binding(0) var src : texture_2d<f32>;\n@group(0) @binding(1) var dst : texture_storage_2d<rgba8unorm, write>;\n@group(0) @binding(2) var smp: sampler;\n@group(0) @binding(3) var<uniform> params: Params;\n\nfn linear_to_srgb_vec3(c: vec3<f32>) -> vec3<f32> {\n return select(\n 1.055 * pow(c, vec3<f32>(1.0 / 2.4)) - 0.055,\n c * 12.92,\n c <= vec3<f32>(0.0031308)\n );\n}\n\nfn linear_to_srgb_vec4(c: vec4<f32>) -> vec4<f32> {\n return vec4<f32>(linear_to_srgb_vec3(c.xyz), 1.0);\n}\n\n@compute @workgroup_size(8, 8)\nfn mipmap(@builtin(global_invocation_id) id : vec3<u32>) {\n let dstSize = textureDimensions(dst).xy;\n if (id.x >= dstSize.x || id.y >= dstSize.y) {\n return;\n }\n\n let size_rcp = vec2f(1.0) / vec2f(dstSize);\n let uv0 = vec2f(id.xy) * size_rcp;\n let uv1 = uv0 + size_rcp;\n\n var color = vec4f(0.0);\n color += textureSampleLevel(src, smp, vec2f(uv0.x, uv0.y), 0);\n color += textureSampleLevel(src, smp, vec2f(uv1.x, uv0.y), 0);\n color += textureSampleLevel(src, smp, vec2f(uv0.x, uv1.y), 0);\n color += textureSampleLevel(src, smp, vec2f(uv1.x, uv1.y), 0);\n color *= 0.25; \n\n if (params.to_srgb != 0) {\n color = linear_to_srgb_vec4(color);\n }\n\n textureStore(dst, id.xy, color);\n}\n\n@compute @workgroup_size(8, 8)\nfn resize(@builtin(global_invocation_id) id : vec3<u32>) {\n let dstSize = textureDimensions(dst).xy;\n if (id.x >= dstSize.x || id.y >= dstSize.y) {\n return;\n }\n\n let uv = (vec2f(id.xy) + vec2f(0.5)) / vec2f(dstSize);\n var color = textureSampleLevel(src, smp, uv, 0);\n\n if (params.to_srgb != 0) {\n color = linear_to_srgb_vec4(color);\n }\n\n textureStore(dst, id.xy, color);\n}\n\n@compute @workgroup_size(8, 8)\nfn flipy(@builtin(global_invocation_id) id : vec3<u32>) {\n let dstSize = textureDimensions(dst).xy;\n if (id.x >= dstSize.x || id.y >= dstSize.y) {\n return;\n }\n\n let uv = vec2f(f32(id.x), f32(dstSize.y - 1u - id.y)) / vec2f(dstSize);\n var color = textureSampleLevel(src, smp, uv, 0);\n\n if (params.to_srgb != 0) {\n color = linear_to_srgb_vec4(color);\n }\n\n textureStore(dst, id.xy, color);\n}\n\n\n@group(0) @binding(1) var<storage, read_write> global_counters: array<atomic<u32>, 3>;\n\nvar<workgroup> local_opaque: atomic<u32>;\nvar<workgroup> local_grayscale: atomic<u32>;\nvar<workgroup> local_invalid_normals: atomic<u32>;\n\n@compute @workgroup_size(8, 8)\nfn detect_channel_count(@builtin(global_invocation_id) global_id: vec3<u32>,\n @builtin(local_invocation_index) local_id: u32) {\n \n if (local_id == 0u) {\n atomicStore(&local_opaque, 1u);\n atomicStore(&local_grayscale, 1u);\n atomicStore(&local_invalid_normals, 0u);\n }\n workgroupBarrier();\n\n let tex_size = textureDimensions(src);\n if (global_id.x < tex_size.x && global_id.y < tex_size.y) {\n\n let color = textureLoad(src, vec2<i32>(global_id.xy), 0);\n\n // Alpha check\n if (color.a < 1.0) {\n atomicStore(&local_opaque, 0u);\n }\n\n // Grayscale check\n if (color.r != color.g || color.g != color.b) {\n atomicStore(&local_grayscale, 0u);\n }\n\n // Normal check\n let n = color.rgb * 2.0 - vec3(1.0);\n let len = length(n);\n\n if (abs(len - 1.0) > 0.2 || n.z < -0.1) {\n atomicAdd(&local_invalid_normals, 1u);\n }\n }\n\n workgroupBarrier();\n\n if (local_id == 0u) {\n // If not opaque, write not-opaque flag.\n if (atomicLoad(&local_opaque) == 0u) {\n atomicStore(&global_counters[0], 1u);\n }\n\n // If not greyscale, write not greyscale flag.\n if (atomicLoad(&local_grayscale) == 0u) {\n atomicStore(&global_counters[1], 1u);\n }\n\n // Add number of texels that are not normal.\n atomicAdd(&global_counters[2], atomicLoad(&local_invalid_normals));\n }\n}\n\n\n// @@ Compute RMSE?\n\n\n";
|
|
2
|
-
export {
|
|
3
|
-
utils as default
|
|
4
|
-
};
|