react-native-shine 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (70) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +35 -0
  3. package/lib/module/index.js +182 -0
  4. package/lib/module/index.js.map +1 -0
  5. package/lib/module/package.json +1 -0
  6. package/lib/module/roots.js +16 -0
  7. package/lib/module/roots.js.map +1 -0
  8. package/lib/module/shaders/bindGroupLayouts.js +45 -0
  9. package/lib/module/shaders/bindGroupLayouts.js.map +1 -0
  10. package/lib/module/shaders/bindGroupUtils.js +45 -0
  11. package/lib/module/shaders/bindGroupUtils.js.map +1 -0
  12. package/lib/module/shaders/fragmentShaders/bloomFragment.js +66 -0
  13. package/lib/module/shaders/fragmentShaders/bloomFragment.js.map +1 -0
  14. package/lib/module/shaders/fragmentShaders/colorMaskFragment.js +28 -0
  15. package/lib/module/shaders/fragmentShaders/colorMaskFragment.js.map +1 -0
  16. package/lib/module/shaders/pipelineSetups.js +26 -0
  17. package/lib/module/shaders/pipelineSetups.js.map +1 -0
  18. package/lib/module/shaders/resourceManagement.js +19 -0
  19. package/lib/module/shaders/resourceManagement.js.map +1 -0
  20. package/lib/module/shaders/tgpuUtils.js +38 -0
  21. package/lib/module/shaders/tgpuUtils.js.map +1 -0
  22. package/lib/module/shaders/utils.js +65 -0
  23. package/lib/module/shaders/utils.js.map +1 -0
  24. package/lib/module/shaders/vertexShaders/mainVertex.js +35 -0
  25. package/lib/module/shaders/vertexShaders/mainVertex.js.map +1 -0
  26. package/lib/module/types/typeUtils.js +92 -0
  27. package/lib/module/types/typeUtils.js.map +1 -0
  28. package/lib/module/types/types.js +4 -0
  29. package/lib/module/types/types.js.map +1 -0
  30. package/lib/typescript/package.json +1 -0
  31. package/lib/typescript/src/index.d.ts +12 -0
  32. package/lib/typescript/src/index.d.ts.map +1 -0
  33. package/lib/typescript/src/roots.d.ts +4 -0
  34. package/lib/typescript/src/roots.d.ts.map +1 -0
  35. package/lib/typescript/src/shaders/bindGroupLayouts.d.ts +57 -0
  36. package/lib/typescript/src/shaders/bindGroupLayouts.d.ts.map +1 -0
  37. package/lib/typescript/src/shaders/bindGroupUtils.d.ts +53 -0
  38. package/lib/typescript/src/shaders/bindGroupUtils.d.ts.map +1 -0
  39. package/lib/typescript/src/shaders/fragmentShaders/bloomFragment.d.ts +6 -0
  40. package/lib/typescript/src/shaders/fragmentShaders/bloomFragment.d.ts.map +1 -0
  41. package/lib/typescript/src/shaders/fragmentShaders/colorMaskFragment.d.ts +6 -0
  42. package/lib/typescript/src/shaders/fragmentShaders/colorMaskFragment.d.ts.map +1 -0
  43. package/lib/typescript/src/shaders/pipelineSetups.d.ts +7 -0
  44. package/lib/typescript/src/shaders/pipelineSetups.d.ts.map +1 -0
  45. package/lib/typescript/src/shaders/resourceManagement.d.ts +3 -0
  46. package/lib/typescript/src/shaders/resourceManagement.d.ts.map +1 -0
  47. package/lib/typescript/src/shaders/tgpuUtils.d.ts +6 -0
  48. package/lib/typescript/src/shaders/tgpuUtils.d.ts.map +1 -0
  49. package/lib/typescript/src/shaders/utils.d.ts +13 -0
  50. package/lib/typescript/src/shaders/utils.d.ts.map +1 -0
  51. package/lib/typescript/src/shaders/vertexShaders/mainVertex.d.ts +6 -0
  52. package/lib/typescript/src/shaders/vertexShaders/mainVertex.d.ts.map +1 -0
  53. package/lib/typescript/src/types/typeUtils.d.ts +16 -0
  54. package/lib/typescript/src/types/typeUtils.d.ts.map +1 -0
  55. package/lib/typescript/src/types/types.d.ts +33 -0
  56. package/lib/typescript/src/types/types.d.ts.map +1 -0
  57. package/package.json +158 -13
  58. package/src/index.tsx +289 -0
  59. package/src/roots.ts +16 -0
  60. package/src/shaders/bindGroupLayouts.ts +40 -0
  61. package/src/shaders/bindGroupUtils.ts +101 -0
  62. package/src/shaders/fragmentShaders/bloomFragment.ts +83 -0
  63. package/src/shaders/fragmentShaders/colorMaskFragment.ts +35 -0
  64. package/src/shaders/pipelineSetups.ts +33 -0
  65. package/src/shaders/resourceManagement.ts +22 -0
  66. package/src/shaders/tgpuUtils.ts +75 -0
  67. package/src/shaders/utils.ts +103 -0
  68. package/src/shaders/vertexShaders/mainVertex.ts +35 -0
  69. package/src/types/typeUtils.ts +122 -0
  70. package/src/types/types.ts +51 -0
@@ -0,0 +1,83 @@
1
+ import tgpu from 'typegpu';
2
+ import * as d from 'typegpu/data';
3
+ import * as std from 'typegpu/std';
4
+ import {
5
+ rotationValuesBindGroupLayout,
6
+ textureBindGroupLayout,
7
+ bloomOptionsBindGroupLayout,
8
+ colorMaskBindGroupLayout,
9
+ } from '../bindGroupLayouts';
10
+ import { bloomColorShift, hueShift, overlayChannels } from '../tgpuUtils';
11
+
12
+ const bloomFragment = tgpu['~unstable'].fragmentFn({
13
+ in: { uv: d.vec2f },
14
+ out: d.vec4f,
15
+ })((input) => {
16
+ const texcoord = d.vec2f(input.uv.x, 1.0 - input.uv.y);
17
+ const uv = d.vec2f(input.uv.x, 1.0 - input.uv.y);
18
+ const centeredCoords = std.sub(std.mul(uv, 2.0), 1); //-1 to 1
19
+
20
+ const rot = rotationValuesBindGroupLayout.$.vec;
21
+ const center = std.add(d.vec2f(0.0), d.vec2f(rot.x, rot.y));
22
+
23
+ const bloomOptions = bloomOptionsBindGroupLayout.$.bloomOptions;
24
+ const bloomIntensity = bloomOptions.bloomIntensity;
25
+ const glowPower = bloomOptions.glowPower;
26
+ const hueBlendPower = bloomOptions.hueBlendPower;
27
+ const hueShiftAngleMax = bloomOptions.hueShiftAngleMax;
28
+ const hueShiftAngleMin = bloomOptions.hueShiftAngleMin;
29
+ const lightIntensity = bloomOptions.lightIntensity;
30
+
31
+ const mask = colorMaskBindGroupLayout.$.mask;
32
+ const maskedColor = mask.baseColor;
33
+ const rgbToleranceRange = mask.rgbToleranceRange;
34
+
35
+ let color = std.textureSample(
36
+ textureBindGroupLayout.$.texture,
37
+ textureBindGroupLayout.$.sampler,
38
+ texcoord
39
+ );
40
+
41
+ const maskedColorLower = std.sub(maskedColor, rgbToleranceRange.lower);
42
+ const maskedColorUpper = std.add(maskedColor, rgbToleranceRange.upper);
43
+ const upperCheck = std.all(std.le(color.xyz, maskedColorUpper));
44
+ const lowerCheck = std.all(std.ge(color.xyz, maskedColorLower));
45
+ if (upperCheck && lowerCheck) {
46
+ return color;
47
+ }
48
+
49
+ //bloomIntensity
50
+ const dst = std.exp(-std.distance(center, centeredCoords));
51
+ const distToCenter = std.smoothstep(0.0, 1 / bloomIntensity, dst);
52
+
53
+ //glowPower
54
+ let glow = d.vec3f(distToCenter);
55
+ glow = std.mul(glow, glowPower * color.w);
56
+
57
+ //hueBlend
58
+ const hueBlend = (d.f32(hueBlendPower) * dst) / 10.0;
59
+
60
+ //lightIntensity
61
+ glow = std.add(glow, lightIntensity / 10.0);
62
+ let shiftedRGB = bloomColorShift(color.xyz, dst / (lightIntensity * 2));
63
+
64
+ //hueShiftAngleMin/Max
65
+ const hueShiftAngle = std.smoothstep(
66
+ hueShiftAngleMin,
67
+ hueShiftAngleMax,
68
+ distToCenter
69
+ );
70
+ const shiftedHue = hueShift(shiftedRGB, hueShiftAngle);
71
+ shiftedRGB = overlayChannels(shiftedRGB, shiftedHue);
72
+
73
+ color = d.vec4f(std.mix(color.xyz, shiftedRGB, hueBlend), color.w);
74
+ const baseColor = color;
75
+ const blendColor = glow;
76
+
77
+ const combined = overlayChannels(baseColor.xyz, blendColor);
78
+ color = d.vec4f(std.mix(color.xyz, combined, glow), color.w);
79
+
80
+ return color;
81
+ });
82
+
83
+ export default bloomFragment;
@@ -0,0 +1,35 @@
1
+ import tgpu from 'typegpu';
2
+ import * as d from 'typegpu/data';
3
+ import * as std from 'typegpu/std';
4
+ import {
5
+ textureBindGroupLayout,
6
+ colorMaskBindGroupLayout,
7
+ } from '../bindGroupLayouts';
8
+
9
+ const colorMaskFragment = tgpu['~unstable'].fragmentFn({
10
+ in: { uv: d.vec2f },
11
+ out: d.vec4f,
12
+ })((input) => {
13
+ const texcoord = d.vec2f(input.uv.x, 1.0 - input.uv.y);
14
+
15
+ const mask = colorMaskBindGroupLayout.$.mask;
16
+ const maskedColor = mask.baseColor;
17
+ const rgbToleranceRange = mask.rgbToleranceRange;
18
+
19
+ let color = std.textureSample(
20
+ textureBindGroupLayout.$.texture,
21
+ textureBindGroupLayout.$.sampler,
22
+ texcoord
23
+ );
24
+
25
+ const maskedColorLower = std.sub(maskedColor, rgbToleranceRange.lower);
26
+ const maskedColorUpper = std.add(maskedColor, rgbToleranceRange.upper);
27
+ const upperCheck = std.all(std.le(color.xyz, maskedColorUpper));
28
+ const lowerCheck = std.all(std.ge(color.xyz, maskedColorLower));
29
+ if (upperCheck && lowerCheck) {
30
+ return color;
31
+ }
32
+ std.discard();
33
+ });
34
+
35
+ export default colorMaskFragment;
@@ -0,0 +1,33 @@
1
+ import type { TgpuRenderPipeline } from 'typegpu';
2
+ import type { BindGroupPair } from '../types/types';
3
+
4
+ export const attachBindGroups = (
5
+ pipeline: TgpuRenderPipeline,
6
+ bindGroupPairs: BindGroupPair[]
7
+ ) => {
8
+ for (const pair of bindGroupPairs) {
9
+ pipeline = pipeline.with(pair.layout, pair.group);
10
+ }
11
+
12
+ return pipeline;
13
+ };
14
+
15
+ export const getDefaultTarget = (
16
+ presentationFormat: GPUTextureFormat
17
+ ): GPUColorTargetState => {
18
+ return {
19
+ format: presentationFormat,
20
+ blend: {
21
+ color: {
22
+ srcFactor: 'src-alpha',
23
+ dstFactor: 'one-minus-src-alpha',
24
+ operation: 'add',
25
+ },
26
+ alpha: {
27
+ srcFactor: 'one',
28
+ dstFactor: 'one-minus-src-alpha',
29
+ operation: 'add',
30
+ },
31
+ },
32
+ };
33
+ };
@@ -0,0 +1,22 @@
1
+ import { Asset } from 'expo-asset';
2
+
3
+ const getBitmapFromURI = async (uri: string): Promise<ImageBitmap> => {
4
+ if (uriToBitmapMap.has(uri)) return uriToBitmapMap.get(uri)!;
5
+ console.log('bitmap not found in cache, fetching from URI');
6
+
7
+ const ast = Asset.fromURI(uri);
8
+ await ast.downloadAsync();
9
+ const fileURI = ast.localUri || ast.uri;
10
+
11
+ console.log('fetch completed, creating ImageBitmap');
12
+ const response = await fetch(fileURI);
13
+ const blob = await response.blob();
14
+ const imageBitmap = await createImageBitmap(blob);
15
+
16
+ uriToBitmapMap.set(uri, imageBitmap);
17
+ return imageBitmap;
18
+ };
19
+
20
+ const uriToBitmapMap = new Map<string, ImageBitmap>();
21
+
22
+ export default getBitmapFromURI;
@@ -0,0 +1,75 @@
1
+ import tgpu from 'typegpu';
2
+ import * as std from 'typegpu/std';
3
+ import * as d from 'typegpu/data';
4
+
5
+ export const hueShift = tgpu.fn(
6
+ [d.vec3f, d.f32],
7
+ d.vec3f
8
+ )((rgb, angle) => {
9
+ const yiqY = std.add(
10
+ std.mul(rgb.x, 0.299),
11
+ std.add(std.mul(rgb.y, 0.587), std.mul(rgb.z, 0.114))
12
+ );
13
+ const yiqI = std.add(
14
+ std.mul(rgb.x, 0.596),
15
+ std.sub(std.mul(rgb.y, -0.274), std.mul(rgb.z, 0.322))
16
+ );
17
+ const yiqQ = std.add(
18
+ std.mul(rgb.x, 0.211),
19
+ std.sub(std.mul(rgb.y, -0.523), std.mul(rgb.z, 0.311))
20
+ );
21
+
22
+ // Rotate hue
23
+ const cosA = std.cos(angle);
24
+ const sinA = std.sin(angle);
25
+ const i = std.sub(std.mul(yiqI, cosA), std.mul(yiqQ, sinA));
26
+ const q = std.add(std.mul(yiqI, sinA), std.mul(yiqQ, cosA));
27
+
28
+ // Convert back to RGB
29
+ const r = std.add(std.add(yiqY, std.mul(i, 0.956)), std.mul(q, 0.621));
30
+ const g = std.add(std.add(yiqY, std.mul(i, -0.272)), std.mul(q, -0.647));
31
+ const b = std.add(std.add(yiqY, std.mul(i, -1.105)), std.mul(q, 1.702));
32
+
33
+ return d.vec3f(r, g, b);
34
+ });
35
+
36
+ export const bloomColorShift = tgpu.fn(
37
+ [d.vec3f, d.f32],
38
+ d.vec3f
39
+ )((color, power) => {
40
+ const maxValue = std.max(std.max(color.x, color.y), color.z);
41
+ const scale = std.mix(
42
+ d.f32(1.0),
43
+ d.f32(1.0) / std.max(maxValue, d.f32(0.001)),
44
+ power
45
+ );
46
+ const boosted = std.mul(color, scale);
47
+ const saturated = std.mix(color, boosted, power);
48
+
49
+ return saturated;
50
+ });
51
+
52
+ export const overlayChannel = tgpu.fn(
53
+ [d.f32, d.f32],
54
+ d.f32
55
+ )((base, blend) => {
56
+ const mult = std.mul(2.0, std.mul(base, blend));
57
+
58
+ const screen = std.sub(
59
+ 1.0,
60
+ std.mul(2.0, std.mul(std.sub(1.0, base), std.sub(1.0, blend)))
61
+ );
62
+
63
+ return std.select(screen, mult, base < d.f32(0.5));
64
+ });
65
+
66
+ export const overlayChannels = tgpu.fn(
67
+ [d.vec3f, d.vec3f],
68
+ d.vec3f
69
+ )((base, blend) => {
70
+ return d.vec3f(
71
+ overlayChannel(base.x, blend.x),
72
+ overlayChannel(base.y, blend.y),
73
+ overlayChannel(base.z, blend.z)
74
+ );
75
+ });
@@ -0,0 +1,103 @@
1
+ import { type TgpuRoot, type TgpuTexture } from 'typegpu';
2
+ import type { quaternion, vec3 } from '../types/types';
3
+ import { Dimensions } from 'react-native';
4
+
5
+ export const createTexture = async (
6
+ root: TgpuRoot,
7
+ size: {
8
+ width: number;
9
+ height: number;
10
+ }
11
+ ): Promise<TgpuTexture> => {
12
+ const texture = root['~unstable']
13
+ .createTexture({
14
+ size: [size.width, size.height],
15
+ format: 'rgba8unorm',
16
+ })
17
+ .$usage('sampled', 'render');
18
+
19
+ return texture;
20
+ };
21
+
22
+ export const loadTexture = async (
23
+ root: TgpuRoot,
24
+ imageBitmap: ImageBitmap,
25
+ texture: TgpuTexture
26
+ ) => {
27
+ root.device.queue.copyExternalImageToTexture(
28
+ { source: imageBitmap },
29
+ { texture: root.unwrap(texture) },
30
+ [imageBitmap.width, imageBitmap.height]
31
+ );
32
+ };
33
+
34
+ export const rotateVectorByQuaternion = (
35
+ vec: vec3,
36
+ quaternion: quaternion
37
+ ): vec3 => {
38
+ 'worklet';
39
+ const t: vec3 = [
40
+ quaternion[1] * vec[2] - quaternion[2] * vec[1],
41
+ quaternion[2] * vec[0] - quaternion[0] * vec[2],
42
+ quaternion[0] * vec[1] - quaternion[1] * vec[0],
43
+ ];
44
+
45
+ // t2 = qw * forward + t
46
+ const t2: vec3 = [
47
+ quaternion[3] * vec[0] + t[0],
48
+ quaternion[3] * vec[1] + t[1],
49
+ quaternion[3] * vec[2] + t[2],
50
+ ];
51
+
52
+ const crossQT2: vec3 = [
53
+ quaternion[1] * t2[2] - quaternion[2] * t2[1],
54
+ quaternion[2] * t2[0] - quaternion[0] * t2[2],
55
+ quaternion[0] * t2[1] - quaternion[1] * t2[0],
56
+ ];
57
+
58
+ // rotated = vec + 2.0 * cross(q, t2)
59
+ const rotated: vec3 = [
60
+ vec[0] + 2.0 * crossQT2[0],
61
+ vec[1] + 2.0 * crossQT2[1],
62
+ vec[2] + 2.0 * crossQT2[2],
63
+ ];
64
+
65
+ return [rotated[0], rotated[1], rotated[2]];
66
+ };
67
+
68
+ export const clamp = (v: number, min = -1, max = 1) => {
69
+ 'worklet';
70
+ return Math.max(min, Math.min(max, v));
71
+ };
72
+
73
+ export const rotate2D = (
74
+ [x, y]: [number, number],
75
+ angleDeg: number
76
+ ): [number, number] => {
77
+ 'worklet';
78
+ const rad = (angleDeg * Math.PI) / 180;
79
+ const c = Math.cos(rad);
80
+ const s = Math.sin(rad);
81
+ return [x * c - y * s, x * s + y * c];
82
+ };
83
+
84
+ // Simple helper to get angle from dimensions (0 or 90)
85
+ export function getAngleFromDimensions() {
86
+ const { width, height } = Dimensions.get('window');
87
+ return width >= height ? 90 : 0;
88
+ }
89
+
90
+ // Subscribe to orientation change via Dimensions API only
91
+ export function subscribeToOrientationChange(
92
+ callback: (angleDeg: number) => void
93
+ ) {
94
+ callback(getAngleFromDimensions());
95
+ const handler = () => {
96
+ callback(getAngleFromDimensions());
97
+ };
98
+
99
+ const dimSub = Dimensions.addEventListener('change', handler);
100
+ return () => {
101
+ dimSub.remove();
102
+ };
103
+ }
@@ -0,0 +1,35 @@
1
+ import tgpu from 'typegpu';
2
+ import * as d from 'typegpu/data';
3
+
4
+ const mainVertex = tgpu['~unstable'].vertexFn({
5
+ in: { vertexIndex: d.builtin.vertexIndex },
6
+ out: { position: d.builtin.position, uv: d.vec2f },
7
+ })((input) => {
8
+ const position: d.v2f[] = [
9
+ d.vec2f(-1.0, -1.0), // bottom left
10
+ d.vec2f(1.0, 1.0), // top right
11
+ d.vec2f(1.0, -1.0), // bottom right
12
+ d.vec2f(-1.0, -1.0), // bottom left
13
+ d.vec2f(-1.0, 1.0), // top left
14
+ d.vec2f(1.0, 1.0), // top right
15
+ ];
16
+
17
+ const uv: d.v2f[] = [
18
+ d.vec2f(0.0, 0.0),
19
+ d.vec2f(1.0, 1.0),
20
+ d.vec2f(1.0, 0.0),
21
+ d.vec2f(0.0, 0.0),
22
+ d.vec2f(0.0, 1.0),
23
+ d.vec2f(1.0, 1.0),
24
+ ];
25
+
26
+ const index = input.vertexIndex;
27
+ const pos = position[index] as d.v2f;
28
+
29
+ return {
30
+ position: d.vec4f(pos.xy, 0.0, 1.0),
31
+ uv: uv[index] as d.v2f,
32
+ };
33
+ });
34
+
35
+ export default mainVertex;
@@ -0,0 +1,122 @@
1
+ import { f32, vec2f, vec3f, vec4f } from 'typegpu/data';
2
+ import type {
3
+ BindGroupPair,
4
+ BloomOptions,
5
+ ColorMask,
6
+ DeepPartiallyOptional,
7
+ vec3,
8
+ } from './types';
9
+ import { div } from 'typegpu/std';
10
+ import type { TgpuBindGroup, TgpuBindGroupLayout } from 'typegpu';
11
+
12
+ export const createBloomOptions = (
13
+ options: Partial<BloomOptions>
14
+ ): BloomOptions => {
15
+ const {
16
+ glowPower,
17
+ hueShiftAngleMax,
18
+ hueShiftAngleMin,
19
+ hueBlendPower,
20
+ lightIntensity,
21
+ bloomIntensity,
22
+ } = options;
23
+
24
+ const bloomOp = {
25
+ glowPower: glowPower ?? 1.0,
26
+ hueShiftAngleMax: hueShiftAngleMax ?? 1.0,
27
+ hueShiftAngleMin: hueShiftAngleMin ?? 0.0,
28
+ hueBlendPower: hueBlendPower ?? 1.0,
29
+ lightIntensity: lightIntensity ?? 1.0,
30
+ bloomIntensity: bloomIntensity ?? 1.0,
31
+ };
32
+
33
+ return bloomOp;
34
+ };
35
+
36
+ export const mapToF32 = <T extends Record<string, number>>(
37
+ obj: T
38
+ ): {
39
+ [K in keyof T]: ReturnType<typeof f32>;
40
+ } => {
41
+ const result = {} as any;
42
+ for (const key in obj) {
43
+ result[key] = f32(obj[key]);
44
+ }
45
+
46
+ return result;
47
+ };
48
+
49
+ export const createColorMask = (
50
+ colorMask: DeepPartiallyOptional<ColorMask, 'baseColor'>
51
+ ): ColorMask => {
52
+ const { baseColor, rgbToleranceRange } = colorMask;
53
+ const baseTolerance = {
54
+ upper: [20, 20, 20] as vec3,
55
+ lower: [20, 20, 20] as vec3,
56
+ };
57
+ const tolerance = { ...baseTolerance, ...rgbToleranceRange };
58
+
59
+ const mask: ColorMask = {
60
+ baseColor: baseColor,
61
+ rgbToleranceRange: tolerance,
62
+ };
63
+
64
+ return mask;
65
+ };
66
+
67
+ export const colorMaskToTyped = (colorMask: ColorMask) => {
68
+ const result = {
69
+ baseColor: div(numberArrToTyped(colorMask.baseColor), 255),
70
+ rgbToleranceRange: {
71
+ upper: div(numberArrToTyped(colorMask.rgbToleranceRange.upper), 255),
72
+ lower: div(numberArrToTyped(colorMask.rgbToleranceRange.lower), 255),
73
+ },
74
+ };
75
+ return result;
76
+ };
77
+
78
+ const numberArrToTyped = (vec: number[]) => {
79
+ let convFn: ((...args: number[]) => any) | null = null;
80
+ switch (vec.length) {
81
+ case 2:
82
+ convFn = vec2f;
83
+ break;
84
+ case 3:
85
+ convFn = vec3f;
86
+ break;
87
+ case 4:
88
+ convFn = vec4f;
89
+ break;
90
+ default:
91
+ throw new Error('numberArrToTyped: Vector must be of length [2-4]');
92
+ }
93
+
94
+ const typed = convFn(...vec);
95
+ return typed;
96
+ };
97
+
98
+ export const createBindGroupPair = (
99
+ bindGroupLayout: TgpuBindGroupLayout,
100
+ bindGroup: TgpuBindGroup
101
+ ): BindGroupPair => {
102
+ return { layout: bindGroupLayout, group: bindGroup };
103
+ };
104
+
105
+ export const createBindGroupPairs = (
106
+ bindGroupLayouts: TgpuBindGroupLayout[],
107
+ bindGroups: TgpuBindGroup[]
108
+ ): BindGroupPair[] => {
109
+ if (
110
+ bindGroupLayouts.length > 0 &&
111
+ bindGroupLayouts.length !== bindGroups.length
112
+ )
113
+ throw new Error(
114
+ 'createBindGroups: bindGroupLayout and bindGroup arrrays must be of the same length'
115
+ );
116
+ const pairs: BindGroupPair[] = [];
117
+ for (let i = 0; i < bindGroupLayouts.length; i++) {
118
+ pairs.push(createBindGroupPair(bindGroupLayouts[i]!, bindGroups[i]!));
119
+ }
120
+
121
+ return pairs;
122
+ };
@@ -0,0 +1,51 @@
1
+ import type { TgpuBindGroup, TgpuBindGroupLayout } from 'typegpu';
2
+
3
+ export type vec2 = [number, number];
4
+ export type vec3 = [number, number, number];
5
+ export type vec4 = [number, number, number, number];
6
+ export type quaternion = vec4;
7
+
8
+ export type BloomOptions = {
9
+ glowPower: number;
10
+ hueShiftAngleMax: number;
11
+ hueShiftAngleMin: number;
12
+ hueBlendPower: number;
13
+ lightIntensity: number;
14
+ bloomIntensity: number;
15
+ };
16
+
17
+ export type ColorMask = {
18
+ baseColor: vec3;
19
+ rgbToleranceRange: {
20
+ upper: vec3;
21
+ lower: vec3;
22
+ };
23
+ };
24
+
25
+ //makes all keys besides specified optional
26
+ export type PartiallyOptional<T, K extends keyof T> = {
27
+ [P in K]: T[P];
28
+ } & Partial<Omit<T, K>>;
29
+
30
+ export type Primitive =
31
+ | string
32
+ | number
33
+ | boolean
34
+ | bigint
35
+ | symbol
36
+ | null
37
+ | undefined;
38
+
39
+ //makes every object and its' properties optional
40
+ //unless the objects are contained in any kind of array
41
+ export type DeepPartial<T> = {
42
+ [P in keyof T]?: T[P] extends Primitive | any[] ? T[P] : DeepPartial<T[P]>;
43
+ };
44
+
45
+ export type DeepPartiallyOptional<T, K extends keyof T> = Required<Pick<T, K>> &
46
+ DeepPartial<Omit<T, K>>;
47
+
48
+ export type BindGroupPair = {
49
+ layout: TgpuBindGroupLayout;
50
+ group: TgpuBindGroup;
51
+ };