typegpu 0.12.0 → 0.12.2

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/std/boolean.d.ts CHANGED
@@ -16,7 +16,7 @@ export declare const allEq: import("../types.ts").DualFn<(<T extends AnyVecInsta
16
16
  * all(eq(vec4i(4, 3, 2, 1), vec4i(4, 3, 2, 1))) // returns true
17
17
  * allEq(vec4i(4, 3, 2, 1), vec4i(4, 3, 2, 1)) // returns true
18
18
  */
19
- export declare const eq: import("../types.ts").DualFn<(<T extends AnyVecInstance>(lhs: T, rhs: T) => T extends AnyVec2Instance ? v2b : T extends AnyVec3Instance ? v3b : v4b)>;
19
+ export declare const eq: import("../types.ts").DualFn<(<T extends AnyVecInstance>(lhs: T, rhs: T) => import("../data/generalizeFn.ts").ToBool<T>)>;
20
20
  /**
21
21
  * Checks **component-wise** whether `lhs != rhs`.
22
22
  * This function does **not** return `bool`, for that use-case, wrap the result in `any`.
@@ -25,7 +25,7 @@ export declare const eq: import("../types.ts").DualFn<(<T extends AnyVecInstance
25
25
  * ne(vec3u(0, 1, 2), vec3u(2, 1, 0)) // returns vec3b(true, false, true)
26
26
  * any(ne(vec4i(4, 3, 2, 1), vec4i(4, 2, 2, 1))) // returns true
27
27
  */
28
- export declare const ne: import("../types.ts").DualFn<(<T extends AnyVecInstance>(lhs: T, rhs: T) => T extends AnyVec2Instance ? v2b : T extends AnyVec3Instance ? v3b : v4b)>;
28
+ export declare const ne: import("../types.ts").DualFn<(<T extends AnyVecInstance>(lhs: T, rhs: T) => import("../data/generalizeFn.ts").ToBool<T>)>;
29
29
  /**
30
30
  * Checks **component-wise** whether `lhs < rhs`.
31
31
  * This function does **not** return `bool`, for that use-case, wrap the result in `all`.
@@ -34,7 +34,7 @@ export declare const ne: import("../types.ts").DualFn<(<T extends AnyVecInstance
34
34
  * lt(vec3u(0, 1, 2), vec3u(2, 1, 0)) // returns vec3b(true, false, false)
35
35
  * all(lt(vec4i(1, 2, 3, 4), vec4i(2, 3, 4, 5))) // returns true
36
36
  */
37
- export declare const lt: import("../types.ts").DualFn<(<T extends AnyNumericVecInstance>(lhs: T, rhs: T) => T extends AnyVec2Instance ? v2b : T extends AnyVec3Instance ? v3b : v4b)>;
37
+ export declare const lt: import("../types.ts").DualFn<(<T extends AnyNumericVecInstance>(lhs: T, rhs: T) => import("../data/generalizeFn.ts").ToBool<T>)>;
38
38
  /**
39
39
  * Checks **component-wise** whether `lhs <= rhs`.
40
40
  * This function does **not** return `bool`, for that use-case, wrap the result in `all`.
@@ -43,7 +43,7 @@ export declare const lt: import("../types.ts").DualFn<(<T extends AnyNumericVecI
43
43
  * le(vec3u(0, 1, 2), vec3u(2, 1, 0)) // returns vec3b(true, true, false)
44
44
  * all(le(vec4i(1, 2, 3, 4), vec4i(2, 3, 3, 5))) // returns true
45
45
  */
46
- export declare const le: import("../types.ts").DualFn<(<T extends AnyNumericVecInstance>(lhs: T, rhs: T) => T extends AnyVec2Instance ? v2b : T extends AnyVec3Instance ? v3b : v4b)>;
46
+ export declare const le: import("../types.ts").DualFn<(<T extends AnyNumericVecInstance>(lhs: T, rhs: T) => import("../data/generalizeFn.ts").ToBool<import("../data/generalizeFn.ts").ToBool<T>>)>;
47
47
  /**
48
48
  * Checks **component-wise** whether `lhs > rhs`.
49
49
  * This function does **not** return `bool`, for that use-case, wrap the result in `all`.
@@ -52,7 +52,7 @@ export declare const le: import("../types.ts").DualFn<(<T extends AnyNumericVecI
52
52
  * gt(vec3u(0, 1, 2), vec3u(2, 1, 0)) // returns vec3b(false, false, true)
53
53
  * all(gt(vec4i(2, 3, 4, 5), vec4i(1, 2, 3, 4))) // returns true
54
54
  */
55
- export declare const gt: import("../types.ts").DualFn<(<T extends AnyNumericVecInstance>(lhs: T, rhs: T) => T extends AnyVec2Instance ? v2b : T extends AnyVec3Instance ? v3b : v4b)>;
55
+ export declare const gt: import("../types.ts").DualFn<(<T extends AnyNumericVecInstance>(lhs: T, rhs: T) => import("../data/generalizeFn.ts").ToBool<import("../data/generalizeFn.ts").ToBool<T>>)>;
56
56
  /**
57
57
  * Checks **component-wise** whether `lhs >= rhs`.
58
58
  * This function does **not** return `bool`, for that use-case, wrap the result in `all`.
@@ -61,7 +61,7 @@ export declare const gt: import("../types.ts").DualFn<(<T extends AnyNumericVecI
61
61
  * ge(vec3u(0, 1, 2), vec3u(2, 1, 0)) // returns vec3b(false, true, true)
62
62
  * all(ge(vec4i(2, 2, 4, 5), vec4i(1, 2, 3, 4))) // returns true
63
63
  */
64
- export declare const ge: import("../types.ts").DualFn<(<T extends AnyNumericVecInstance>(lhs: T, rhs: T) => T extends AnyVec2Instance ? v2b : T extends AnyVec3Instance ? v3b : v4b)>;
64
+ export declare const ge: import("../types.ts").DualFn<(<T extends AnyNumericVecInstance>(lhs: T, rhs: T) => import("../data/generalizeFn.ts").ToBool<T>)>;
65
65
  declare function cpuNot(value: boolean): boolean;
66
66
  declare function cpuNot<T extends AnyBooleanVecInstance>(value: T): T;
67
67
  /**
@@ -79,14 +79,14 @@ export declare const not: import("../types.ts").DualFn<typeof cpuNot>;
79
79
  * or(vec2b(false, true), vec2b(false, false)) // returns vec2b(false, true)
80
80
  * or(vec3b(true, true, false), vec3b(false, true, false)) // returns vec3b(true, true, false)
81
81
  */
82
- export declare const or: import("../types.ts").DualFn<(<T extends AnyBooleanVecInstance>(lhs: T, rhs: T) => T)>;
82
+ export declare const or: import("../types.ts").DualFn<(<T extends AnyBooleanVecInstance>(lhs: T, rhs: T) => import("../data/generalizeFn.ts").ToBool<T>)>;
83
83
  /**
84
84
  * Returns **component-wise** logical `and` result.
85
85
  * @example
86
86
  * and(vec2b(false, true), vec2b(true, true)) // returns vec2b(false, true)
87
87
  * and(vec3b(true, true, false), vec3b(false, true, false)) // returns vec3b(false, true, false)
88
88
  */
89
- export declare const and: import("../types.ts").DualFn<(<T extends AnyBooleanVecInstance>(lhs: T, rhs: T) => T)>;
89
+ export declare const and: import("../types.ts").DualFn<(<T extends AnyBooleanVecInstance>(lhs: T, rhs: T) => import("../data/generalizeFn.ts").ToBool<T>)>;
90
90
  /**
91
91
  * Returns `true` if each component of `value` is true.
92
92
  * @example
package/std/boolean.js CHANGED
@@ -4,11 +4,11 @@ import { bool, f16, f32, i32, u32 } from "../data/numeric.js";
4
4
  import { isSnippetNumeric, snip } from "../data/snippet.js";
5
5
  import { vec2b, vec2f, vec2h, vec2i, vec2u, vec3b, vec3f, vec3h, vec3i, vec3u, vec4b, vec4f, vec4h, vec4i, vec4u, } from "../data/vector.js";
6
6
  import { VectorOps } from "../data/vectorOps.js";
7
- import { isBool, isVecBool, isVecBoolInstance, isVecInstance, } from "../data/wgslTypes.js";
7
+ import { generalizeBoolFn, generalizeFn } from "../data/generalizeFn.js";
8
+ import { isBool, isVecBool, isVecBoolInstance, } from "../data/wgslTypes.js";
8
9
  import { SignatureNotSupportedError } from "../errors.js";
9
10
  import { unify } from "../tgsl/conversion.js";
10
11
  import { cpuCopy } from "./copy.js";
11
- import { sub } from "./operators.js";
12
12
  function correspondingBooleanVectorSchema(dataType) {
13
13
  if (dataType.type.includes('2')) {
14
14
  return vec2b;
@@ -33,7 +33,7 @@ export const allEq = dualImpl({
33
33
  codegenImpl: (_ctx, [lhs, rhs]) => stitch `all(${lhs} == ${rhs})`,
34
34
  sideEffects: false,
35
35
  });
36
- const cpuEq = (lhs, rhs) => VectorOps.eq[lhs.kind](lhs, rhs);
36
+ const cpuEq = (lhs, rhs) => generalizeBoolFn((a, b) => a === b, [lhs, rhs]);
37
37
  /**
38
38
  * Checks **component-wise** whether `lhs == rhs`.
39
39
  * This function does **not** return `bool`, for that use-case, wrap the result in `all`, or use `allEq`.
@@ -71,7 +71,7 @@ export const ne = dualImpl({
71
71
  codegenImpl: (_ctx, [lhs, rhs]) => stitch `(${lhs} != ${rhs})`,
72
72
  sideEffects: false,
73
73
  });
74
- const cpuLt = (lhs, rhs) => VectorOps.lt[lhs.kind](lhs, rhs);
74
+ const cpuLt = (lhs, rhs) => generalizeBoolFn((a, b) => a < b, [lhs, rhs]);
75
75
  /**
76
76
  * Checks **component-wise** whether `lhs < rhs`.
77
77
  * This function does **not** return `bool`, for that use-case, wrap the result in `all`.
@@ -183,7 +183,7 @@ export const not = dualImpl({
183
183
  codegenImpl: (_ctx, [arg]) => stitch `!(${arg})`,
184
184
  sideEffects: false,
185
185
  });
186
- const cpuOr = (lhs, rhs) => VectorOps.or[lhs.kind](lhs, rhs);
186
+ const cpuOr = (lhs, rhs) => generalizeBoolFn((a, b) => a || b, [lhs, rhs]);
187
187
  /**
188
188
  * Returns **component-wise** logical `or` result.
189
189
  * @example
@@ -257,13 +257,8 @@ export const isCloseTo = dualImpl({
257
257
  }),
258
258
  // CPU implementation
259
259
  normalImpl: (lhs, rhs, precision = 0.01) => {
260
- if (typeof lhs === 'number' && typeof rhs === 'number') {
261
- return Math.abs(lhs - rhs) < precision;
262
- }
263
- if (isVecInstance(lhs) && isVecInstance(rhs)) {
264
- return VectorOps.isCloseToZero[lhs.kind](sub(lhs, rhs), precision);
265
- }
266
- return false;
260
+ const componentResult = generalizeBoolFn((lhs, rhs) => Math.abs(lhs - rhs) < precision, [lhs, rhs]);
261
+ return typeof componentResult === 'boolean' ? componentResult : all(componentResult);
267
262
  },
268
263
  // GPU implementation
269
264
  codegenImpl: (_ctx, [lhs, rhs, precision = snip(0.01, f32, /* origin */ 'constant', false)]) => {
@@ -283,7 +278,8 @@ function cpuSelect(f, t, cond) {
283
278
  if (typeof cond === 'boolean') {
284
279
  return cpuCopy(cond ? t : f);
285
280
  }
286
- return VectorOps.select[f.kind](f, t, cond);
281
+ // generalizeFn will handle this fine, it just has no mixed type overload.
282
+ return generalizeFn((f, t, c) => (c ? t : f), [f, t, cond]);
287
283
  }
288
284
  export const validSelectBranchTypes = [
289
285
  f32,
package/std/index.d.ts CHANGED
@@ -3,7 +3,7 @@
3
3
  */
4
4
  export { copy } from './copy.ts';
5
5
  export { discard } from './discard.ts';
6
- export { abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceil, clamp, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, distance, dot, dot4I8Packed, dot4U8Packed, exp, exp2, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, insertBits, inverseSqrt, ldexp, length, log, log2, max, min, mix, modf, normalize, pow, quantizeToF16, radians, reflect, refract, reverseBits, round, saturate, sign, sin, sinh, smoothstep, sqrt, step, tan, tanh, transpose, trunc, } from './numeric.ts';
6
+ export { abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceil, clamp, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, distance, dot, dot4I8Packed, dot4U8Packed, exp, exp2, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, insertBits, inverseSqrt, ldexp, length, log, log2, max, min, mix, modf, normalize, pow, quantizeToF16, radians, reflect, refract, reverseBits, round, saturate, sign, sin, sinh, smoothstep, sqrt, step, tan, tanh, transpose, trunc, intdiv, } from './numeric.ts';
7
7
  export { add, bitShiftLeft, bitShiftRight, div, mod, mul, neg, sub } from './operators.ts';
8
8
  export { rotateX4, rotateY4, rotateZ4, scale4, translate4 } from './matrix.ts';
9
9
  export { identity2, identity3, identity4, rotationX4, rotationY4, rotationZ4, scaling4, translation4, } from '../data/matrix.ts';
package/std/index.js CHANGED
@@ -4,7 +4,7 @@
4
4
  // NOTE: This is a barrel file, internal files should not import things from this file
5
5
  export { copy } from "./copy.js";
6
6
  export { discard } from "./discard.js";
7
- export { abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceil, clamp, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, distance, dot, dot4I8Packed, dot4U8Packed, exp, exp2, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, insertBits, inverseSqrt, ldexp, length, log, log2, max, min, mix, modf, normalize, pow, quantizeToF16, radians, reflect, refract, reverseBits, round, saturate, sign, sin, sinh, smoothstep, sqrt, step, tan, tanh, transpose, trunc, } from "./numeric.js";
7
+ export { abs, acos, acosh, asin, asinh, atan, atan2, atanh, ceil, clamp, cos, cosh, countLeadingZeros, countOneBits, countTrailingZeros, cross, degrees, determinant, distance, dot, dot4I8Packed, dot4U8Packed, exp, exp2, extractBits, faceForward, firstLeadingBit, firstTrailingBit, floor, fma, fract, frexp, insertBits, inverseSqrt, ldexp, length, log, log2, max, min, mix, modf, normalize, pow, quantizeToF16, radians, reflect, refract, reverseBits, round, saturate, sign, sin, sinh, smoothstep, sqrt, step, tan, tanh, transpose, trunc, intdiv, } from "./numeric.js";
8
8
  export { add, bitShiftLeft, bitShiftRight, div, mod, mul, neg, sub } from "./operators.js";
9
9
  export { rotateX4, rotateY4, rotateZ4, scale4, translate4 } from "./matrix.js";
10
10
  export { identity2, identity3, identity4, rotationX4, rotationY4, rotationZ4, scaling4, translation4, } from "../data/matrix.js";
package/std/numeric.d.ts CHANGED
@@ -248,4 +248,11 @@ export declare const transpose: import("../types.ts").DualFn<typeof cpuTranspose
248
248
  declare function cpuTrunc(value: number): number;
249
249
  declare function cpuTrunc<T extends AnyFloatVecInstance>(value: T): T;
250
250
  export declare const trunc: import("../types.ts").DualFn<typeof cpuTrunc>;
251
+ declare function cpuIntdiv(lhs: number, rhs: number): number;
252
+ /**
253
+ * Performs integer division on the passed in scalars.
254
+ * Equivalent to `trunc(trunc(lhs) / trunc(rhs))`. Coerces both
255
+ * arguments to integers if they're floating point.
256
+ */
257
+ export declare const intdiv: import("../types.ts").DualFn<typeof cpuIntdiv>;
251
258
  export {};
package/std/numeric.js CHANGED
@@ -1,12 +1,13 @@
1
1
  import { dualImpl, MissingCpuImplError } from "../core/function/dualImpl.js";
2
2
  import { stitch } from "../core/resolve/stitch.js";
3
3
  import { mat2x2f, mat3x3f, mat4x4f } from "../data/matrix.js";
4
- import { smoothstepScalar } from "../data/numberOps.js";
4
+ import { clampScalar, smoothstepScalar } from "../data/numberOps.js";
5
5
  import { abstractFloat, abstractInt, f16, f32, i32, u32 } from "../data/numeric.js";
6
6
  import { abstruct } from "../data/struct.js";
7
7
  import { vec2f, vec2h, vec2i, vec2u, vec3f, vec3h, vec3i, vec3u, vec4f, vec4h, vec4i, vec4u, } from "../data/vector.js";
8
8
  import { VectorOps } from "../data/vectorOps.js";
9
- import { isHalfPrecisionSchema, isVecInstance, WORKAROUND_getSchema, } from "../data/wgslTypes.js";
9
+ import { generalizeFn, upCast } from "../data/generalizeFn.js";
10
+ import { isHalfPrecisionSchema, WORKAROUND_getSchema, } from "../data/wgslTypes.js";
10
11
  import { SignatureNotSupportedError } from "../errors.js";
11
12
  import { assertExhaustive } from "../shared/utilityTypes.js";
12
13
  import { unify } from "../tgsl/conversion.js";
@@ -60,10 +61,7 @@ const anyConcreteIntegerPrimitive = [i32, u32];
60
61
  const anyConcreteIntegerVec = [vec2i, vec3i, vec4i, vec2u, vec3u, vec4u];
61
62
  const anyConcreteInteger = [...anyConcreteIntegerPrimitive, ...anyConcreteIntegerVec];
62
63
  function cpuAbs(value) {
63
- if (typeof value === 'number') {
64
- return Math.abs(value);
65
- }
66
- return VectorOps.abs[value.kind](value);
64
+ return generalizeFn(Math.abs, [value]);
67
65
  }
68
66
  export const abs = dualImpl({
69
67
  name: 'abs',
@@ -73,10 +71,7 @@ export const abs = dualImpl({
73
71
  sideEffects: false,
74
72
  });
75
73
  function cpuAcos(value) {
76
- if (typeof value === 'number') {
77
- return Math.acos(value);
78
- }
79
- return VectorOps.acos[value.kind](value);
74
+ return generalizeFn(Math.acos, [value]);
80
75
  }
81
76
  export const acos = dualImpl({
82
77
  name: 'acos',
@@ -86,10 +81,7 @@ export const acos = dualImpl({
86
81
  sideEffects: false,
87
82
  });
88
83
  function cpuAcosh(value) {
89
- if (typeof value === 'number') {
90
- return Math.acosh(value);
91
- }
92
- return VectorOps.acosh[value.kind](value);
84
+ return generalizeFn(Math.acosh, [value]);
93
85
  }
94
86
  export const acosh = dualImpl({
95
87
  name: 'acosh',
@@ -99,10 +91,7 @@ export const acosh = dualImpl({
99
91
  sideEffects: false,
100
92
  });
101
93
  function cpuAsin(value) {
102
- if (typeof value === 'number') {
103
- return Math.asin(value);
104
- }
105
- return VectorOps.asin[value.kind](value);
94
+ return generalizeFn(Math.asin, [value]);
106
95
  }
107
96
  export const asin = dualImpl({
108
97
  name: 'asin',
@@ -112,10 +101,7 @@ export const asin = dualImpl({
112
101
  sideEffects: false,
113
102
  });
114
103
  function cpuAsinh(value) {
115
- if (typeof value === 'number') {
116
- return Math.asinh(value);
117
- }
118
- return VectorOps.asinh[value.kind](value);
104
+ return generalizeFn(Math.asinh, [value]);
119
105
  }
120
106
  export const asinh = dualImpl({
121
107
  name: 'asinh',
@@ -125,10 +111,7 @@ export const asinh = dualImpl({
125
111
  sideEffects: false,
126
112
  });
127
113
  function cpuAtan(value) {
128
- if (typeof value === 'number') {
129
- return Math.atan(value);
130
- }
131
- return VectorOps.atan[value.kind](value);
114
+ return generalizeFn(Math.atan, [value]);
132
115
  }
133
116
  export const atan = dualImpl({
134
117
  name: 'atan',
@@ -138,10 +121,7 @@ export const atan = dualImpl({
138
121
  sideEffects: false,
139
122
  });
140
123
  function cpuAtanh(value) {
141
- if (typeof value === 'number') {
142
- return Math.atanh(value);
143
- }
144
- return VectorOps.atanh[value.kind](value);
124
+ return generalizeFn(Math.atanh, [value]);
145
125
  }
146
126
  export const atanh = dualImpl({
147
127
  name: 'atanh',
@@ -151,10 +131,7 @@ export const atanh = dualImpl({
151
131
  sideEffects: false,
152
132
  });
153
133
  function cpuAtan2(y, x) {
154
- if (typeof y === 'number' && typeof x === 'number') {
155
- return Math.atan2(y, x);
156
- }
157
- return VectorOps.atan2[y.kind](y, x);
134
+ return generalizeFn(Math.atan2, [y, x]);
158
135
  }
159
136
  export const atan2 = dualImpl({
160
137
  name: 'atan2',
@@ -164,10 +141,7 @@ export const atan2 = dualImpl({
164
141
  sideEffects: false,
165
142
  });
166
143
  function cpuCeil(value) {
167
- if (typeof value === 'number') {
168
- return Math.ceil(value);
169
- }
170
- return VectorOps.ceil[value.kind](value);
144
+ return generalizeFn(Math.ceil, [value]);
171
145
  }
172
146
  export const ceil = dualImpl({
173
147
  name: 'ceil',
@@ -177,10 +151,7 @@ export const ceil = dualImpl({
177
151
  sideEffects: false,
178
152
  });
179
153
  function cpuClamp(value, low, high) {
180
- if (typeof value === 'number') {
181
- return Math.min(Math.max(low, value), high);
182
- }
183
- return VectorOps.clamp[value.kind](value, low, high);
154
+ return generalizeFn(clampScalar, [value, low, high]);
184
155
  }
185
156
  export const clamp = dualImpl({
186
157
  name: 'clamp',
@@ -190,10 +161,7 @@ export const clamp = dualImpl({
190
161
  sideEffects: false,
191
162
  });
192
163
  function cpuCos(value) {
193
- if (typeof value === 'number') {
194
- return Math.cos(value);
195
- }
196
- return VectorOps.cos[value.kind](value);
164
+ return generalizeFn(Math.cos, [value]);
197
165
  }
198
166
  export const cos = dualImpl({
199
167
  name: 'cos',
@@ -203,10 +171,7 @@ export const cos = dualImpl({
203
171
  sideEffects: false,
204
172
  });
205
173
  function cpuCosh(value) {
206
- if (typeof value === 'number') {
207
- return Math.cosh(value);
208
- }
209
- return VectorOps.cosh[value.kind](value);
174
+ return generalizeFn(Math.cosh, [value]);
210
175
  }
211
176
  export const cosh = dualImpl({
212
177
  name: 'cosh',
@@ -324,10 +289,7 @@ export const dot4I8Packed = dualImpl({
324
289
  sideEffects: false,
325
290
  });
326
291
  function cpuExp(value) {
327
- if (typeof value === 'number') {
328
- return Math.exp(value);
329
- }
330
- return VectorOps.exp[value.kind](value);
292
+ return generalizeFn(Math.exp, [value]);
331
293
  }
332
294
  export const exp = dualImpl({
333
295
  name: 'exp',
@@ -337,10 +299,7 @@ export const exp = dualImpl({
337
299
  sideEffects: false,
338
300
  });
339
301
  function cpuExp2(value) {
340
- if (typeof value === 'number') {
341
- return (2 ** value);
342
- }
343
- return VectorOps.exp2[value.kind](value);
302
+ return generalizeFn((val) => 2 ** val, [value]);
344
303
  }
345
304
  export const exp2 = dualImpl({
346
305
  name: 'exp2',
@@ -396,10 +355,7 @@ export const firstTrailingBit = dualImpl({
396
355
  sideEffects: false,
397
356
  });
398
357
  function cpuFloor(value) {
399
- if (typeof value === 'number') {
400
- return Math.floor(value);
401
- }
402
- return VectorOps.floor[value.kind](value);
358
+ return generalizeFn(Math.floor, [value]);
403
359
  }
404
360
  export const floor = dualImpl({
405
361
  name: 'floor',
@@ -422,10 +378,7 @@ export const fma = dualImpl({
422
378
  sideEffects: false,
423
379
  });
424
380
  function cpuFract(value) {
425
- if (typeof value === 'number') {
426
- return (value - Math.floor(value));
427
- }
428
- return VectorOps.fract[value.kind](value);
381
+ return generalizeFn((value) => value - Math.floor(value), [value]);
429
382
  }
430
383
  export const fract = dualImpl({
431
384
  name: 'fract',
@@ -542,10 +495,7 @@ export const length = dualImpl({
542
495
  sideEffects: false,
543
496
  });
544
497
  function cpuLog(value) {
545
- if (typeof value === 'number') {
546
- return Math.log(value);
547
- }
548
- return VectorOps.log[value.kind](value);
498
+ return generalizeFn(Math.log, [value]);
549
499
  }
550
500
  export const log = dualImpl({
551
501
  name: 'log',
@@ -555,10 +505,7 @@ export const log = dualImpl({
555
505
  sideEffects: false,
556
506
  });
557
507
  function cpuLog2(value) {
558
- if (typeof value === 'number') {
559
- return Math.log2(value);
560
- }
561
- return VectorOps.log2[value.kind](value);
508
+ return generalizeFn(Math.log2, [value]);
562
509
  }
563
510
  export const log2 = dualImpl({
564
511
  name: 'log2',
@@ -568,10 +515,7 @@ export const log2 = dualImpl({
568
515
  sideEffects: false,
569
516
  });
570
517
  function cpuMax(a, b) {
571
- if (typeof a === 'number') {
572
- return Math.max(a, b);
573
- }
574
- return VectorOps.max[a.kind](a, b);
518
+ return generalizeFn(Math.max, [a, b]);
575
519
  }
576
520
  export const max = dualImpl({
577
521
  name: 'max',
@@ -581,10 +525,7 @@ export const max = dualImpl({
581
525
  sideEffects: false,
582
526
  });
583
527
  function cpuMin(a, b) {
584
- if (typeof a === 'number') {
585
- return Math.min(a, b);
586
- }
587
- return VectorOps.min[a.kind](a, b);
528
+ return generalizeFn(Math.min, [a, b]);
588
529
  }
589
530
  export const min = dualImpl({
590
531
  name: 'min',
@@ -594,16 +535,7 @@ export const min = dualImpl({
594
535
  sideEffects: false,
595
536
  });
596
537
  function cpuMix(e1, e2, e3) {
597
- if (typeof e1 === 'number') {
598
- if (typeof e3 !== 'number' || typeof e2 !== 'number') {
599
- throw new Error('When e1 and e2 are numbers, the blend factor must be a number.');
600
- }
601
- return (e1 * (1 - e3) + e2 * e3);
602
- }
603
- if (typeof e1 === 'number' || typeof e2 === 'number') {
604
- throw new Error('e1 and e2 need to both be vectors of the same kind.');
605
- }
606
- return VectorOps.mix[e1.kind](e1, e2, e3);
538
+ return generalizeFn((e1, e2, e3) => e1 * (1 - e3) + e2 * e3, [e1, ...upCast([e2, e3])]);
607
539
  }
608
540
  export const mix = dualImpl({
609
541
  name: 'mix',
@@ -655,18 +587,15 @@ export const modf = dualImpl({
655
587
  export const normalize = dualImpl({
656
588
  name: 'normalize',
657
589
  signature: unifyRestrictedSignature(anyFloatVec),
658
- normalImpl: (v) => VectorOps.normalize[v.kind](v),
590
+ normalImpl: (v) => {
591
+ const len = length(v);
592
+ return generalizeFn((e) => e / len, [v]);
593
+ },
659
594
  codegenImpl: (_ctx, [value]) => stitch `normalize(${value})`,
660
595
  sideEffects: false,
661
596
  });
662
597
  function powCpu(base, exponent) {
663
- if (typeof base === 'number' && typeof exponent === 'number') {
664
- return (base ** exponent);
665
- }
666
- if (isVecInstance(base) && isVecInstance(exponent)) {
667
- return VectorOps.pow[base.kind](base, exponent);
668
- }
669
- throw new Error(`Invalid arguments to pow(): '${base}' '${exponent}'`);
598
+ return generalizeFn((a, b) => a ** b, [base, exponent]);
670
599
  }
671
600
  export const pow = dualImpl({
672
601
  name: 'pow',
@@ -775,10 +704,7 @@ export const saturate = dualImpl({
775
704
  sideEffects: false,
776
705
  });
777
706
  function cpuSign(e) {
778
- if (typeof e === 'number') {
779
- return Math.sign(e);
780
- }
781
- return VectorOps.sign[e.kind](e);
707
+ return generalizeFn(Math.sign, [e]);
782
708
  }
783
709
  export const sign = dualImpl({
784
710
  name: 'sign',
@@ -795,10 +721,7 @@ export const sign = dualImpl({
795
721
  sideEffects: false,
796
722
  });
797
723
  function cpuSin(value) {
798
- if (typeof value === 'number') {
799
- return Math.sin(value);
800
- }
801
- return VectorOps.sin[value.kind](value);
724
+ return generalizeFn(Math.sin, [value]);
802
725
  }
803
726
  export const sin = dualImpl({
804
727
  name: 'sin',
@@ -808,10 +731,7 @@ export const sin = dualImpl({
808
731
  sideEffects: false,
809
732
  });
810
733
  function cpuSinh(value) {
811
- if (typeof value === 'number') {
812
- return Math.sinh(value);
813
- }
814
- throw new MissingCpuImplError('CPU implementation for sinh on vectors not implemented yet. Please submit an issue at https://github.com/software-mansion/TypeGPU/issues');
734
+ return generalizeFn(Math.sinh, [value]);
815
735
  }
816
736
  export const sinh = dualImpl({
817
737
  name: 'sinh',
@@ -821,10 +741,7 @@ export const sinh = dualImpl({
821
741
  sideEffects: false,
822
742
  });
823
743
  function cpuSmoothstep(edge0, edge1, x) {
824
- if (typeof x === 'number') {
825
- return smoothstepScalar(edge0, edge1, x);
826
- }
827
- return VectorOps.smoothstep[x.kind](edge0, edge1, x);
744
+ return generalizeFn(smoothstepScalar, [edge0, edge1, x]);
828
745
  }
829
746
  export const smoothstep = dualImpl({
830
747
  name: 'smoothstep',
@@ -834,10 +751,7 @@ export const smoothstep = dualImpl({
834
751
  sideEffects: false,
835
752
  });
836
753
  function cpuSqrt(value) {
837
- if (typeof value === 'number') {
838
- return Math.sqrt(value);
839
- }
840
- return VectorOps.sqrt[value.kind](value);
754
+ return generalizeFn(Math.sqrt, [value]);
841
755
  }
842
756
  export const sqrt = dualImpl({
843
757
  name: 'sqrt',
@@ -873,10 +787,7 @@ export const tan = dualImpl({
873
787
  sideEffects: false,
874
788
  });
875
789
  function cpuTanh(value) {
876
- if (typeof value === 'number') {
877
- return Math.tanh(value);
878
- }
879
- return VectorOps.tanh[value.kind](value);
790
+ return generalizeFn(Math.tanh, [value]);
880
791
  }
881
792
  export const tanh = dualImpl({
882
793
  name: 'tanh',
@@ -954,3 +865,27 @@ export const trunc = dualImpl({
954
865
  codegenImpl: (_ctx, [value]) => stitch `trunc(${value})`,
955
866
  sideEffects: false,
956
867
  });
868
+ function cpuIntdiv(lhs, rhs) {
869
+ if (typeof lhs !== 'number' || typeof rhs !== 'number') {
870
+ throw new Error('std.intdiv called with invalid arguments.');
871
+ }
872
+ return Math.trunc(Math.trunc(lhs) / Math.trunc(rhs));
873
+ }
874
+ /**
875
+ * Performs integer division on the passed in scalars.
876
+ * Equivalent to `trunc(trunc(lhs) / trunc(rhs))`. Coerces both
877
+ * arguments to integers if they're floating point.
878
+ */
879
+ export const intdiv = dualImpl({
880
+ name: 'intdiv',
881
+ signature: (lhs, rhs) => {
882
+ const unified = unify([lhs, rhs], [u32, i32]);
883
+ if (!unified) {
884
+ throw new SignatureNotSupportedError([lhs, rhs], [u32, i32, abstractInt]);
885
+ }
886
+ return { argTypes: unified, returnType: unified[0] };
887
+ },
888
+ normalImpl: cpuIntdiv,
889
+ codegenImpl: (ctx, [lhs, rhs]) => ctx.gen.emitBinaryOp(lhs, '/', rhs),
890
+ sideEffects: false,
891
+ });