@takram/three-geospatial 0.0.1-alpha.5 → 0.0.1-alpha.7

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 (47) hide show
  1. package/build/index.cjs +1 -43
  2. package/build/index.cjs.map +1 -1
  3. package/build/index.js +403 -787
  4. package/build/index.js.map +1 -1
  5. package/build/r3f.js +2 -2
  6. package/build/shaders.cjs +397 -0
  7. package/build/shaders.cjs.map +1 -0
  8. package/build/shaders.js +408 -0
  9. package/build/shaders.js.map +1 -0
  10. package/package.json +7 -3
  11. package/src/DataLoader.ts +1 -0
  12. package/src/STBNLoader.ts +21 -0
  13. package/src/Texture3DLoader.ts +81 -0
  14. package/src/bufferGeometry.ts +2 -2
  15. package/src/constants.ts +6 -0
  16. package/src/defineShorthand.ts +68 -0
  17. package/src/index.ts +5 -10
  18. package/src/math.ts +36 -1
  19. package/src/r3f/index.ts +1 -0
  20. package/src/r3f/types.ts +63 -0
  21. package/src/resolveIncludes.test.ts +21 -0
  22. package/src/resolveIncludes.ts +22 -0
  23. package/src/shaders/cascadedShadowMaps.glsl +79 -0
  24. package/src/shaders/depth.glsl +3 -1
  25. package/src/shaders/generators.glsl +9 -0
  26. package/src/shaders/index.ts +19 -0
  27. package/src/shaders/math.glsl +92 -0
  28. package/src/shaders/poissonDisk.glsl +23 -0
  29. package/src/shaders/raySphereIntersection.glsl +134 -0
  30. package/src/shaders/turbo.glsl +9 -0
  31. package/src/typedArrayParsers.ts +19 -8
  32. package/src/types.ts +5 -51
  33. package/src/unrollLoops.ts +23 -0
  34. package/types/DataLoader.d.ts +4 -4
  35. package/types/STBNLoader.d.ts +1 -0
  36. package/types/Texture3DLoader.d.ts +5 -0
  37. package/types/TypedArrayLoader.d.ts +3 -3
  38. package/types/constants.d.ts +4 -0
  39. package/types/defineShorthand.d.ts +16 -0
  40. package/types/index.d.ts +5 -3
  41. package/types/math.d.ts +4 -1
  42. package/types/r3f/index.d.ts +1 -0
  43. package/types/r3f/types.d.ts +21 -0
  44. package/types/resolveIncludes.d.ts +5 -0
  45. package/types/shaders/index.d.ts +9 -0
  46. package/types/types.d.ts +5 -20
  47. package/types/unrollLoops.d.ts +1 -0
package/src/math.ts CHANGED
@@ -10,7 +10,42 @@ export const isPowerOfTwo = MathUtils.isPowerOfTwo
10
10
  export const ceilPowerOfTwo = MathUtils.ceilPowerOfTwo
11
11
  export const floorPowerOfTwo = MathUtils.floorPowerOfTwo
12
12
  export const normalize = MathUtils.normalize
13
- export const remap = MathUtils.mapLinear
13
+
14
+ export function remap(x: number, min1: number, max1: number): number
15
+ export function remap(
16
+ x: number,
17
+ min1: number,
18
+ max1: number,
19
+ min2: number,
20
+ max2: number
21
+ ): number
22
+ export function remap(
23
+ x: number,
24
+ min1: number,
25
+ max1: number,
26
+ min2 = 0,
27
+ max2 = 1
28
+ ): number {
29
+ return MathUtils.mapLinear(x, min1, max1, min2, max2)
30
+ }
31
+
32
+ export function remapClamped(x: number, min1: number, max1: number): number
33
+ export function remapClamped(
34
+ x: number,
35
+ min1: number,
36
+ max1: number,
37
+ min2: number,
38
+ max2: number
39
+ ): number
40
+ export function remapClamped(
41
+ x: number,
42
+ min1: number,
43
+ max1: number,
44
+ min2 = 0,
45
+ max2 = 1
46
+ ): number {
47
+ return clamp(MathUtils.mapLinear(x, min1, max1, min2, max2), min2, max2)
48
+ }
14
49
 
15
50
  // Prefer glsl's argument order which differs from that of MathUtils.
16
51
  export function smoothstep(min: number, max: number, x: number): number {
package/src/r3f/index.ts CHANGED
@@ -1,2 +1,3 @@
1
1
  export * from './EastNorthUpFrame'
2
2
  export * from './EllipsoidMesh'
3
+ export * from './types'
@@ -0,0 +1,63 @@
1
+ import {
2
+ type NodeProps,
3
+ type Overwrite,
4
+ type Color as R3FColor,
5
+ type Vector2 as R3FVector2,
6
+ type Vector3 as R3FVector3,
7
+ type Vector4 as R3FVector4
8
+ } from '@react-three/fiber'
9
+ import {
10
+ type Color as ColorImpl,
11
+ type Vector2 as Vector2Impl,
12
+ type Vector3 as Vector3Impl,
13
+ type Vector4 as Vector4Impl
14
+ } from 'three'
15
+ import { type WritableKeysOf } from 'type-fest'
16
+
17
+ import { type Callable } from '../types'
18
+
19
+ // prettier-ignore
20
+ export type ExtendedProps<T> = {
21
+ [K in keyof T]:
22
+ Vector2Impl extends T[K] ? R3FVector2 | T[K] :
23
+ Vector3Impl extends T[K] ? R3FVector3 | T[K] :
24
+ Vector4Impl extends T[K] ? R3FVector4 | T[K] :
25
+ ColorImpl extends T[K] ? R3FColor | T[K] :
26
+ T[K]
27
+ }
28
+
29
+ // @react-three/fiber's NonFunctionKeys cannot exclude partial functions.
30
+ // This excludes callback properties, which may be undesirable behavior.
31
+ type NonFunctionKeys<T> = keyof {
32
+ [K in keyof T as Callable extends T[K] ? never : K]: any
33
+ }
34
+
35
+ // prettier-ignore
36
+ type WritableNonExtendableKeysOf<T> =
37
+ | WritableKeysOf<T>
38
+ | keyof {
39
+ [K in keyof T as
40
+ Vector2Impl extends T[K] ? K :
41
+ Vector3Impl extends T[K] ? K :
42
+ Vector4Impl extends T[K] ? K :
43
+ ColorImpl extends T[K] ? K :
44
+ never
45
+ ]: any
46
+ }
47
+
48
+ export type PassThoughInstanceProps<
49
+ RefType,
50
+ Args extends readonly any[],
51
+ Props
52
+ > = Overwrite<
53
+ ExtendedProps<{
54
+ [K in NonFunctionKeys<Props> as K extends WritableNonExtendableKeysOf<Props>
55
+ ? K
56
+ : never]: Props[K]
57
+ }>,
58
+ NodeProps<RefType, Args>
59
+ >
60
+
61
+ export type ExpandNestedProps<T, Prop extends keyof T & string> = {
62
+ [K in keyof T[Prop] as K extends string ? `${Prop}-${K}` : never]: T[Prop][K]
63
+ }
@@ -0,0 +1,21 @@
1
+ import { resolveIncludes } from './resolveIncludes'
2
+
3
+ describe('resolveIncludes', () => {
4
+ test('delimited paths', () => {
5
+ expect(
6
+ resolveIncludes('#include "scope/lib"', {
7
+ scope: {
8
+ lib: 'imported'
9
+ }
10
+ })
11
+ ).toBe('imported')
12
+
13
+ expect(() =>
14
+ resolveIncludes('#include "scope/lib"', {
15
+ other: {
16
+ lib: 'imported'
17
+ }
18
+ })
19
+ ).toThrow()
20
+ })
21
+ })
@@ -0,0 +1,22 @@
1
+ const includePattern = /^[ \t]*#include +"([\w\d./]+)"/gm
2
+
3
+ interface Includes {
4
+ [key: string]: string | Includes
5
+ }
6
+
7
+ export function resolveIncludes(source: string, includes: Includes): string {
8
+ return source.replace(includePattern, (match, path: string) => {
9
+ const components = path.split('/')
10
+ const include = components.reduce<string | Includes | undefined>(
11
+ (parent, component) =>
12
+ typeof parent !== 'string' && parent != null
13
+ ? parent[component]
14
+ : undefined,
15
+ includes
16
+ )
17
+ if (typeof include !== 'string') {
18
+ throw new Error(`Could not find include for ${path}.`)
19
+ }
20
+ return resolveIncludes(include, includes)
21
+ })
22
+ }
@@ -0,0 +1,79 @@
1
+ // Reference: https://github.com/mrdoob/three.js/blob/r171/examples/jsm/csm/CSMShader.js
2
+
3
+ #ifndef SHADOW_CASCADE_COUNT
4
+ #error "SHADOW_CASCADE_COUNT macro must be defined."
5
+ #endif // SHADOW_CASCADE_COUNT
6
+
7
+ int getCascadeIndex(
8
+ const mat4 viewMatrix,
9
+ const vec3 worldPosition,
10
+ const vec2 intervals[SHADOW_CASCADE_COUNT],
11
+ const float near,
12
+ const float far
13
+ ) {
14
+ vec4 viewPosition = viewMatrix * vec4(worldPosition, 1.0);
15
+ float depth = viewZToOrthographicDepth(viewPosition.z, near, far);
16
+ vec2 interval;
17
+ #pragma unroll_loop_start
18
+ for (int i = 0; i < 4; ++i) {
19
+ #if UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT
20
+ interval = intervals[i];
21
+ if (depth >= interval.x && depth < interval.y) {
22
+ return UNROLLED_LOOP_INDEX;
23
+ }
24
+ #endif // UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT
25
+ }
26
+ #pragma unroll_loop_end
27
+ return SHADOW_CASCADE_COUNT - 1;
28
+ }
29
+
30
+ int getFadedCascadeIndex(
31
+ const mat4 viewMatrix,
32
+ const vec3 worldPosition,
33
+ const vec2 intervals[SHADOW_CASCADE_COUNT],
34
+ const float near,
35
+ const float far,
36
+ const float jitter
37
+ ) {
38
+ vec4 viewPosition = viewMatrix * vec4(worldPosition, 1.0);
39
+ float depth = viewZToOrthographicDepth(viewPosition.z, near, far);
40
+
41
+ vec2 interval;
42
+ float intervalCenter;
43
+ float closestEdge;
44
+ float margin;
45
+ int nextIndex = -1;
46
+ int prevIndex = -1;
47
+ float alpha;
48
+
49
+ #pragma unroll_loop_start
50
+ for (int i = 0; i < 4; ++i) {
51
+ #if UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT
52
+ interval = intervals[i];
53
+ intervalCenter = (interval.x + interval.y) * 0.5;
54
+ closestEdge = depth < intervalCenter ? interval.x : interval.y;
55
+ margin = closestEdge * closestEdge * 0.5;
56
+ interval += margin * vec2(-0.5, 0.5);
57
+
58
+ #if UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT - 1
59
+ if (depth >= interval.x && depth < interval.y) {
60
+ prevIndex = nextIndex;
61
+ nextIndex = UNROLLED_LOOP_INDEX;
62
+ alpha = saturate(min(depth - interval.x, interval.y - depth) / margin);
63
+ }
64
+ #else // UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT - 1
65
+ // Don't fade out the last cascade.
66
+ if (depth >= interval.x) {
67
+ prevIndex = nextIndex;
68
+ nextIndex = UNROLLED_LOOP_INDEX;
69
+ alpha = saturate((depth - interval.x) / margin);
70
+ }
71
+ #endif // UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT - 1
72
+ #endif // UNROLLED_LOOP_INDEX < SHADOW_CASCADE_COUNT
73
+ }
74
+ #pragma unroll_loop_end
75
+
76
+ return jitter <= alpha
77
+ ? nextIndex
78
+ : prevIndex;
79
+ }
@@ -1,10 +1,12 @@
1
+ // cSpell:words logdepthbuf
2
+
1
3
  float reverseLogDepth(const float depth, const float near, const float far) {
2
4
  #ifdef USE_LOGDEPTHBUF
3
5
  float d = pow(2.0, depth * log2(far + 1.0)) - 1.0;
4
6
  float a = far / (far - near);
5
7
  float b = far * near / (near - far);
6
8
  return a + b / d;
7
- #else
9
+ #else // USE_LOGDEPTHBUF
8
10
  return depth;
9
11
  #endif // USE_LOGDEPTHBUF
10
12
  }
@@ -0,0 +1,9 @@
1
+ float checker(const vec2 uv, const vec2 repeats) {
2
+ vec2 c = floor(repeats * uv);
3
+ float result = mod(c.x + c.y, 2.0);
4
+ return sign(result);
5
+ }
6
+
7
+ float checker(const vec2 uv, const float repeats) {
8
+ return checker(uv, vec2(repeats));
9
+ }
@@ -0,0 +1,19 @@
1
+ import _cascadedShadowMaps from './cascadedShadowMaps.glsl?raw'
2
+ import _depth from './depth.glsl?raw'
3
+ import _generators from './generators.glsl?raw'
4
+ import _math from './math.glsl?raw'
5
+ import _packing from './packing.glsl?raw'
6
+ import _poissonDisk from './poissonDisk.glsl?raw'
7
+ import _raySphereIntersection from './raySphereIntersection.glsl?raw'
8
+ import _transform from './transform.glsl?raw'
9
+ import _turbo from './turbo.glsl?raw'
10
+
11
+ export const cascadedShadowMaps: string = _cascadedShadowMaps
12
+ export const depth: string = _depth
13
+ export const generators: string = _generators
14
+ export const math: string = _math
15
+ export const packing: string = _packing
16
+ export const poissonDisk: string = _poissonDisk
17
+ export const raySphereIntersection: string = _raySphereIntersection
18
+ export const transform: string = _transform
19
+ export const turbo: string = _turbo
@@ -0,0 +1,92 @@
1
+ #if !defined(saturate)
2
+ #define saturate(a) clamp(a, 0.0, 1.0)
3
+ #endif // !defined(saturate)
4
+
5
+ float remap(const float x, const float min1, const float max1, const float min2, const float max2) {
6
+ return min2 + (x - min1) / (max1 - min1) * (max2 - min2);
7
+ }
8
+
9
+ vec2 remap(const vec2 x, const vec2 min1, const vec2 max1, const vec2 min2, const vec2 max2) {
10
+ return min2 + (x - min1) / (max1 - min1) * (max2 - min2);
11
+ }
12
+
13
+ vec3 remap(const vec3 x, const vec3 min1, const vec3 max1, const vec3 min2, const vec3 max2) {
14
+ return min2 + (x - min1) / (max1 - min1) * (max2 - min2);
15
+ }
16
+
17
+ vec4 remap(const vec4 x, const vec4 min1, const vec4 max1, const vec4 min2, const vec4 max2) {
18
+ return min2 + (x - min1) / (max1 - min1) * (max2 - min2);
19
+ }
20
+
21
+ float remapClamped(
22
+ const float x,
23
+ const float min1,
24
+ const float max1,
25
+ const float min2,
26
+ const float max2
27
+ ) {
28
+ return clamp(min2 + (x - min1) / (max1 - min1) * (max2 - min2), min2, max2);
29
+ }
30
+
31
+ vec2 remapClamped(
32
+ const vec2 x,
33
+ const vec2 min1,
34
+ const vec2 max1,
35
+ const vec2 min2,
36
+ const vec2 max2
37
+ ) {
38
+ return clamp(min2 + (x - min1) / (max1 - min1) * (max2 - min2), min2, max2);
39
+ }
40
+
41
+ vec3 remapClamped(
42
+ const vec3 x,
43
+ const vec3 min1,
44
+ const vec3 max1,
45
+ const vec3 min2,
46
+ const vec3 max2
47
+ ) {
48
+ return clamp(min2 + (x - min1) / (max1 - min1) * (max2 - min2), min2, max2);
49
+ }
50
+
51
+ vec4 remapClamped(
52
+ const vec4 x,
53
+ const vec4 min1,
54
+ const vec4 max1,
55
+ const vec4 min2,
56
+ const vec4 max2
57
+ ) {
58
+ return clamp(min2 + (x - min1) / (max1 - min1) * (max2 - min2), min2, max2);
59
+ }
60
+
61
+ // Implicitly remap to 0 and 1
62
+ float remap(const float x, const float min1, const float max1) {
63
+ return (x - min1) / (max1 - min1);
64
+ }
65
+
66
+ vec2 remap(const vec2 x, const vec2 min1, const vec2 max1) {
67
+ return (x - min1) / (max1 - min1);
68
+ }
69
+
70
+ vec3 remap(const vec3 x, const vec3 min1, const vec3 max1) {
71
+ return (x - min1) / (max1 - min1);
72
+ }
73
+
74
+ vec4 remap(const vec4 x, const vec4 min1, const vec4 max1) {
75
+ return (x - min1) / (max1 - min1);
76
+ }
77
+
78
+ float remapClamped(const float x, const float min1, const float max1) {
79
+ return saturate((x - min1) / (max1 - min1));
80
+ }
81
+
82
+ vec2 remapClamped(const vec2 x, const vec2 min1, const vec2 max1) {
83
+ return saturate((x - min1) / (max1 - min1));
84
+ }
85
+
86
+ vec3 remapClamped(const vec3 x, const vec3 min1, const vec3 max1) {
87
+ return saturate((x - min1) / (max1 - min1));
88
+ }
89
+
90
+ vec4 remapClamped(const vec4 x, const vec4 min1, const vec4 max1) {
91
+ return saturate((x - min1) / (max1 - min1));
92
+ }
@@ -0,0 +1,23 @@
1
+ // TODO: Maybe switch to Vogel disk with IGN:
2
+ // https://www.gamedev.net/tutorials/programming/graphics/contact-hardening-soft-shadows-made-fast-r4906/
3
+ // Taken from: https://developer.download.nvidia.com/whitepapers/2008/PCSS_Integration.pdf
4
+ const vec2 poissonDisk[16] = vec2[16](
5
+ vec2(-0.94201624, -0.39906216),
6
+ vec2(0.94558609, -0.76890725),
7
+ vec2(-0.094184101, -0.9293887),
8
+ vec2(0.34495938, 0.2938776),
9
+ vec2(-0.91588581, 0.45771432),
10
+ vec2(-0.81544232, -0.87912464),
11
+ vec2(-0.38277543, 0.27676845),
12
+ vec2(0.97484398, 0.75648379),
13
+ vec2(0.44323325, -0.97511554),
14
+ vec2(0.53742981, -0.4737342),
15
+ vec2(-0.26496911, -0.41893023),
16
+ vec2(0.79197514, 0.19090188),
17
+ vec2(-0.2418884, 0.99706507),
18
+ vec2(-0.81409955, 0.9143759),
19
+ vec2(0.19984126, 0.78641367),
20
+ vec2(0.14383161, -0.1410079)
21
+ );
22
+
23
+ #define POISSON_DISK_COUNT (16)
@@ -0,0 +1,134 @@
1
+ float raySphereFirstIntersection(
2
+ const vec3 origin,
3
+ const vec3 direction,
4
+ const vec3 center,
5
+ const float radius
6
+ ) {
7
+ vec3 a = origin - center;
8
+ float b = 2.0 * dot(direction, a);
9
+ float c = dot(a, a) - radius * radius;
10
+ float discriminant = b * b - 4.0 * c;
11
+ return discriminant < 0.0
12
+ ? -1.0
13
+ : (-b - sqrt(discriminant)) * 0.5;
14
+ }
15
+
16
+ float raySphereFirstIntersection(const vec3 origin, const vec3 direction, const float radius) {
17
+ return raySphereFirstIntersection(origin, direction, vec3(0.0), radius);
18
+ }
19
+
20
+ vec4 raySphereFirstIntersection(
21
+ const vec3 origin,
22
+ const vec3 direction,
23
+ const vec3 center,
24
+ const vec4 radius
25
+ ) {
26
+ vec3 a = origin - center;
27
+ float b = 2.0 * dot(direction, a);
28
+ vec4 c = dot(a, a) - radius * radius;
29
+ vec4 discriminant = b * b - 4.0 * c;
30
+ vec4 mask = step(discriminant, vec4(0.0));
31
+ return mix((-b - sqrt(max(vec4(0.0), discriminant))) * 0.5, vec4(-1.0), mask);
32
+ }
33
+
34
+ vec4 raySphereFirstIntersection(const vec3 origin, const vec3 direction, const vec4 radius) {
35
+ return raySphereFirstIntersection(origin, direction, vec3(0.0), radius);
36
+ }
37
+
38
+ float raySphereSecondIntersection(
39
+ const vec3 origin,
40
+ const vec3 direction,
41
+ const vec3 center,
42
+ const float radius
43
+ ) {
44
+ vec3 a = origin - center;
45
+ float b = 2.0 * dot(direction, a);
46
+ float c = dot(a, a) - radius * radius;
47
+ float discriminant = b * b - 4.0 * c;
48
+ return discriminant < 0.0
49
+ ? -1.0
50
+ : (-b + sqrt(discriminant)) * 0.5;
51
+ }
52
+
53
+ float raySphereSecondIntersection(const vec3 origin, const vec3 direction, const float radius) {
54
+ return raySphereSecondIntersection(origin, direction, vec3(0.0), radius);
55
+ }
56
+
57
+ vec4 raySphereSecondIntersection(
58
+ const vec3 origin,
59
+ const vec3 direction,
60
+ const vec3 center,
61
+ const vec4 radius
62
+ ) {
63
+ vec3 a = origin - center;
64
+ float b = 2.0 * dot(direction, a);
65
+ vec4 c = dot(a, a) - radius * radius;
66
+ vec4 discriminant = b * b - 4.0 * c;
67
+ vec4 mask = step(discriminant, vec4(0.0));
68
+ return mix((-b + sqrt(max(vec4(0.0), discriminant))) * 0.5, vec4(-1.0), mask);
69
+ }
70
+
71
+ vec4 raySphereSecondIntersection(const vec3 origin, const vec3 direction, const vec4 radius) {
72
+ return raySphereSecondIntersection(origin, direction, vec3(0.0), radius);
73
+ }
74
+
75
+ void raySphereIntersections(
76
+ const vec3 origin,
77
+ const vec3 direction,
78
+ const vec3 center,
79
+ const float radius,
80
+ out float intersection1,
81
+ out float intersection2
82
+ ) {
83
+ vec3 a = origin - center;
84
+ float b = 2.0 * dot(direction, a);
85
+ float c = dot(a, a) - radius * radius;
86
+ float discriminant = b * b - 4.0 * c;
87
+ if (discriminant < 0.0) {
88
+ intersection1 = -1.0;
89
+ intersection2 = -1.0;
90
+ return;
91
+ } else {
92
+ float Q = sqrt(discriminant);
93
+ intersection1 = (-b - Q) * 0.5;
94
+ intersection2 = (-b + Q) * 0.5;
95
+ }
96
+ }
97
+
98
+ void raySphereIntersections(
99
+ const vec3 origin,
100
+ const vec3 direction,
101
+ const float radius,
102
+ out float intersection1,
103
+ out float intersection2
104
+ ) {
105
+ raySphereIntersections(origin, direction, vec3(0.0), radius, intersection1, intersection2);
106
+ }
107
+
108
+ void raySphereIntersections(
109
+ const vec3 origin,
110
+ const vec3 direction,
111
+ const vec3 center,
112
+ const vec4 radius,
113
+ out vec4 intersection1,
114
+ out vec4 intersection2
115
+ ) {
116
+ vec3 a = origin - center;
117
+ float b = 2.0 * dot(direction, a);
118
+ vec4 c = dot(a, a) - radius * radius;
119
+ vec4 discriminant = b * b - 4.0 * c;
120
+ vec4 mask = step(discriminant, vec4(0.0));
121
+ vec4 Q = sqrt(max(vec4(0.0), discriminant));
122
+ intersection1 = mix((-b - Q) * 0.5, vec4(-1.0), mask);
123
+ intersection2 = mix((-b + Q) * 0.5, vec4(-1.0), mask);
124
+ }
125
+
126
+ void raySphereIntersections(
127
+ const vec3 origin,
128
+ const vec3 direction,
129
+ const vec4 radius,
130
+ out vec4 intersection1,
131
+ out vec4 intersection2
132
+ ) {
133
+ raySphereIntersections(origin, direction, vec3(0.0), radius, intersection1, intersection2);
134
+ }
@@ -0,0 +1,9 @@
1
+ // A fifth-order polynomial approximation of Turbo color map.
2
+ // See: https://observablehq.com/@mbostock/turbo
3
+ // prettier-ignore
4
+ vec3 turbo(const float x) {
5
+ float r = 0.1357 + x * (4.5974 - x * (42.3277 - x * (130.5887 - x * (150.5666 - x * 58.1375))));
6
+ float g = 0.0914 + x * (2.1856 + x * (4.8052 - x * (14.0195 - x * (4.2109 + x * 2.7747))));
7
+ float b = 0.1067 + x * (12.5925 - x * (60.1097 - x * (109.0745 - x * (88.5066 - x * 26.8183))));
8
+ return vec3(r, g, b);
9
+ }
@@ -1,5 +1,17 @@
1
1
  import { type TypedArray, type TypedArrayConstructor } from './typedArray'
2
2
 
3
+ let hostLittleEndian: boolean | undefined
4
+
5
+ function isHostLittleEndian(): boolean {
6
+ if (hostLittleEndian != null) {
7
+ return hostLittleEndian
8
+ }
9
+ const a = new Uint32Array([0x10000000])
10
+ const b = new Uint8Array(a.buffer, a.byteOffset, a.byteLength)
11
+ hostLittleEndian = b[0] === 0
12
+ return hostLittleEndian
13
+ }
14
+
3
15
  type GetValue = keyof {
4
16
  [K in keyof DataView as DataView[K] extends (byteOffset: number) => number
5
17
  ? K
@@ -19,6 +31,9 @@ function parseTypedArray<K extends GetValue>(
19
31
  getValue: K,
20
32
  littleEndian = true
21
33
  ): TypedArray {
34
+ if (littleEndian === isHostLittleEndian()) {
35
+ return new TypedArray(buffer)
36
+ }
22
37
  const data = new DataView(buffer)
23
38
  const array = new TypedArray(data.byteLength / TypedArray.BYTES_PER_ELEMENT)
24
39
  for (
@@ -36,15 +51,11 @@ export type TypedArrayParser<T extends TypedArray> = (
36
51
  littleEndian?: boolean
37
52
  ) => T
38
53
 
39
- export const parseUint8Array: TypedArrayParser<Uint8Array> = (
40
- buffer,
41
- littleEndian
42
- ) => parseTypedArray(buffer, Uint8Array, 'getUint8', littleEndian)
54
+ export const parseUint8Array: TypedArrayParser<Uint8Array> = buffer =>
55
+ new Uint8Array(buffer)
43
56
 
44
- export const parseInt8Array: TypedArrayParser<Int8Array> = (
45
- buffer,
46
- littleEndian
47
- ) => parseTypedArray(buffer, Int8Array, 'getInt8', littleEndian)
57
+ export const parseInt8Array: TypedArrayParser<Int8Array> = buffer =>
58
+ new Int8Array(buffer)
48
59
 
49
60
  export const parseUint16Array: TypedArrayParser<Uint16Array> = (
50
61
  buffer,
package/src/types.ts CHANGED
@@ -1,54 +1,8 @@
1
- import {
2
- type Matrix2,
3
- type Matrix3,
4
- type Matrix4,
5
- type Vector2,
6
- type Vector3,
7
- type Vector4
8
- } from 'three'
9
- import { type ReadonlyTuple } from 'type-fest'
1
+ import { type Uniform } from 'three'
10
2
 
11
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
12
3
  export type Callable = (...args: any) => any
13
4
 
14
- export type ReadonlyTuple2<T = number> = ReadonlyTuple<T, 2>
15
- export type ReadonlyTuple3<T = number> = ReadonlyTuple<T, 3>
16
- export type ReadonlyTuple4<T = number> = ReadonlyTuple<T, 4>
17
-
18
- // Non-readonly version of ReadonlyTuple. This is not type-safe because mutable
19
- // methods still exist in the type.
20
- // See https://github.com/sindresorhus/type-fest/blob/main/source/readonly-tuple.d.ts
21
- type BuildTupleHelper<
22
- Element,
23
- Length extends number,
24
- Rest extends Element[]
25
- > = Rest['length'] extends Length
26
- ? [...Rest]
27
- : BuildTupleHelper<Element, Length, [Element, ...Rest]>
28
-
29
- export type Tuple<T, Length extends number> = number extends Length
30
- ? readonly T[]
31
- : BuildTupleHelper<T, Length, []>
32
-
33
- export type Tuple2<T = number> = BuildTupleHelper<T, 2, []>
34
- export type Tuple3<T = number> = BuildTupleHelper<T, 3, []>
35
- export type Tuple4<T = number> = BuildTupleHelper<T, 4, []>
36
-
37
- // Suppose return type of the mutable methods of classes like Vector3 is `this`.
38
- // TODO: How can we specify `this` as a constraint?
39
- type ReadonlyThreeInstance<T> = Readonly<{
40
- [K in keyof T as T[K] extends Callable
41
- ? ReturnType<T[K]> extends T
42
- ? K extends 'clone'
43
- ? K
44
- : never
45
- : K
46
- : K]: T[K]
47
- }>
48
-
49
- export type ReadonlyVector2 = ReadonlyThreeInstance<Vector2>
50
- export type ReadonlyVector3 = ReadonlyThreeInstance<Vector3>
51
- export type ReadonlyVector4 = ReadonlyThreeInstance<Vector4>
52
- export type ReadonlyMatrix2 = ReadonlyThreeInstance<Matrix2>
53
- export type ReadonlyMatrix3 = ReadonlyThreeInstance<Matrix3>
54
- export type ReadonlyMatrix4 = ReadonlyThreeInstance<Matrix4>
5
+ export type UniformMap<T> = Omit<Map<string, Uniform>, 'get'> & {
6
+ get: <K extends keyof T>(key: K) => T[K]
7
+ set: <K extends keyof T>(key: K, value: T[K]) => void
8
+ }
@@ -0,0 +1,23 @@
1
+ // Based on: https://github.com/mrdoob/three.js/blob/r170/src/renderers/webgl/WebGLProgram.js#L294
2
+
3
+ const unrollLoopPattern =
4
+ /#pragma unroll_loop_start\s+for\s*\(\s*int\s+i\s*=\s*(\d+)\s*;\s*i\s*<\s*(\d+)\s*;\s*(?:i\s*\+\+|\+\+\s*i)\s*\)\s*{([\s\S]+?)}\s+#pragma unroll_loop_end/g
5
+
6
+ function loopReplacer(
7
+ match: string,
8
+ start: string,
9
+ end: string,
10
+ snippet: string
11
+ ): string {
12
+ let string = ''
13
+ for (let i = parseInt(start); i < parseInt(end); ++i) {
14
+ string += snippet
15
+ .replace(/\[\s*i\s*\]/g, '[' + i + ']')
16
+ .replace(/UNROLLED_LOOP_INDEX/g, `${i}`)
17
+ }
18
+ return string
19
+ }
20
+
21
+ export function unrollLoops(string: string): string {
22
+ return string.replace(unrollLoopPattern, loopReplacer)
23
+ }