Closed greggman closed 4 months ago
I think it would be better to come up with solution to what I consider to be the root problem: The "global" defaultType makes it impossible to have correct types for the created vectors, matrices etc. If the api was something like:
const { mat4 } = wgpuMatrix(Array);
const matrix = mat4.identity();
you could actually have correct type for matrix
and remove the need for manual type assertions. The default export could be wgpuMatrix(Float32Array)
for convenience.
Another option which might be possible. I'll post this since I spent some time figuring it out, but I think the first solution is way better.
Change default TS return type to be Float32Array
but keep setDefaultType
and come up with some nice solution where you add d.ts
file into your project to override the default type when necessary. This is the best I was able to come up with:
wgpu-matrix.d.ts (this file goes to any project using wgpu-matrix
)
declare module 'wgpu-matrix' {
import { Vec2 } from 'wgpu-matrix/dist/2.x/vec2';
import * as origvec2 from 'wgpu-matrix/dist/2.x/vec2-impl';
type vec2Type = typeof origvec2;
type vec2 = {
[K in keyof vec2Type]: vec2Type[K] extends (...args: infer Args) => Vec2
? (...args: Args) => [number, number]
: vec2Type[K];
};
export const vec2: vec2;
}
now you'd get the correct type for all vec2 operations (assuming you remember to call setDefaultType
).
import { vec2 } from 'wgpu-matrix';
// [number, number]
const matrix = vec2.create();
It feels a bit dirty for sure and I'm sure it's possible to come up with something more elegant when modifying the actual type definitions of this module is an option. It requires more work and still requires you to make sure you make the type match whatever you call setDefaultType
with. Also nothing prevent you from calling setDefaultType
later making the types incorrect. That's why I think the first solution would be way better.
For completeness, there's also the option of using generics, and making the output type always the same as the input type.
const vec3 = {
cross<T extends Vec3 = Float32Array>(a: T, b: T): T;
...
};
I personally prefer the
const { mat4 } = wgpuMatrix(Array);
const matrix = mat4.identity();
option, because it means that I, and a random npm library, can both use wgpu-matrix and won't ever run into weird conflicts because I'm using number[] while the npm library globally assumes Float32Arrays.
To make that option ergonomic to use, I'd create a math.ts
file in my project, where I import all the relevant wgpu-matrix types, and re-export them. That way, whenever I type mat4
in any Typescript file, my IDE will suggest an import with types that make sense for my project.
Yet another option would be having an API for each type, like vec3
(defaults to Float32Array), vec3d
for Float64Array and vec3n
for number[]
;
I personally think that setDefaultType
is rarely what one wants, since it globally affects code, including potentially affecting other libraries that happen to use wgpu-matrix.
I saw some code like this
const matrix = mat4.identity(); device.writeBuffer(uniformBuffer, 0, matrix);
I'm currently trying to do very similar in TS, and encountering this problem. Right now I'm casting to Float32Array
; is this an okay workaround for the time being?
I saw some code like this
const matrix = mat4.identity(); device.writeBuffer(uniformBuffer, 0, matrix);
I'm currently trying to do very similar in TS, and encountering this problem. Right now I'm casting to
Float32Array
; is this an okay workaround for the time being?
Yes, you can do that. It's an okay workaround
My coding style doesn't run into this because because the odds of me having just one matrix are low. For me, I have 2 styles.
views into a array buffer
struct Uniforms {
world: mat4x4f,
viewProjection: mat4x4f;
}
const uniformValues = new Float32Array(32);
const world = uniformValues.subarray(0, 16);
const viewProjection = uniformValues.subarray(16, 32);
mat4.identity(world);
mat4.perspective(fov, aspect, 1, 10, viewProjection);
device.queue.writeData(uniformBuffer, 0, uniformValues);
use webgpu-utils
I'm not saying anyone is doing anything wrong. Only that I didn't run into this issue until recently
So I tried @FINDarkside's idea I think
It need some cleanup but there's a test here (only refactored mat4)
https://github.com/greggman/wgpu-matrix/tree/refactor-getAPI-type
Unfortunately TypeDoc fails to generate docs. (npm run docs
). It could be something I'm doing or it could be a bug in TypeDoc.
One problem I ran into is dst
ends up having to be the type. With other JS style you could do this
mat4.identity(someFloat32Array);
mat4.identity(someNativeArray);
But with this typed version only the type assigned to dst
is allowed.
Like I said above, that makes me think I should just do Float32Array only
That's here (again, only tried mat4)
https://github.com/greggman/wgpu-matrix/tree/refactor-just-float32array
v3.x is release which I hope solves this issue.
I saw some code like this
This fails in typescript because
Mat4
isFloat32Array | Float64Array | number[]
andnumber[]
is not compatible as a parameter todevice.writeBuffer
so you end up having to cast.I thought about changing it so all wgpu functions take a
XXXArg
but returnXXX
whereXXXArg
includes extra types butXXX
does not. As in:This way you can still pass raw arrays but you get back something that's compatible with WebGPU
But, it also means you can no longer use the functions as is, for non-
Float32Array
stuffNote: I've never used this feature.
Similarly you could no longer reconfigure the function via
setDefaultType
(though again I've never used these functions)Should I make this change?