@footgun/cobalt 0.1.1 → 0.2.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.
@@ -1,99 +1,104 @@
1
- import { vec2 } from '../deps.js'
1
+ import cdt2d from 'cdt2d'
2
+ import { mat3, vec2 } from 'wgpu-matrix'
2
3
 
3
4
 
4
- function line (cobalt, node, start, end, color, lineWidth=1) {
5
-
6
- const delta = vec2.sub(end, start)
5
+ // works similarly to the HTML Canvas transforms:
6
+ // https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Transformations
7
+ export default {
8
+ line,
7
9
 
8
- const unitBasis = vec2.normalize(delta)
9
- const perp = perpendicularComponent(unitBasis)
10
+ save: function (cobalt, node) {
11
+ node.data.transforms.push(mat3.clone(node.data.transforms.at(-1)))
12
+ },
10
13
 
11
- const halfLineWidth = lineWidth / 2
12
-
13
- let i = node.data.vertexCount * 6 // 2 floats position + 4 floats color per vertex
14
+ restore: function (cobalt, node) {
15
+ if (node.data.transforms.length > 1) // don't remove the identity matrix
16
+ node.data.transforms.pop()
17
+ },
14
18
 
15
- // triangle 1
16
- // pt 1
17
- node.data.vertices[i + 0] = start[0] + perp[0] * halfLineWidth
18
- node.data.vertices[i + 1] = start[1] + perp[1] * halfLineWidth
19
+ translate: function (cobalt, node, translation) {
20
+ const m = node.data.transforms.at(-1)
21
+ mat3.translate(m, translation, m)
22
+ },
19
23
 
20
- // pt1 color
21
- node.data.vertices[i + 2] = color[0]
22
- node.data.vertices[i + 3] = color[1]
23
- node.data.vertices[i + 4] = color[2]
24
- node.data.vertices[i + 5] = color[3]
24
+ rotate: function (cobalt, node, radians) {
25
+ const m = node.data.transforms.at(-1)
26
+ mat3.rotate(m, radians, m)
27
+ },
25
28
 
26
- // pt 2
27
- node.data.vertices[i + 6] = start[0] - perp[0] * halfLineWidth
28
- node.data.vertices[i + 7] = start[1] - perp[1] * halfLineWidth
29
+ scale: function (cobalt, node, scale) {
30
+ const m = node.data.transforms.at(-1)
31
+ mat3.scale(m, scale, m)
32
+ },
29
33
 
30
- // pt2 color
31
- node.data.vertices[i + 8] = color[0]
32
- node.data.vertices[i + 9] = color[1]
33
- node.data.vertices[i + 10] = color[2]
34
- node.data.vertices[i + 11] = color[3]
34
+ strokePath: function (cobalt, node, segments, color, lineWidth=1) {
35
+ for (const s of segments)
36
+ line(cobalt, node, s[0], s[1], color, lineWidth)
37
+ },
35
38
 
36
- // pt 3
37
- node.data.vertices[i + 12] = end[0] + perp[0] * halfLineWidth
38
- node.data.vertices[i + 13] = end[1] + perp[1] * halfLineWidth
39
+ filledPath: function (cobalt, node, points, color) {
39
40
 
40
- // pt3 color
41
- node.data.vertices[i + 14] = color[0]
42
- node.data.vertices[i + 15] = color[1]
43
- node.data.vertices[i + 16] = color[2]
44
- node.data.vertices[i + 17] = color[3]
45
-
41
+ const edges = [ ]
46
42
 
47
- // triangle 2
48
- // pt 2
49
- node.data.vertices[i + 18] = start[0] - perp[0] * halfLineWidth
50
- node.data.vertices[i + 19] = start[1] - perp[1] * halfLineWidth
43
+ for (let i=1; i < points.length; i++)
44
+ edges.push([ i-1, i ])
51
45
 
52
- // pt2 color
53
- node.data.vertices[i + 20] = color[0]
54
- node.data.vertices[i + 21] = color[1]
55
- node.data.vertices[i + 22] = color[2]
56
- node.data.vertices[i + 23] = color[3]
57
-
58
- // pt 3
59
- node.data.vertices[i + 24] = end[0] + perp[0] * halfLineWidth
60
- node.data.vertices[i + 25] = end[1] + perp[1] * halfLineWidth
61
46
 
62
- // pt3 color
63
- node.data.vertices[i + 26] = color[0]
64
- node.data.vertices[i + 27] = color[1]
65
- node.data.vertices[i + 28] = color[2]
66
- node.data.vertices[i + 29] = color[3]
47
+ // The flag {exterior: false} tells it to remove exterior faces
48
+ const triangles = cdt2d(points, edges, { exterior: true })
67
49
 
68
- // pt 4
69
- node.data.vertices[i + 30] = end[0] - perp[0] * halfLineWidth
70
- node.data.vertices[i + 31] = end[1] - perp[1] * halfLineWidth
50
+ const m = node.data.transforms.at(-1)
71
51
 
72
- // pt4 color
73
- node.data.vertices[i + 32] = color[0]
74
- node.data.vertices[i + 33] = color[1]
75
- node.data.vertices[i + 34] = color[2]
76
- node.data.vertices[i + 35] = color[3]
52
+ let i = node.data.vertexCount * 6 // 2 floats position + 4 floats color per vertex
77
53
 
54
+ const pos = vec2.create()
78
55
 
79
- node.data.vertexCount += 6
56
+ for (const tri of triangles) {
80
57
 
81
- node.data.dirty = true
82
- }
58
+ // pt 1
59
+ vec2.transformMat3(points[tri[0]], m, pos)
60
+ node.data.vertices[i + 0] = pos[0]
61
+ node.data.vertices[i + 1] = pos[1]
83
62
 
63
+ // pt1 color
64
+ node.data.vertices[i + 2] = color[0]
65
+ node.data.vertices[i + 3] = color[1]
66
+ node.data.vertices[i + 4] = color[2]
67
+ node.data.vertices[i + 5] = color[3]
84
68
 
85
- // return component of vector perpendicular to a unit basis vector
86
- // (IMPORTANT NOTE: assumes "basis" has unit magnitude (length==1))
87
- function perpendicularComponent (inp) {
88
- return [ -inp[1], inp[0] ]
89
- }
69
+ // pt 2
70
+ vec2.transformMat3(points[tri[1]], m, pos)
71
+ node.data.vertices[i + 6] = pos[0]
72
+ node.data.vertices[i + 7] = pos[1]
90
73
 
74
+ // pt2 color
75
+ node.data.vertices[i + 8] = color[0]
76
+ node.data.vertices[i + 9] = color[1]
77
+ node.data.vertices[i + 10] = color[2]
78
+ node.data.vertices[i + 11] = color[3]
79
+
80
+ // pt 3
81
+ vec2.transformMat3(points[tri[2]], m, pos)
82
+ node.data.vertices[i + 12] = pos[0]
83
+ node.data.vertices[i + 13] = pos[1]
84
+
85
+ // pt3 color
86
+ node.data.vertices[i + 14] = color[0]
87
+ node.data.vertices[i + 15] = color[1]
88
+ node.data.vertices[i + 16] = color[2]
89
+ node.data.vertices[i + 17] = color[3]
90
+
91
+ i += 18
92
+ }
93
+
94
+ node.data.vertexCount += (3 * triangles.length)
95
+
96
+ node.data.dirty = true
97
+ },
91
98
 
92
- export default {
93
- line,
94
99
 
95
100
  ellipse: function (cobalt, node, center, halfWidth, halfHeight, numSegments, color, lineWidth=1) {
96
-
101
+
97
102
  const [ x, y ] = center
98
103
 
99
104
  // angle between each segment
@@ -122,6 +127,8 @@ export default {
122
127
  // angle between each segment
123
128
  const deltaAngle = 2 * Math.PI / numSegments
124
129
 
130
+ const m = node.data.transforms.at(-1)
131
+
125
132
  // Generate points for the ellipsoid
126
133
  for (let i = 0; i < numSegments; i++) {
127
134
  // Angle for this and the next segment
@@ -141,8 +148,9 @@ export default {
141
148
  const vi = (node.data.vertexCount * 6) + (i * stride)
142
149
 
143
150
  // position
144
- node.data.vertices[vi + 0] = x
145
- node.data.vertices[vi + 1] = y
151
+ const pos = vec2.transformMat3([ x, y ], m)
152
+ node.data.vertices[vi + 0] = pos[0]
153
+ node.data.vertices[vi + 1] = pos[1]
146
154
 
147
155
  // color
148
156
  node.data.vertices[vi + 2] = color[0]
@@ -154,8 +162,9 @@ export default {
154
162
  // Second triangle vertex (current point on ellipse)
155
163
 
156
164
  // position
157
- node.data.vertices[vi + 6] = currX
158
- node.data.vertices[vi + 7] = currY
165
+ vec2.transformMat3([ currX, currY ], m, pos)
166
+ node.data.vertices[vi + 6] = pos[0]
167
+ node.data.vertices[vi + 7] = pos[1]
159
168
 
160
169
  // color
161
170
  node.data.vertices[vi + 8] = color[0]
@@ -166,8 +175,9 @@ export default {
166
175
 
167
176
  // Third triangle vertex (next point on ellipse)
168
177
  // position
169
- node.data.vertices[vi + 12] = nextX
170
- node.data.vertices[vi + 13] = nextY
178
+ vec2.transformMat3([ nextX, nextY ], m, pos)
179
+ node.data.vertices[vi + 12] = pos[0]
180
+ node.data.vertices[vi + 13] = pos[1]
171
181
 
172
182
  // color
173
183
  node.data.vertices[vi + 14] = color[0]
@@ -181,8 +191,7 @@ export default {
181
191
  node.data.dirty = true
182
192
  },
183
193
 
184
- // @param Number angle rotation (radians)
185
- box: function (cobalt, node, center, width, height, color, angle=0, lineWidth=1) {
194
+ box: function (cobalt, node, center, width, height, color, lineWidth=1) {
186
195
  const [ x, y ] = center
187
196
 
188
197
  const halfWidth = width / 2
@@ -193,43 +202,25 @@ export default {
193
202
  const bottomLeft = [ x - halfWidth, y + halfHeight ]
194
203
  const bottomRight = [ x + halfWidth, y + halfHeight ]
195
204
 
196
- if (angle !== 0) {
197
- // rotate the point by <angle> rads around origin
198
- // point origin rads out
199
- _rotate(topLeft, center, angle, topLeft)
200
- _rotate(topRight, center, angle, topRight)
201
- _rotate(bottomLeft, center, angle, bottomLeft)
202
- _rotate(bottomRight, center, angle, bottomRight)
203
- }
204
-
205
205
  line(cobalt, node, topLeft, topRight, color, lineWidth)
206
206
  line(cobalt, node, bottomLeft, bottomRight, color, lineWidth)
207
207
  line(cobalt, node, topLeft, bottomLeft, color, lineWidth)
208
208
  line(cobalt, node, topRight, bottomRight, color, lineWidth)
209
209
  },
210
210
 
211
-
212
-
213
- // @param Number angle rotation (radians)
214
- filledBox: function (cobalt, node, center, width, height, color, angle=0) {
211
+ filledBox: function (cobalt, node, center, width, height, color) {
212
+
215
213
  const [ x, y ] = center
216
214
 
217
215
  const halfWidth = width / 2
218
216
  const halfHeight = height / 2
219
217
 
220
- const topLeft = [ x - halfWidth, y - halfHeight ];
221
- const topRight = [ x + halfWidth, y - halfHeight ];
222
- const bottomLeft = [ x - halfWidth, y + halfHeight ];
223
- const bottomRight = [ x + halfWidth, y + halfHeight ];
224
-
225
- if (angle !== 0) {
226
- // rotate the point by <angle> rads around origin
227
- // point origin rads out
228
- _rotate(topLeft, center, angle, topLeft)
229
- _rotate(topRight, center, angle, topRight)
230
- _rotate(bottomLeft, center, angle, bottomLeft)
231
- _rotate(bottomRight, center, angle, bottomRight)
232
- }
218
+ const m = node.data.transforms.at(-1)
219
+
220
+ const topLeft = vec2.transformMat3([ x - halfWidth, y - halfHeight ], m)
221
+ const topRight = vec2.transformMat3([ x + halfWidth, y - halfHeight ], m)
222
+ const bottomLeft = vec2.transformMat3([ x - halfWidth, y + halfHeight ], m)
223
+ const bottomRight = vec2.transformMat3([ x + halfWidth, y + halfHeight ], m)
233
224
 
234
225
  let i = node.data.vertexCount * 6 // 2 floats position + 4 floats color per vertex
235
226
 
@@ -305,21 +296,99 @@ export default {
305
296
 
306
297
  clear: function (cobalt, node) {
307
298
  node.data.vertexCount = 0
299
+ node.data.transforms.length = 1 // remove all transform matrices except the first one
300
+ mat3.identity(node.data.transforms[0])
308
301
  node.data.dirty = true
309
302
  },
310
303
  }
311
304
 
312
305
 
313
- function _rotate (a, b, rad, out) {
314
- //Translate point to the origin
315
- let p0 = a[0] - b[0],
316
- p1 = a[1] - b[1],
317
- sinC = Math.sin(rad),
318
- cosC = Math.cos(rad);
306
+ function line (cobalt, node, start, end, color, lineWidth=1) {
307
+
308
+ const m = node.data.transforms.at(-1)
309
+ start = vec2.transformMat3(start, m)
310
+ end = vec2.transformMat3(end, m)
311
+
312
+ const delta = vec2.sub(end, start)
313
+
314
+ const unitBasis = vec2.normalize(delta)
315
+ const perp = perpendicularComponent(unitBasis)
316
+
317
+ const halfLineWidth = lineWidth / 2
318
+
319
+ let i = node.data.vertexCount * 6 // 2 floats position + 4 floats color per vertex
320
+
321
+ // triangle 1
322
+ // pt 1
323
+ node.data.vertices[i + 0] = start[0] + perp[0] * halfLineWidth
324
+ node.data.vertices[i + 1] = start[1] + perp[1] * halfLineWidth
325
+
326
+ // pt1 color
327
+ node.data.vertices[i + 2] = color[0]
328
+ node.data.vertices[i + 3] = color[1]
329
+ node.data.vertices[i + 4] = color[2]
330
+ node.data.vertices[i + 5] = color[3]
331
+
332
+ // pt 2
333
+ node.data.vertices[i + 6] = start[0] - perp[0] * halfLineWidth
334
+ node.data.vertices[i + 7] = start[1] - perp[1] * halfLineWidth
335
+
336
+ // pt2 color
337
+ node.data.vertices[i + 8] = color[0]
338
+ node.data.vertices[i + 9] = color[1]
339
+ node.data.vertices[i + 10] = color[2]
340
+ node.data.vertices[i + 11] = color[3]
341
+
342
+ // pt 3
343
+ node.data.vertices[i + 12] = end[0] + perp[0] * halfLineWidth
344
+ node.data.vertices[i + 13] = end[1] + perp[1] * halfLineWidth
345
+
346
+ // pt3 color
347
+ node.data.vertices[i + 14] = color[0]
348
+ node.data.vertices[i + 15] = color[1]
349
+ node.data.vertices[i + 16] = color[2]
350
+ node.data.vertices[i + 17] = color[3]
351
+
352
+
353
+ // triangle 2
354
+ // pt 2
355
+ node.data.vertices[i + 18] = start[0] - perp[0] * halfLineWidth
356
+ node.data.vertices[i + 19] = start[1] - perp[1] * halfLineWidth
319
357
 
320
- //perform rotation and translate to correct position
321
- out[0] = p0 * cosC - p1 * sinC + b[0];
322
- out[1] = p0 * sinC + p1 * cosC + b[1];
323
- return out;
358
+ // pt2 color
359
+ node.data.vertices[i + 20] = color[0]
360
+ node.data.vertices[i + 21] = color[1]
361
+ node.data.vertices[i + 22] = color[2]
362
+ node.data.vertices[i + 23] = color[3]
363
+
364
+ // pt 3
365
+ node.data.vertices[i + 24] = end[0] + perp[0] * halfLineWidth
366
+ node.data.vertices[i + 25] = end[1] + perp[1] * halfLineWidth
367
+
368
+ // pt3 color
369
+ node.data.vertices[i + 26] = color[0]
370
+ node.data.vertices[i + 27] = color[1]
371
+ node.data.vertices[i + 28] = color[2]
372
+ node.data.vertices[i + 29] = color[3]
373
+
374
+ // pt 4
375
+ node.data.vertices[i + 30] = end[0] - perp[0] * halfLineWidth
376
+ node.data.vertices[i + 31] = end[1] - perp[1] * halfLineWidth
377
+
378
+ // pt4 color
379
+ node.data.vertices[i + 32] = color[0]
380
+ node.data.vertices[i + 33] = color[1]
381
+ node.data.vertices[i + 34] = color[2]
382
+ node.data.vertices[i + 35] = color[3]
383
+
384
+
385
+ node.data.vertexCount += 6
386
+ node.data.dirty = true
324
387
  }
325
388
 
389
+
390
+ // return component of vector perpendicular to a unit basis vector
391
+ // (IMPORTANT NOTE: assumes "basis" has unit magnitude (length==1))
392
+ function perpendicularComponent (inp) {
393
+ return [ -inp[1], inp[0] ]
394
+ }
@@ -3,7 +3,8 @@ import createTextureFromBuffer from '../create-texture-from-buffer.js'
3
3
  import createTextureFromUrl from '../create-texture-from-url.js'
4
4
  import readSpriteSheet from './read-spritesheet.js'
5
5
  import spriteWGSL from './sprite.wgsl'
6
- import { round, mat4, vec3 } from '../deps.js'
6
+ import round from 'round-half-up-symmetric'
7
+ import { mat4, vec3 } from 'wgpu-matrix'
7
8
 
8
9
 
9
10
  // shared spritesheet resource, used by each sprite render node
@@ -1,8 +0,0 @@
1
- export default function componentAnimation (obj) {
2
- return {
3
- name: obj.name || '',
4
- frame: obj.frame || 0,
5
- accumulator: obj.accumulator || 0,
6
- done: false,
7
- }
8
- }
@@ -1,13 +0,0 @@
1
- import { vec3 } from './deps.js'
2
-
3
-
4
- export default function componentTransform (obj) {
5
- return {
6
- position: obj.position || vec3.create(0, 0, 0),
7
- rotation: obj.rotation || 0,
8
-
9
- // if set, this means the position is relative to another transform
10
- // rather than being in world space
11
- relativeTo: obj.relativeTo,
12
- }
13
- }
@@ -1,47 +0,0 @@
1
- import * as Cobalt from '../../bundle.js'
2
- import animationComponent from './component-animation.js'
3
- import transformComponent from './component-transform.js'
4
- import { ECS, vec3, vec4 } from './deps.js'
5
-
6
-
7
- export default function spriteEntity (world, opts) {
8
- const ENTITY = ECS.createEntity(world)
9
-
10
- ECS.addComponentToEntity(world, ENTITY, 'transform', transformComponent({
11
- position: vec3.create(opts.position[0], opts.position[1], 0)
12
- }))
13
-
14
- ECS.addComponentToEntity(world, ENTITY, 'animation', animationComponent({
15
- name: opts.name
16
- }))
17
-
18
- const tint = vec4.create(0, 0, 0, 0)
19
-
20
- const opacity = opts.opacity ?? 255
21
-
22
- const spriteNode = opts.spriteNode
23
-
24
- const cobaltSpriteId = spriteNode.addSprite(opts.name,
25
- opts.position,
26
- vec3.create(1, 1, 1),
27
- tint,
28
- opacity / 255,
29
- opts.rotation || 0,
30
- opts.zIndex)
31
-
32
- ECS.addComponentToEntity(world, ENTITY, 'sprite', {
33
- name: opts.name,
34
-
35
- layer: opts.layer,
36
- rotation: 0, // radians
37
- scale: vec3.create(1, 1, 1),
38
- opacity: 1, // 0 is transparent, 1 is opaque
39
- tint: vec4.create(0, 0, 0, 0),
40
-
41
- // cobalt references
42
- cobaltSpriteId,
43
- spriteNode,
44
- })
45
-
46
- return ENTITY
47
- }
package/src/deps.js DELETED
@@ -1,3 +0,0 @@
1
- export { default as removeArrayItems } from 'https://cdn.jsdelivr.net/gh/mreinstein/remove-array-items/src/remove-array-items.js'
2
- export { default as round } from 'https://cdn.skypack.dev/pin/round-half-up-symmetric@v2.0.0-pfMZ4UGGs9FcqO8UiEHO/mode=imports,min/optimized/round-half-up-symmetric.js'
3
- export { mat4, vec2, vec3, vec4 } from 'https://wgpu-matrix.org/dist/3.x/wgpu-matrix.module.js'
File without changes