@kiberon-labs/behave-graph-scene 1.0.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 (50) hide show
  1. package/package.json +34 -0
  2. package/src/Abstractions/Drivers/DummyScene.ts +79 -0
  3. package/src/Abstractions/IScene.ts +18 -0
  4. package/src/GLTFJson.ts +34 -0
  5. package/src/Nodes/Actions/EaseSceneProperty.ts +162 -0
  6. package/src/Nodes/Actions/SetSceneProperty.ts +35 -0
  7. package/src/Nodes/Events/OnSceneNodeClick.ts +66 -0
  8. package/src/Nodes/Logic/ColorNodes.ts +121 -0
  9. package/src/Nodes/Logic/EulerNodes.ts +115 -0
  10. package/src/Nodes/Logic/Mat3Nodes.ts +202 -0
  11. package/src/Nodes/Logic/Mat4Nodes.ts +257 -0
  12. package/src/Nodes/Logic/QuatNodes.ts +178 -0
  13. package/src/Nodes/Logic/Vec2Nodes.ts +111 -0
  14. package/src/Nodes/Logic/Vec3Nodes.ts +121 -0
  15. package/src/Nodes/Logic/Vec4Nodes.ts +112 -0
  16. package/src/Nodes/Logic/VecElements.ts +34 -0
  17. package/src/Nodes/Queries/GetSceneProperty.ts +35 -0
  18. package/src/Values/ColorValue.ts +22 -0
  19. package/src/Values/EulerValue.ts +22 -0
  20. package/src/Values/Internal/Mat2.ts +214 -0
  21. package/src/Values/Internal/Mat3.ts +422 -0
  22. package/src/Values/Internal/Mat4.ts +831 -0
  23. package/src/Values/Internal/Vec2.ts +97 -0
  24. package/src/Values/Internal/Vec3.ts +244 -0
  25. package/src/Values/Internal/Vec4.ts +350 -0
  26. package/src/Values/Mat3Value.ts +20 -0
  27. package/src/Values/Mat4Value.ts +20 -0
  28. package/src/Values/QuatValue.ts +22 -0
  29. package/src/Values/Vec2Value.ts +14 -0
  30. package/src/Values/Vec3Value.ts +22 -0
  31. package/src/Values/Vec4Value.ts +21 -0
  32. package/src/buildScene.ts +479 -0
  33. package/src/index.ts +38 -0
  34. package/src/loadScene.ts +81 -0
  35. package/src/registerSceneProfile.ts +105 -0
  36. package/tests/graphs/logic/Color.json +53 -0
  37. package/tests/graphs/logic/Euler.json +53 -0
  38. package/tests/graphs/logic/Quaternion.json +56 -0
  39. package/tests/graphs/logic/Vector2.json +50 -0
  40. package/tests/graphs/logic/Vector3.json +53 -0
  41. package/tests/graphs/logic/Vector4.json +56 -0
  42. package/tests/readSceneGraphs.test.ts +57 -0
  43. package/tests/registerSceneProfile.test.ts +62 -0
  44. package/tests/tsconfig.json +11 -0
  45. package/tests/values/internal/Vec2.test.ts +74 -0
  46. package/tests/values/internal/Vec3.test.ts +83 -0
  47. package/tests/values/internal/Vec4.test.ts +91 -0
  48. package/tsconfig.json +55 -0
  49. package/tsdown.config.ts +13 -0
  50. package/vitest.config.ts +15 -0
@@ -0,0 +1,111 @@
1
+ import { makeInNOutFunctionDesc } from '@kiberon-labs/behave-graph';
2
+
3
+ import {
4
+ Vec2,
5
+ vec2Add,
6
+ vec2Dot,
7
+ vec2Equals,
8
+ vec2Length,
9
+ vec2Mix,
10
+ vec2MultiplyByScalar,
11
+ vec2Negate,
12
+ vec2Normalize,
13
+ vec2Subtract,
14
+ vec2ToArray
15
+ } from '../../Values/Internal/Vec2.js';
16
+
17
+ export const Constant = makeInNOutFunctionDesc({
18
+ name: 'math/vec2',
19
+ label: 'Vec2',
20
+ in: ['vec2'],
21
+ out: 'vec2',
22
+ exec: (a: Vec2) => a
23
+ });
24
+
25
+ export const Create = makeInNOutFunctionDesc({
26
+ name: 'math/toVec2/float',
27
+ label: 'Float to Vec2',
28
+ in: [{ x: 'float' }, { y: 'float' }],
29
+ out: 'vec2',
30
+ exec: (x: number, y: number) => new Vec2(x, y)
31
+ });
32
+
33
+ export const Elements = makeInNOutFunctionDesc({
34
+ name: 'math/toFloat/vec2',
35
+ label: 'Vec2 To Float',
36
+ in: ['vec2'],
37
+ out: [{ x: 'float' }, { y: 'float' }],
38
+ exec: vec2ToArray
39
+ });
40
+
41
+ export const Add = makeInNOutFunctionDesc({
42
+ name: 'math/add/vec2',
43
+ label: '+',
44
+ in: ['vec2', 'vec2'],
45
+ out: 'vec2',
46
+ exec: vec2Add
47
+ });
48
+
49
+ export const Subtract = makeInNOutFunctionDesc({
50
+ name: 'math/subtract/vec2',
51
+ label: '-',
52
+ in: ['vec2', 'vec2'],
53
+ out: 'vec2',
54
+ exec: vec2Subtract
55
+ });
56
+
57
+ export const Negate = makeInNOutFunctionDesc({
58
+ name: 'math/negate/vec2',
59
+ label: '-',
60
+ in: ['vec2'],
61
+ out: 'vec2',
62
+ exec: vec2Negate
63
+ });
64
+
65
+ export const Scale = makeInNOutFunctionDesc({
66
+ name: 'math/scale/vec2',
67
+ label: '×',
68
+ in: ['vec2', 'float'],
69
+ out: 'vec2',
70
+ exec: vec2MultiplyByScalar
71
+ });
72
+
73
+ export const Length = makeInNOutFunctionDesc({
74
+ name: 'math/length/vec2',
75
+ label: 'Length',
76
+ in: ['vec2'],
77
+ out: 'float',
78
+ exec: vec2Length
79
+ });
80
+
81
+ export const Normalize = makeInNOutFunctionDesc({
82
+ name: 'math/normalize/vec2',
83
+ label: 'Normalize',
84
+ in: ['vec2'],
85
+ out: 'vec2',
86
+ exec: vec2Normalize
87
+ });
88
+
89
+ export const Dot = makeInNOutFunctionDesc({
90
+ name: 'math/dot/vec2',
91
+ label: 'Dot Product',
92
+ in: ['vec2', 'vec2'],
93
+ out: 'float',
94
+ exec: vec2Dot
95
+ });
96
+
97
+ export const Mix = makeInNOutFunctionDesc({
98
+ name: 'math/mix/vec2',
99
+ label: '÷',
100
+ in: [{ a: 'vec2' }, { b: 'vec2' }, { t: 'float' }],
101
+ out: 'vec2',
102
+ exec: vec2Mix
103
+ });
104
+
105
+ export const Equal = makeInNOutFunctionDesc({
106
+ name: 'math/equal/vec2',
107
+ label: '=',
108
+ in: [{ a: 'vec2' }, { b: 'vec2' }, { tolerance: 'float' }],
109
+ out: 'boolean',
110
+ exec: vec2Equals
111
+ });
@@ -0,0 +1,121 @@
1
+ import { makeInNOutFunctionDesc } from '@kiberon-labs/behave-graph';
2
+
3
+ import {
4
+ Vec3,
5
+ vec3Add,
6
+ vec3Cross,
7
+ vec3Dot,
8
+ vec3Equals,
9
+ vec3Length,
10
+ vec3Mix,
11
+ vec3MultiplyByScalar,
12
+ vec3Negate,
13
+ vec3Normalize,
14
+ vec3Subtract
15
+ } from '../../Values/Internal/Vec3.js';
16
+
17
+ export const Constant = makeInNOutFunctionDesc({
18
+ name: 'math/vec3',
19
+ label: 'Vec3',
20
+ in: ['vec3'],
21
+ out: 'vec3',
22
+ exec: (a: Vec3) => a
23
+ });
24
+
25
+ export const Create = makeInNOutFunctionDesc({
26
+ name: 'math/toVec3/float',
27
+ label: 'Float to Vec3',
28
+ in: [{ x: 'float' }, { y: 'float' }, { z: 'float' }],
29
+ out: 'vec3',
30
+ exec: (x: number, y: number, z: number) => new Vec3(x, y, z)
31
+ });
32
+
33
+ export const Elements = makeInNOutFunctionDesc({
34
+ name: 'math/toFloat/vec3',
35
+ label: 'Vec3 To Float',
36
+ in: ['vec3'],
37
+ out: [{ x: 'float' }, { y: 'float' }, { z: 'float' }],
38
+ exec: (a: Vec3) => {
39
+ return { x: a.x, y: a.y, z: a.z };
40
+ }
41
+ });
42
+
43
+ export const Add = makeInNOutFunctionDesc({
44
+ name: 'math/add/vec3',
45
+ label: '+',
46
+ in: ['vec3', 'vec3'],
47
+ out: 'vec3',
48
+ exec: vec3Add
49
+ });
50
+
51
+ export const Subtract = makeInNOutFunctionDesc({
52
+ name: 'math/subtract/vec3',
53
+ label: '-',
54
+ in: ['vec3', 'vec3'],
55
+ out: 'vec3',
56
+ exec: vec3Subtract
57
+ });
58
+
59
+ export const Negate = makeInNOutFunctionDesc({
60
+ name: 'math/negate/vec3',
61
+ label: '-',
62
+ in: ['vec3'],
63
+ out: 'vec3',
64
+ exec: vec3Negate
65
+ });
66
+
67
+ export const Scale = makeInNOutFunctionDesc({
68
+ name: 'math/scale/vec3',
69
+ label: '×',
70
+ in: ['vec3', 'float'],
71
+ out: 'vec3',
72
+ exec: vec3MultiplyByScalar
73
+ });
74
+
75
+ export const Length = makeInNOutFunctionDesc({
76
+ name: 'math/length/vec3',
77
+ label: 'Length',
78
+ in: ['vec3'],
79
+ out: 'float',
80
+ exec: vec3Length
81
+ });
82
+
83
+ export const Normalize = makeInNOutFunctionDesc({
84
+ name: 'math/normalize/vec3',
85
+ label: 'Normalize',
86
+ in: ['vec3'],
87
+ out: 'vec3',
88
+ exec: vec3Normalize
89
+ });
90
+
91
+ export const Cross = makeInNOutFunctionDesc({
92
+ name: 'math/cross/vec3',
93
+ label: 'Cross',
94
+ in: ['vec3', 'vec3'],
95
+ out: 'vec3',
96
+ exec: vec3Cross
97
+ });
98
+
99
+ export const Dot = makeInNOutFunctionDesc({
100
+ name: 'math/dot/vec3',
101
+ label: 'Dot',
102
+ in: ['vec3', 'vec3'],
103
+ out: 'float',
104
+ exec: vec3Dot
105
+ });
106
+
107
+ export const Mix = makeInNOutFunctionDesc({
108
+ name: 'math/mix/vec3',
109
+ label: '÷',
110
+ in: [{ a: 'vec3' }, { b: 'vec3' }, { t: 'float' }],
111
+ out: 'vec3',
112
+ exec: vec3Mix
113
+ });
114
+
115
+ export const Equal = makeInNOutFunctionDesc({
116
+ name: 'math/equal/vec3',
117
+ label: '=',
118
+ in: [{ a: 'vec3' }, { b: 'vec3' }, { tolerance: 'float' }],
119
+ out: 'boolean',
120
+ exec: vec3Equals
121
+ });
@@ -0,0 +1,112 @@
1
+ import { makeInNOutFunctionDesc } from '@kiberon-labs/behave-graph';
2
+
3
+ import {
4
+ Vec4,
5
+ vec4Add,
6
+ vec4Dot,
7
+ vec4Equals,
8
+ vec4Length,
9
+ vec4Mix,
10
+ vec4MultiplyByScalar,
11
+ vec4Negate,
12
+ vec4Normalize,
13
+ vec4Subtract
14
+ } from '../../Values/Internal/Vec4.js';
15
+
16
+ export const Constant = makeInNOutFunctionDesc({
17
+ name: 'math/vec4',
18
+ label: 'Vec4',
19
+ in: ['vec4'],
20
+ out: 'vec4',
21
+ exec: (a) => a
22
+ });
23
+
24
+ export const Create = makeInNOutFunctionDesc({
25
+ name: 'math/toVec4/float',
26
+ label: 'Float to Vec4',
27
+ in: [{ x: 'float' }, { y: 'float' }, { z: 'float' }, { w: 'float' }],
28
+ out: 'vec4',
29
+ exec: (x: number, y: number, z: number, w: number) => new Vec4(x, y, z, w)
30
+ });
31
+
32
+ export const Elements = makeInNOutFunctionDesc({
33
+ name: 'math/toFloat/vec4',
34
+ label: 'Vec4 to Float',
35
+ in: ['vec4'],
36
+ out: [{ x: 'float' }, { y: 'float' }, { z: 'float' }, { w: 'float' }],
37
+ exec: (a: Vec4) => {
38
+ return { x: a.x, y: a.y, z: a.z, w: a.z };
39
+ }
40
+ });
41
+
42
+ export const Add = makeInNOutFunctionDesc({
43
+ name: 'math/add/vec4',
44
+ label: '+',
45
+ in: ['vec4', 'vec4'],
46
+ out: 'vec4',
47
+ exec: vec4Add
48
+ });
49
+
50
+ export const Subtract = makeInNOutFunctionDesc({
51
+ name: 'math/subtract/vec4',
52
+ label: '-',
53
+ in: ['vec4', 'vec4'],
54
+ out: 'vec4',
55
+ exec: vec4Subtract
56
+ });
57
+
58
+ export const Negate = makeInNOutFunctionDesc({
59
+ name: 'math/negate/vec4',
60
+ label: '-',
61
+ in: ['vec4'],
62
+ out: 'vec4',
63
+ exec: vec4Negate
64
+ });
65
+
66
+ export const Scale = makeInNOutFunctionDesc({
67
+ name: 'math/scale/vec4',
68
+ label: '×',
69
+ in: ['vec4', 'float'],
70
+ out: 'vec4',
71
+ exec: vec4MultiplyByScalar
72
+ });
73
+
74
+ export const Length = makeInNOutFunctionDesc({
75
+ name: 'math/length/vec4',
76
+ label: 'Length',
77
+ in: ['vec4'],
78
+ out: 'float',
79
+ exec: vec4Length
80
+ });
81
+
82
+ export const Normalize = makeInNOutFunctionDesc({
83
+ name: 'math/normalize/vec4',
84
+ label: 'Normalize',
85
+ in: ['vec4'],
86
+ out: 'vec4',
87
+ exec: vec4Normalize
88
+ });
89
+
90
+ export const Dot = makeInNOutFunctionDesc({
91
+ name: 'math/dot/vec4',
92
+ label: 'Dot Product',
93
+ in: ['vec4', 'vec4'],
94
+ out: 'float',
95
+ exec: vec4Dot
96
+ });
97
+
98
+ export const Mix = makeInNOutFunctionDesc({
99
+ name: 'math/mix/vec4',
100
+ label: '÷',
101
+ in: [{ a: 'vec4' }, { b: 'vec4' }, { t: 'float' }],
102
+ out: 'vec4',
103
+ exec: vec4Mix
104
+ });
105
+
106
+ export const Equal = makeInNOutFunctionDesc({
107
+ name: 'math/equal/vec4',
108
+ label: '=',
109
+ in: [{ a: 'vec4' }, { b: 'vec4' }, { tolerance: 'float' }],
110
+ out: 'boolean',
111
+ exec: vec4Equals
112
+ });
@@ -0,0 +1,34 @@
1
+ import {
2
+ FunctionNode,
3
+ type IGraph,
4
+ NodeDescription,
5
+ Socket
6
+ } from '@kiberon-labs/behave-graph';
7
+
8
+ export class VecElements<T> extends FunctionNode {
9
+ constructor(
10
+ description: NodeDescription,
11
+ graph: IGraph,
12
+ valueTypeName: string,
13
+ elementNames: string[] = ['x', 'y', 'z', 'w'],
14
+ toArray: (value: T, array: number[], offset: number) => void,
15
+ id: string
16
+ ) {
17
+ super(
18
+ description,
19
+ graph,
20
+ [new Socket(valueTypeName, 'value')],
21
+ elementNames.map((elementName) => new Socket('float', elementName)),
22
+ () => {
23
+ const value = this.readInput('value') as T;
24
+ const elementValues = elementNames.map(() => 0);
25
+ toArray(value, elementValues, 0);
26
+ elementNames.forEach((elementName, index) =>
27
+ this.writeOutput(elementName, elementValues[index])
28
+ );
29
+ },
30
+ {},
31
+ id
32
+ );
33
+ }
34
+ }
@@ -0,0 +1,35 @@
1
+ import {
2
+ makeFunctionNodeDefinition,
3
+ NodeCategory
4
+ } from '@kiberon-labs/behave-graph';
5
+ import type { IScene } from '../../Abstractions/IScene.js';
6
+
7
+ export const GetSceneProperty = (valueTypeNames: string[]) =>
8
+ valueTypeNames.map((valueTypeName) =>
9
+ makeFunctionNodeDefinition({
10
+ typeName: `scene/get/${valueTypeName}`,
11
+ category: NodeCategory.Query,
12
+ label: `Scene set ${valueTypeName}`,
13
+ in: {
14
+ jsonPath: (_, graphApi) => {
15
+ const scene = graphApi.getDependency<IScene>('IScene');
16
+
17
+ return {
18
+ valueType: 'string',
19
+ choices: scene?.getProperties()
20
+ };
21
+ }
22
+ },
23
+ out: {
24
+ value: valueTypeName
25
+ },
26
+ exec: ({ graph, read, write }) => {
27
+ const scene = graph.getDependency<IScene>('IScene');
28
+ const propertyValue = scene?.getProperty(
29
+ read('jsonPath'),
30
+ valueTypeName
31
+ );
32
+ write('value', propertyValue);
33
+ }
34
+ })
35
+ );
@@ -0,0 +1,22 @@
1
+ import type { ValueType } from '@kiberon-labs/behave-graph';
2
+
3
+ import {
4
+ Vec3,
5
+ vec3Equals,
6
+ type Vec3JSON,
7
+ vec3Mix,
8
+ vec3Parse
9
+ } from './Internal/Vec3.js';
10
+
11
+ export const ColorValue: ValueType = {
12
+ name: 'color',
13
+ creator: () => new Vec3(),
14
+ deserialize: (value: string | Vec3JSON) =>
15
+ typeof value === 'string'
16
+ ? vec3Parse(value)
17
+ : new Vec3(value[0], value[1], value[2]),
18
+ serialize: (value) => [value.x, value.y, value.z] as Vec3JSON,
19
+ lerp: (start: Vec3, end: Vec3, t: number) => vec3Mix(start, end, t),
20
+ equals: (a: Vec3, b: Vec3) => vec3Equals(a, b),
21
+ clone: (value: Vec3) => value.clone()
22
+ };
@@ -0,0 +1,22 @@
1
+ import type { ValueType } from '@kiberon-labs/behave-graph';
2
+
3
+ import {
4
+ Vec3,
5
+ vec3Equals,
6
+ type Vec3JSON,
7
+ vec3Mix,
8
+ vec3Parse
9
+ } from './Internal/Vec3.js';
10
+
11
+ export const EulerValue: ValueType = {
12
+ name: 'euler',
13
+ creator: () => new Vec3(),
14
+ deserialize: (value: string | Vec3JSON) =>
15
+ typeof value === 'string'
16
+ ? vec3Parse(value)
17
+ : new Vec3(value[0], value[1], value[2]),
18
+ serialize: (value) => [value.x, value.y, value.z] as Vec3JSON,
19
+ lerp: (start: Vec3, end: Vec3, t: number) => vec3Mix(start, end, t),
20
+ equals: (a: Vec3, b: Vec3) => vec3Equals(a, b),
21
+ clone: (value: Vec3) => value.clone()
22
+ };
@@ -0,0 +1,214 @@
1
+ import {
2
+ EPSILON,
3
+ equalsTolerance,
4
+ parseSafeFloats,
5
+ toSafeString
6
+ } from '@kiberon-labs/behave-graph';
7
+
8
+ import { Mat3 } from './Mat3.js';
9
+ import { Mat4 } from './Mat4.js';
10
+ import { Vec2 } from './Vec2.js';
11
+
12
+ // uses OpenGL matrix layout where each column is specified subsequently in order from left to right.
13
+ // ( x, y ) x [ 0 2 ] = ( x', y' )
14
+ // [ 1 3 ]
15
+
16
+ const NUM_ROWS = 2;
17
+ const NUM_COLUMNS = 2;
18
+ const NUM_ELEMENTS = NUM_ROWS * NUM_COLUMNS;
19
+
20
+ export type Mat2JSON = number[];
21
+
22
+ type Mat2Elements = [number, number, number, number];
23
+
24
+ export class Mat2 {
25
+ public elements: Mat2Elements;
26
+ constructor(elements: Mat2Elements = [1, 0, 0, 1]) {
27
+ this.elements = elements;
28
+ if (elements.length !== NUM_ELEMENTS) {
29
+ throw new Error(
30
+ `elements must have length ${NUM_ELEMENTS}, got ${elements.length}`
31
+ );
32
+ }
33
+ }
34
+
35
+ clone(result = new Mat2()): Mat2 {
36
+ return result.set(this.elements);
37
+ }
38
+ set(elements: Mat2Elements): this {
39
+ if (elements.length !== NUM_ELEMENTS) {
40
+ throw new Error(
41
+ `elements must have length ${NUM_ELEMENTS}, got ${elements.length}`
42
+ );
43
+ }
44
+ this.elements = [...elements];
45
+ return this;
46
+ }
47
+ }
48
+
49
+ export function mat2SetColumn3(
50
+ m: Mat2,
51
+ columnIndex: number,
52
+ column: Vec2,
53
+ result = new Mat2()
54
+ ): Mat2 {
55
+ const re = result.set(m.elements).elements;
56
+ const base = columnIndex * NUM_ROWS;
57
+ re[base + 0] = column.x;
58
+ re[base + 1] = column.y;
59
+ return result;
60
+ }
61
+
62
+ export function mat2SetRow3(
63
+ m: Mat2,
64
+ rowIndex: number,
65
+ row: Vec2,
66
+ result = new Mat2()
67
+ ): Mat2 {
68
+ const re = result.set(m.elements).elements;
69
+ re[rowIndex + NUM_COLUMNS * 0] = row.x;
70
+ re[rowIndex + NUM_COLUMNS * 1] = row.y;
71
+ return result;
72
+ }
73
+
74
+ export function column3ToMat2(
75
+ a: Vec2,
76
+ b: Vec2,
77
+ c: Vec2,
78
+ result = new Mat2()
79
+ ): Mat2 {
80
+ const re = result.elements;
81
+ const columns = [a, b, c];
82
+ for (let c = 0; c < columns.length; c++) {
83
+ const base = c * NUM_ROWS;
84
+ const column = columns[c]!;
85
+ re[base + 0] = column.x;
86
+ re[base + 1] = column.y;
87
+ }
88
+ return result;
89
+ }
90
+
91
+ export function mat2Equals(a: Mat2, b: Mat2, tolerance = EPSILON): boolean {
92
+ for (let i = 0; i < NUM_ELEMENTS; i++) {
93
+ if (!equalsTolerance(a.elements[i]!, b.elements[i]!, tolerance))
94
+ return false;
95
+ }
96
+ return true;
97
+ }
98
+ export function mat2Add(a: Mat2, b: Mat2, result: Mat2 = new Mat2()): Mat2 {
99
+ for (let i = 0; i < NUM_ELEMENTS; i++) {
100
+ result.elements[i] = a.elements[i]! + b.elements[i]!;
101
+ }
102
+ return result;
103
+ }
104
+ export function mat2Subtract(
105
+ a: Mat2,
106
+ b: Mat2,
107
+ result: Mat2 = new Mat2()
108
+ ): Mat2 {
109
+ for (let i = 0; i < NUM_ELEMENTS; i++) {
110
+ result.elements[i] = a.elements[i]! - b.elements[i]!;
111
+ }
112
+ return result;
113
+ }
114
+ export function mat2MultiplyByScalar(
115
+ a: Mat2,
116
+ b: number,
117
+ result: Mat2 = new Mat2()
118
+ ): Mat2 {
119
+ for (let i = 0; i < NUM_ELEMENTS; i++) {
120
+ result.elements[i] = a.elements[i]! * b;
121
+ }
122
+ return result;
123
+ }
124
+ export function mat2Negate(a: Mat2, result: Mat2 = new Mat2()): Mat2 {
125
+ for (let i = 0; i < NUM_ELEMENTS; i++) {
126
+ result.elements[i] = -a.elements[i]!;
127
+ }
128
+ return result;
129
+ }
130
+
131
+ export function mat2Multiply(a: Mat2, b: Mat2, result = new Mat2()): Mat2 {
132
+ throw new Error('not implemented');
133
+ }
134
+
135
+ export function mat2Determinant(m: Mat2): number {
136
+ throw new Error('not implemented');
137
+ }
138
+
139
+ export function mat2Transpose(m: Mat2, result = new Mat2()): Mat2 {
140
+ const me = m.elements;
141
+ const te = result.elements;
142
+
143
+ te[0] = me[0];
144
+ te[1] = me[2];
145
+ te[2] = me[1];
146
+ te[3] = me[3];
147
+
148
+ return result;
149
+ }
150
+
151
+ export function mat2Inverse(m: Mat2, result = new Mat2()): Mat2 {
152
+ throw new Error('not implemented');
153
+ }
154
+
155
+ export function mat2Mix(
156
+ a: Mat2,
157
+ b: Mat2,
158
+ t: number,
159
+ result = new Mat2()
160
+ ): Mat2 {
161
+ const s = 1 - t;
162
+ for (let i = 0; i < NUM_ELEMENTS; i++) {
163
+ result.elements[i] = a.elements[i]! * s + b.elements[i]! * t;
164
+ }
165
+ return result;
166
+ }
167
+ export function mat2FromArray(
168
+ array: Float32Array | number[],
169
+ offset = 0,
170
+ result: Mat2 = new Mat2()
171
+ ): Mat2 {
172
+ for (let i = 0; i < NUM_ELEMENTS; i++) {
173
+ result.elements[i] = array[offset + i]!;
174
+ }
175
+ return result;
176
+ }
177
+ export function mat2ToArray(
178
+ a: Mat2,
179
+ array: Float32Array | number[],
180
+ offset = 0
181
+ ): void {
182
+ for (let i = 0; i < NUM_ELEMENTS; i++) {
183
+ array[offset + i] = a.elements[i]!;
184
+ }
185
+ }
186
+
187
+ export function mat2ToString(a: Mat2): string {
188
+ return toSafeString(a.elements);
189
+ }
190
+ export function mat2Parse(text: string, result = new Mat2()): Mat2 {
191
+ return mat2FromArray(parseSafeFloats(text), 0, result);
192
+ }
193
+
194
+ export function scale2ToMat2(s: Vec2, result = new Mat2()): Mat2 {
195
+ return result.set([s.x, 0, 0, s.y]);
196
+ }
197
+ // from gl-matrix
198
+ export function mat2ToScale2(m: Mat4, result = new Vec2()): Vec2 {
199
+ const mat = m.elements;
200
+ const m11 = mat[0];
201
+ const m12 = mat[1];
202
+ const m21 = mat[2];
203
+ const m22 = mat[3];
204
+
205
+ return result.set(
206
+ Math.sqrt(m11 * m11 + m12 * m12),
207
+ Math.sqrt(m21 * m21 + m22 * m22)
208
+ );
209
+ }
210
+
211
+ export function mat3ToMat2(a: Mat3, result = new Mat2()): Mat2 {
212
+ const ae = a.elements;
213
+ return result.set([ae[0], ae[1], ae[3], ae[4]]);
214
+ }