@cosmos-js/wgpu-struct 0.1.0 → 0.1.1
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/dist/index.d.ts +112 -0
- package/dist/index.js +185 -0
- package/package.json +1 -1
- package/src/index.ts +2 -3
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
export declare enum LENGTH {
|
|
2
|
+
BIT8 = 1,
|
|
3
|
+
BIT16 = 2,
|
|
4
|
+
BIT32 = 4
|
|
5
|
+
}
|
|
6
|
+
export declare const WGPU_DATA_TYPE: {
|
|
7
|
+
/**Represents a U8 (1 byte) */
|
|
8
|
+
readonly U8: {
|
|
9
|
+
readonly type: "uint";
|
|
10
|
+
readonly length: LENGTH.BIT8;
|
|
11
|
+
};
|
|
12
|
+
/**Represents a U16 (2 byte) */
|
|
13
|
+
readonly U16: {
|
|
14
|
+
readonly type: "uint";
|
|
15
|
+
readonly length: LENGTH.BIT16;
|
|
16
|
+
};
|
|
17
|
+
/**Represents a U32 (4 byte) */
|
|
18
|
+
readonly U32: {
|
|
19
|
+
readonly type: "uint";
|
|
20
|
+
readonly length: LENGTH.BIT32;
|
|
21
|
+
};
|
|
22
|
+
/**Represent a I8 (1 byte) */
|
|
23
|
+
readonly I8: {
|
|
24
|
+
readonly type: "int";
|
|
25
|
+
readonly length: LENGTH.BIT8;
|
|
26
|
+
};
|
|
27
|
+
/**Represent a I16 (2 byte) */
|
|
28
|
+
readonly I16: {
|
|
29
|
+
readonly type: "int";
|
|
30
|
+
readonly length: LENGTH.BIT16;
|
|
31
|
+
};
|
|
32
|
+
/**Represent a I32 (4 byte) */
|
|
33
|
+
readonly I32: {
|
|
34
|
+
readonly type: "int";
|
|
35
|
+
readonly length: LENGTH.BIT32;
|
|
36
|
+
};
|
|
37
|
+
/**Represent a F16 (2 byte) */
|
|
38
|
+
readonly F16: {
|
|
39
|
+
readonly type: "float";
|
|
40
|
+
readonly length: LENGTH.BIT16;
|
|
41
|
+
};
|
|
42
|
+
/**Repesent a F32 (4 byte) */
|
|
43
|
+
readonly F32: {
|
|
44
|
+
readonly type: "float";
|
|
45
|
+
readonly length: LENGTH.BIT32;
|
|
46
|
+
};
|
|
47
|
+
};
|
|
48
|
+
export type WGPU_DATA_TYPE = typeof WGPU_DATA_TYPE[keyof typeof WGPU_DATA_TYPE];
|
|
49
|
+
export interface TYPE_METADATA {
|
|
50
|
+
/**
|
|
51
|
+
* Represents the length of the type.
|
|
52
|
+
*
|
|
53
|
+
* e.g. **`length: 4`** meaning it's a **`array<yourType, 4>`**
|
|
54
|
+
*/
|
|
55
|
+
length: number;
|
|
56
|
+
/**
|
|
57
|
+
* Represents the webgpu type;
|
|
58
|
+
*
|
|
59
|
+
* e.g. **`WGPU_DATA_TYPE.U8`** represents a **Uint8 [0-256]**
|
|
60
|
+
*/
|
|
61
|
+
type: WGPU_DATA_TYPE;
|
|
62
|
+
}
|
|
63
|
+
export type FIELD = ({
|
|
64
|
+
/**Name of the field */
|
|
65
|
+
name: string;
|
|
66
|
+
required: boolean;
|
|
67
|
+
}) & (({
|
|
68
|
+
/**
|
|
69
|
+
* The type of the field;
|
|
70
|
+
*
|
|
71
|
+
* If you want to represent a vec3i; use `{length: 3, type: WGPU_DATA_TYPE.I32}`
|
|
72
|
+
*/
|
|
73
|
+
type: TYPE_METADATA;
|
|
74
|
+
}) | ({
|
|
75
|
+
/**
|
|
76
|
+
* Inner struct
|
|
77
|
+
*/
|
|
78
|
+
innerStruct: WGPU_STRUCT;
|
|
79
|
+
length: number;
|
|
80
|
+
}));
|
|
81
|
+
export type WGPU_STRUCT = FIELD[];
|
|
82
|
+
export type DIGESTABLE_FIELD = {
|
|
83
|
+
name: string;
|
|
84
|
+
length: number;
|
|
85
|
+
required: boolean;
|
|
86
|
+
} & ({
|
|
87
|
+
struct: DIGESTABLE_STRUCT_LAYOUT;
|
|
88
|
+
} | {
|
|
89
|
+
type: WGPU_DATA_TYPE;
|
|
90
|
+
});
|
|
91
|
+
export interface DIGESTABLE_STRUCT_LAYOUT {
|
|
92
|
+
byteLength: number;
|
|
93
|
+
items: DIGESTABLE_FIELD[];
|
|
94
|
+
}
|
|
95
|
+
export interface DATA_TYPE {
|
|
96
|
+
[x: string]: number[] | DATA_TYPE[];
|
|
97
|
+
}
|
|
98
|
+
export declare namespace StructValidation {
|
|
99
|
+
function validateNames(struct: WGPU_STRUCT): void;
|
|
100
|
+
function validateBytelength(struct: WGPU_STRUCT): void;
|
|
101
|
+
function validateData(data: DATA_TYPE, layout: DIGESTABLE_STRUCT_LAYOUT): void;
|
|
102
|
+
}
|
|
103
|
+
export declare namespace StructConverter {
|
|
104
|
+
function convertToDigestableLayout(struct: WGPU_STRUCT): DIGESTABLE_STRUCT_LAYOUT;
|
|
105
|
+
}
|
|
106
|
+
export declare namespace Packer {
|
|
107
|
+
/** Packs data to {type: "f32"|"i32"|"u32", value: number}[] */
|
|
108
|
+
function packToBit32(data: DATA_TYPE, layout: DIGESTABLE_STRUCT_LAYOUT): {
|
|
109
|
+
type: "f32" | "i32" | "u32";
|
|
110
|
+
value: number;
|
|
111
|
+
}[];
|
|
112
|
+
}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
export var LENGTH;
|
|
2
|
+
(function (LENGTH) {
|
|
3
|
+
LENGTH[LENGTH["BIT8"] = 1] = "BIT8";
|
|
4
|
+
LENGTH[LENGTH["BIT16"] = 2] = "BIT16";
|
|
5
|
+
LENGTH[LENGTH["BIT32"] = 4] = "BIT32";
|
|
6
|
+
})(LENGTH || (LENGTH = {}));
|
|
7
|
+
export const WGPU_DATA_TYPE = {
|
|
8
|
+
/**Represents a U8 (1 byte) */
|
|
9
|
+
U8: { type: "uint", length: LENGTH.BIT8 },
|
|
10
|
+
/**Represents a U16 (2 byte) */
|
|
11
|
+
U16: { type: "uint", length: LENGTH.BIT16 },
|
|
12
|
+
/**Represents a U32 (4 byte) */
|
|
13
|
+
U32: { type: "uint", length: LENGTH.BIT32 },
|
|
14
|
+
/**Represent a I8 (1 byte) */
|
|
15
|
+
I8: { type: "int", length: LENGTH.BIT8 },
|
|
16
|
+
/**Represent a I16 (2 byte) */
|
|
17
|
+
I16: { type: "int", length: LENGTH.BIT16 },
|
|
18
|
+
/**Represent a I32 (4 byte) */
|
|
19
|
+
I32: { type: "int", length: LENGTH.BIT32 },
|
|
20
|
+
/**Represent a F16 (2 byte) */
|
|
21
|
+
F16: { type: "float", length: LENGTH.BIT16 },
|
|
22
|
+
/**Repesent a F32 (4 byte) */
|
|
23
|
+
F32: { type: "float", length: LENGTH.BIT32 }
|
|
24
|
+
};
|
|
25
|
+
export var StructValidation;
|
|
26
|
+
(function (StructValidation) {
|
|
27
|
+
function validateNames(struct) {
|
|
28
|
+
const set = {};
|
|
29
|
+
for (const field of struct) {
|
|
30
|
+
if (set[field.name])
|
|
31
|
+
throw new Error("Duplicate field name " + field.name);
|
|
32
|
+
else if (field?.innerStruct)
|
|
33
|
+
validateNames(field.innerStruct);
|
|
34
|
+
set[field.name] = true;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
StructValidation.validateNames = validateNames;
|
|
38
|
+
function getByteLength(struct) {
|
|
39
|
+
let bytes = 0;
|
|
40
|
+
for (const field of struct) {
|
|
41
|
+
const assingleTyped = field;
|
|
42
|
+
if (assingleTyped.type) {
|
|
43
|
+
bytes += assingleTyped.type.type.length * assingleTyped.type.length;
|
|
44
|
+
}
|
|
45
|
+
const asstructTyped = field;
|
|
46
|
+
if (asstructTyped.innerStruct) {
|
|
47
|
+
bytes += asstructTyped.length * getByteLength(asstructTyped.innerStruct);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return bytes;
|
|
51
|
+
}
|
|
52
|
+
function validateBytelength(struct) {
|
|
53
|
+
const byteLength = getByteLength(struct);
|
|
54
|
+
if (byteLength % 4 !== 0) {
|
|
55
|
+
throw new Error(`Length of the given struct is not divisible by 4.`);
|
|
56
|
+
}
|
|
57
|
+
if (byteLength % 16 !== 0) {
|
|
58
|
+
throw new Error(`Length of the given struct is not divisble by 16`);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
StructValidation.validateBytelength = validateBytelength;
|
|
62
|
+
function validateData(data, layout) {
|
|
63
|
+
for (const field of layout.items) {
|
|
64
|
+
const fieldData = data[field.name];
|
|
65
|
+
if (!fieldData && field.required)
|
|
66
|
+
throw new Error(`Error while validating data: "${field.name}" not given`);
|
|
67
|
+
if (fieldData.length !== field.length)
|
|
68
|
+
throw new Error(`[Field "${field.name}"]: Given data is of ${fieldData.length} where as ${field.length} is required.`);
|
|
69
|
+
const asTyped = field;
|
|
70
|
+
if (asTyped.type) {
|
|
71
|
+
if (fieldData.every(a => typeof a !== "number")) {
|
|
72
|
+
throw new Error(`[Field "${field.name}"]: Array given is not of number[] type`);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
else {
|
|
76
|
+
for (const data of fieldData) {
|
|
77
|
+
validateData(data, field.struct);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
StructValidation.validateData = validateData;
|
|
83
|
+
})(StructValidation || (StructValidation = {}));
|
|
84
|
+
export var StructConverter;
|
|
85
|
+
(function (StructConverter) {
|
|
86
|
+
function convertToDigestableLayout(struct) {
|
|
87
|
+
const layout = { byteLength: 0, items: [] };
|
|
88
|
+
for (const field of struct) {
|
|
89
|
+
const fieldTyped = field;
|
|
90
|
+
const fieldStruct = field;
|
|
91
|
+
if (fieldTyped.type) {
|
|
92
|
+
const byteLength = fieldTyped.type.type.length * fieldTyped.type.length;
|
|
93
|
+
layout.byteLength += byteLength;
|
|
94
|
+
layout.items.push({ "length": fieldTyped.type.length, "name": fieldTyped.name, "type": fieldTyped.type.type, required: fieldTyped.required });
|
|
95
|
+
}
|
|
96
|
+
else if (fieldStruct.innerStruct) {
|
|
97
|
+
const digested = convertToDigestableLayout(fieldStruct.innerStruct);
|
|
98
|
+
const byteLength = fieldStruct.length * digested.byteLength;
|
|
99
|
+
layout.byteLength += byteLength;
|
|
100
|
+
layout.items.push({ length: fieldStruct.length, name: fieldStruct.name, struct: digested, required: fieldStruct.required });
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
return layout;
|
|
104
|
+
}
|
|
105
|
+
StructConverter.convertToDigestableLayout = convertToDigestableLayout;
|
|
106
|
+
})(StructConverter || (StructConverter = {}));
|
|
107
|
+
export var Packer;
|
|
108
|
+
(function (Packer) {
|
|
109
|
+
/** Packs data to {type: "f32"|"i32"|"u32", value: number}[] */
|
|
110
|
+
function packToBit32(data, layout) {
|
|
111
|
+
const buffer = new ArrayBuffer(layout.byteLength);
|
|
112
|
+
const view = new DataView(buffer);
|
|
113
|
+
const chunkTypes = new Array(layout.byteLength / 4).fill("u32");
|
|
114
|
+
let byteOffset = 0;
|
|
115
|
+
function writeField(fieldData, field) {
|
|
116
|
+
const isPrimitive = "type" in field;
|
|
117
|
+
if (isPrimitive) {
|
|
118
|
+
const primitiveType = field.type.type;
|
|
119
|
+
const bitLength = field.type.length;
|
|
120
|
+
const numericArray = fieldData;
|
|
121
|
+
for (let i = 0; i < field.length; i++) {
|
|
122
|
+
const value = numericArray[i] ?? 0;
|
|
123
|
+
const chunkIndex = Math.floor(byteOffset / 4);
|
|
124
|
+
if (primitiveType === "float")
|
|
125
|
+
chunkTypes[chunkIndex] = "f32";
|
|
126
|
+
else if (primitiveType === "int")
|
|
127
|
+
chunkTypes[chunkIndex] = "i32";
|
|
128
|
+
if (primitiveType === "uint") {
|
|
129
|
+
if (bitLength === 1)
|
|
130
|
+
view.setUint8(byteOffset, value);
|
|
131
|
+
else if (bitLength === 2)
|
|
132
|
+
view.setUint16(byteOffset, value, true);
|
|
133
|
+
else if (bitLength === 4)
|
|
134
|
+
view.setUint32(byteOffset, value, true);
|
|
135
|
+
}
|
|
136
|
+
else if (primitiveType === "int") {
|
|
137
|
+
if (bitLength === 1)
|
|
138
|
+
view.setInt8(byteOffset, value);
|
|
139
|
+
else if (bitLength === 2)
|
|
140
|
+
view.setInt16(byteOffset, value, true);
|
|
141
|
+
else if (bitLength === 4)
|
|
142
|
+
view.setInt32(byteOffset, value, true);
|
|
143
|
+
}
|
|
144
|
+
else if (primitiveType === "float") {
|
|
145
|
+
if (bitLength === 4)
|
|
146
|
+
view.setFloat32(byteOffset, value, true);
|
|
147
|
+
}
|
|
148
|
+
byteOffset += bitLength;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
else {
|
|
152
|
+
const structArray = fieldData;
|
|
153
|
+
const innerLayout = field.struct;
|
|
154
|
+
for (let i = 0; i < field.length; i++) {
|
|
155
|
+
const innerData = structArray[i] ?? {};
|
|
156
|
+
for (const innerField of innerLayout.items) {
|
|
157
|
+
writeField(innerData[innerField.name], innerField);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
for (const item of layout.items) {
|
|
163
|
+
writeField(data[item.name], item);
|
|
164
|
+
}
|
|
165
|
+
const result = [];
|
|
166
|
+
const total32BitChunks = layout.byteLength / 4;
|
|
167
|
+
for (let i = 0; i < total32BitChunks; i++) {
|
|
168
|
+
const currentByteOffset = i * 4;
|
|
169
|
+
const targetType = chunkTypes[i];
|
|
170
|
+
let value;
|
|
171
|
+
if (targetType === "f32") {
|
|
172
|
+
value = view.getFloat32(currentByteOffset, true);
|
|
173
|
+
}
|
|
174
|
+
else if (targetType === "i32") {
|
|
175
|
+
value = view.getInt32(currentByteOffset, true);
|
|
176
|
+
}
|
|
177
|
+
else {
|
|
178
|
+
value = view.getUint32(currentByteOffset, true);
|
|
179
|
+
}
|
|
180
|
+
result.push({ type: targetType, value });
|
|
181
|
+
}
|
|
182
|
+
return result;
|
|
183
|
+
}
|
|
184
|
+
Packer.packToBit32 = packToBit32;
|
|
185
|
+
})(Packer || (Packer = {}));
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -74,13 +74,12 @@ export interface DATA_TYPE {
|
|
|
74
74
|
}
|
|
75
75
|
export namespace StructValidation {
|
|
76
76
|
export function validateNames(struct: WGPU_STRUCT) {
|
|
77
|
-
|
|
77
|
+
const set: Record<string, true> = {};
|
|
78
78
|
for (const field of struct) {
|
|
79
79
|
if (set[field.name]) throw new Error("Duplicate field name " + field.name)
|
|
80
80
|
else if ((field as { name: string } & { innerStruct: WGPU_STRUCT })?.innerStruct) validateNames((field as { name: string } & { innerStruct: WGPU_STRUCT }).innerStruct)
|
|
81
81
|
set[field.name] = true;
|
|
82
82
|
}
|
|
83
|
-
set = {}
|
|
84
83
|
}
|
|
85
84
|
function getByteLength(struct: WGPU_STRUCT) {
|
|
86
85
|
let bytes = 0;
|
|
@@ -205,7 +204,7 @@ export namespace Packer {
|
|
|
205
204
|
for (let i = 0; i < total32BitChunks; i++) {
|
|
206
205
|
const currentByteOffset = i * 4;
|
|
207
206
|
const targetType = chunkTypes[i];
|
|
208
|
-
let value
|
|
207
|
+
let value;
|
|
209
208
|
|
|
210
209
|
if (targetType === "f32") {
|
|
211
210
|
value = view.getFloat32(currentByteOffset, true);
|