@footgun/cobalt 0.7.0 → 0.7.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.
@@ -1,29 +1,27 @@
1
- import uuid from '../uuid.js'
2
1
  import { vec2, vec4 } from 'wgpu-matrix'
3
-
2
+ import uuid from '../uuid.js'
4
3
 
5
4
  // returns a unique identifier for the created sprite
6
- export function addSprite (cobalt, renderPass, name, position, scale, tint, opacity, rotation) {
7
-
5
+ export function addSprite(cobalt, renderPass, name, position, scale, tint, opacity, rotation) {
8
6
  const { idByName } = renderPass.refs.spritesheet.data
9
7
 
10
8
  renderPass.data.sprites.push({
11
- position: vec2.clone(position),
12
- sizeX: 1, sizeY: 1,
13
- scale: vec2.clone(scale),
14
- rotation,
15
- opacity,
16
- tint: vec4.clone(tint),
17
- spriteID: idByName.get(name),
18
- id: uuid(),
19
- });
20
-
21
- return renderPass.data.sprites.at(-1).id
9
+ position: vec2.clone(position),
10
+ sizeX: 1,
11
+ sizeY: 1,
12
+ scale: vec2.clone(scale),
13
+ rotation,
14
+ opacity,
15
+ tint: vec4.clone(tint),
16
+ spriteID: idByName.get(name),
17
+ id: uuid(),
18
+ })
19
+
20
+ return renderPass.data.sprites.at(-1).id
22
21
  }
23
22
 
24
-
25
- export function removeSprite (cobalt, renderPass, id) {
26
- for (let i=0; i < renderPass.data.sprites.length; i++) {
23
+ export function removeSprite(cobalt, renderPass, id) {
24
+ for (let i = 0; i < renderPass.data.sprites.length; i++) {
27
25
  if (renderPass.data.sprites[i].id === id) {
28
26
  renderPass.data.sprites.splice(i, 1)
29
27
  return
@@ -31,65 +29,52 @@ export function removeSprite (cobalt, renderPass, id) {
31
29
  }
32
30
  }
33
31
 
34
-
35
32
  // remove all sprites
36
- export function clear (cobalt, renderPass) {
37
- renderPass.data.sprites.length = 0
33
+ export function clear(cobalt, renderPass) {
34
+ renderPass.data.sprites.length = 0
38
35
  }
39
36
 
40
-
41
- export function setSpriteName (cobalt, renderPass, id, name) {
37
+ export function setSpriteName(cobalt, renderPass, id, name) {
42
38
  const sprite = renderPass.data.sprites.find((s) => s.id === id)
43
39
 
44
- if (!sprite)
45
- return
40
+ if (!sprite) return
46
41
 
47
42
  const { idByName } = renderPass.refs.spritesheet.data
48
43
 
49
44
  sprite.spriteID = idByName.get(name)
50
45
  }
51
46
 
52
-
53
- export function setSpritePosition (cobalt, renderPass, id, position) {
47
+ export function setSpritePosition(cobalt, renderPass, id, position) {
54
48
  const sprite = renderPass.data.sprites.find((s) => s.id === id)
55
- if (!sprite)
56
- return
49
+ if (!sprite) return
57
50
 
58
51
  vec2.copy(position, sprite.position)
59
52
  }
60
53
 
61
-
62
- export function setSpriteTint (cobalt, renderPass, id, tint) {
54
+ export function setSpriteTint(cobalt, renderPass, id, tint) {
63
55
  const sprite = renderPass.data.sprites.find((s) => s.id === id)
64
- if (!sprite)
65
- return
56
+ if (!sprite) return
66
57
 
67
58
  vec4.copy(tint, sprite.tint)
68
59
  }
69
60
 
70
-
71
- export function setSpriteOpacity (cobalt, renderPass, id, opacity) {
61
+ export function setSpriteOpacity(cobalt, renderPass, id, opacity) {
72
62
  const sprite = renderPass.data.sprites.find((s) => s.id === id)
73
- if (!sprite)
74
- return
63
+ if (!sprite) return
75
64
 
76
65
  sprite.opacity = opacity
77
66
  }
78
67
 
79
-
80
- export function setSpriteRotation (cobalt, renderPass, id, rotation) {
68
+ export function setSpriteRotation(cobalt, renderPass, id, rotation) {
81
69
  const sprite = renderPass.data.sprites.find((s) => s.id === id)
82
- if (!sprite)
83
- return
70
+ if (!sprite) return
84
71
 
85
72
  sprite.rotation = rotation
86
73
  }
87
74
 
88
-
89
- export function setSpriteScale (cobalt, renderPass, id, scale) {
75
+ export function setSpriteScale(cobalt, renderPass, id, scale) {
90
76
  const sprite = renderPass.data.sprites.find((s) => s.id === id)
91
- if (!sprite)
92
- return
77
+ if (!sprite) return
93
78
 
94
- vec2.copy(scale, sprite.scale)
79
+ vec2.copy(scale, sprite.scale)
95
80
  }
@@ -1,35 +1,33 @@
1
+ import round from 'round-half-up-symmetric'
2
+ import { mat4, vec3 } from 'wgpu-matrix'
1
3
  import getPreferredFormat from '../get-preferred-format.js'
2
4
  import * as publicAPI from './public-api.js'
3
- import spriteWGSL from './sprite.wgsl'
4
- import round from 'round-half-up-symmetric'
5
- import { mat4, vec3 } from 'wgpu-matrix'
6
-
5
+ import spriteWGSL from './sprite.wgsl'
7
6
 
8
7
  // temporary variables, allocated once to avoid garbage collection
9
8
  const _tmpVec3 = vec3.create(0, 0, 0)
10
9
 
11
10
  // Packed instance layout: 48 bytes (aligned for vec4 fetch)
12
- const INSTANCE_STRIDE = 64;
11
+ const INSTANCE_STRIDE = 64
13
12
 
14
13
  // Offsets inside one instance (bytes)
15
- const OFF_POS = 0; // float32x2 (8B)
16
- const OFF_SIZE = 8; // float32x2 (8B)
17
- const OFF_SCALE = 16; // float32x2 (8B)
18
- const OFF_TINT = 24; // float32x4 (16B)
19
- const OFF_SPRITEID = 40; // uint32 (4B)
20
- const OFF_OPACITY = 44; // float32 (4B)
21
- const OFF_ROT = 48; // float32 (4B)
22
-
14
+ const OFF_POS = 0 // float32x2 (8B)
15
+ const OFF_SIZE = 8 // float32x2 (8B)
16
+ const OFF_SCALE = 16 // float32x2 (8B)
17
+ const OFF_TINT = 24 // float32x4 (16B)
18
+ const OFF_SPRITEID = 40 // uint32 (4B)
19
+ const OFF_OPACITY = 44 // float32 (4B)
20
+ const OFF_ROT = 48 // float32 (4B)
23
21
 
24
22
  export default {
25
- type: "cobalt:sprite",
23
+ type: 'cobalt:sprite',
26
24
  refs: [
27
- { name: "spritesheet", type: "customResource", access: "read" },
25
+ { name: 'spritesheet', type: 'customResource', access: 'read' },
28
26
  {
29
- name: "color",
30
- type: "textureView",
31
- format: "rgba8unorm",
32
- access: "write",
27
+ name: 'color',
28
+ type: 'textureView',
29
+ format: 'rgba8unorm',
30
+ access: 'write',
33
31
  },
34
32
  ],
35
33
 
@@ -38,32 +36,38 @@ export default {
38
36
  // @params Object cobalt renderer world object
39
37
  // @params Object options optional data passed when initing this node
40
38
  onInit: async function (cobalt, options = {}) {
41
- return init(cobalt, options);
39
+ return init(cobalt, options)
42
40
  },
43
41
 
44
42
  onRun: function (cobalt, node, webGpuCommandEncoder) {
45
43
  // do whatever you need for this node. webgpu renderpasses, etc.
46
- draw(cobalt, node, webGpuCommandEncoder);
44
+ draw(cobalt, node, webGpuCommandEncoder)
47
45
  },
48
46
 
49
47
  // Clean up GPU resources. Most WebGPU objects are GC-managed and don't
50
48
  // expose destroy(); buffers/textures/query-sets do.
51
49
  onDestroy: function (cobalt, node) {
52
50
  // Explicitly destroy GPU resources that have a destroy() method
53
- try { node.data.instanceBuf?.destroy(); } catch {}
54
- try { node.data.spriteBuf?.destroy(); } catch {}
55
- try { node.data.uniformBuffer?.destroy(); } catch {}
51
+ try {
52
+ node.data.instanceBuf?.destroy()
53
+ } catch {}
54
+ try {
55
+ node.data.spriteBuf?.destroy()
56
+ } catch {}
57
+ try {
58
+ node.data.uniformBuffer?.destroy()
59
+ } catch {}
56
60
 
57
61
  // These do not have destroy(); drop references to let GC reclaim
58
- node.data.pipeline = null; // GPURenderPipeline
59
- node.data.bindGroup = null; // GPUBindGroup
60
- node.data.bindGroupLayout = null;// GPUBindGroupLayout
62
+ node.data.pipeline = null // GPURenderPipeline
63
+ node.data.bindGroup = null // GPUBindGroup
64
+ node.data.bindGroupLayout = null // GPUBindGroupLayout
61
65
 
62
66
  // CPU-side allocations
63
- node.data.instanceStaging = null;
64
- node.data.instanceView = null;
65
- node.data.sprites.length = 0;
66
- node.data.visible.length = 0;
67
+ node.data.instanceStaging = null
68
+ node.data.instanceView = null
69
+ node.data.sprites.length = 0
70
+ node.data.visible.length = 0
67
71
  },
68
72
 
69
73
  onResize: function (cobalt, node) {
@@ -78,108 +82,108 @@ export default {
78
82
  customFunctions: {
79
83
  ...publicAPI,
80
84
  },
81
- };
85
+ }
82
86
 
83
87
  async function init(cobalt, nodeData) {
84
- const { device } = cobalt;
88
+ const { device } = cobalt
85
89
 
86
90
  const { descs, names } = nodeData.refs.spritesheet.data.spritesheet
87
91
 
88
92
  const uniformBuffer = device.createBuffer({
89
93
  size: 64 * 2, // 4x4 matrix with 4 bytes per float32, times 2 matrices (view, projection)
90
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
94
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
91
95
  })
92
96
 
93
97
  // Pack into std430-like struct (4*float*? + vec2 + vec2 → 32 bytes). We'll just write tightly as 8 floats.
94
- const BYTES_PER_DESC = 8 * 4; // 8 float32s
95
- const buf = new ArrayBuffer(BYTES_PER_DESC * descs.length);
96
- const f32 = new Float32Array(buf);
97
- for (let i=0;i<descs.length;i++){
98
- const d = descs[i];
99
- const base = i * 8;
100
- f32[base+0] = d.UvOrigin[0];
101
- f32[base+1] = d.UvOrigin[1];
102
- f32[base+2] = d.UvSpan[0];
103
- f32[base+3] = d.UvSpan[1];
104
- f32[base+4] = d.FrameSize[0];
105
- f32[base+5] = d.FrameSize[1];
106
- f32[base+6] = d.CenterOffset[0];
107
- f32[base+7] = d.CenterOffset[1];
98
+ const BYTES_PER_DESC = 8 * 4 // 8 float32s
99
+ const buf = new ArrayBuffer(BYTES_PER_DESC * descs.length)
100
+ const f32 = new Float32Array(buf)
101
+ for (let i = 0; i < descs.length; i++) {
102
+ const d = descs[i]
103
+ const base = i * 8
104
+ f32[base + 0] = d.UvOrigin[0]
105
+ f32[base + 1] = d.UvOrigin[1]
106
+ f32[base + 2] = d.UvSpan[0]
107
+ f32[base + 3] = d.UvSpan[1]
108
+ f32[base + 4] = d.FrameSize[0]
109
+ f32[base + 5] = d.FrameSize[1]
110
+ f32[base + 6] = d.CenterOffset[0]
111
+ f32[base + 7] = d.CenterOffset[1]
108
112
  }
109
113
 
110
114
  // create buffer for sprite uv lookup
111
115
  const spriteBuf = device.createBuffer({
112
- label: "sprite desc table",
116
+ label: 'sprite desc table',
113
117
  size: Math.max(16, buf.byteLength),
114
118
  usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST,
115
- });
119
+ })
116
120
 
117
- device.queue.writeBuffer(spriteBuf, 0, buf);
121
+ device.queue.writeBuffer(spriteBuf, 0, buf)
118
122
 
119
123
  // --- Instance buffer (growable) ---
120
- const instanceCap = 1024;
124
+ const instanceCap = 1024
121
125
  const instanceBuf = device.createBuffer({
122
- label: "sprite instances",
126
+ label: 'sprite instances',
123
127
  size: INSTANCE_STRIDE * instanceCap,
124
128
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
125
- });
126
- const instanceStaging = new ArrayBuffer(INSTANCE_STRIDE * instanceCap);
127
- const instanceView = new DataView(instanceStaging);
129
+ })
130
+ const instanceStaging = new ArrayBuffer(INSTANCE_STRIDE * instanceCap)
131
+ const instanceView = new DataView(instanceStaging)
128
132
 
129
133
  // --- Pipeline ---
130
- const shader = device.createShaderModule({ code: spriteWGSL });
134
+ const shader = device.createShaderModule({ code: spriteWGSL })
131
135
  const bgl = device.createBindGroupLayout({
132
136
  entries: [
133
137
  {
134
138
  binding: 0,
135
139
  visibility: GPUShaderStage.VERTEX,
136
- buffer: { type: "uniform" },
140
+ buffer: { type: 'uniform' },
137
141
  },
138
142
  {
139
143
  binding: 1,
140
144
  visibility: GPUShaderStage.FRAGMENT,
141
- sampler: { type: "filtering" },
145
+ sampler: { type: 'filtering' },
142
146
  },
143
147
  {
144
148
  binding: 2,
145
149
  visibility: GPUShaderStage.FRAGMENT,
146
- texture: { sampleType: "float" },
150
+ texture: { sampleType: 'float' },
147
151
  },
148
152
  {
149
153
  binding: 3,
150
154
  visibility: GPUShaderStage.VERTEX,
151
- buffer: { type: "read-only-storage" },
155
+ buffer: { type: 'read-only-storage' },
152
156
  },
153
157
  ],
154
- });
158
+ })
155
159
  const pipelineLayout = device.createPipelineLayout({
156
160
  bindGroupLayouts: [bgl],
157
- });
161
+ })
158
162
 
159
163
  const instLayout = {
160
164
  arrayStride: INSTANCE_STRIDE,
161
- stepMode: "instance",
165
+ stepMode: 'instance',
162
166
  attributes: [
163
- { shaderLocation: 0, offset: OFF_POS, format: "float32x2" },
164
- { shaderLocation: 1, offset: OFF_SIZE, format: "float32x2" },
165
- { shaderLocation: 2, offset: OFF_SCALE, format: "float32x2" },
166
- { shaderLocation: 3, offset: OFF_TINT, format: "float32x4" },
167
- { shaderLocation: 4, offset: OFF_SPRITEID, format: "uint32" },
168
- { shaderLocation: 5, offset: OFF_OPACITY, format: "float32" },
169
- { shaderLocation: 6, offset: OFF_ROT, format: "float32" },
167
+ { shaderLocation: 0, offset: OFF_POS, format: 'float32x2' },
168
+ { shaderLocation: 1, offset: OFF_SIZE, format: 'float32x2' },
169
+ { shaderLocation: 2, offset: OFF_SCALE, format: 'float32x2' },
170
+ { shaderLocation: 3, offset: OFF_TINT, format: 'float32x4' },
171
+ { shaderLocation: 4, offset: OFF_SPRITEID, format: 'uint32' },
172
+ { shaderLocation: 5, offset: OFF_OPACITY, format: 'float32' },
173
+ { shaderLocation: 6, offset: OFF_ROT, format: 'float32' },
170
174
  ],
171
- };
175
+ }
172
176
 
173
177
  const pipeline = device.createRenderPipeline({
174
178
  layout: pipelineLayout,
175
179
  vertex: {
176
180
  module: shader,
177
- entryPoint: "vs_main",
181
+ entryPoint: 'vs_main',
178
182
  buffers: [instLayout],
179
183
  },
180
184
  fragment: {
181
185
  module: shader,
182
- entryPoint: "fs_main",
186
+ entryPoint: 'fs_main',
183
187
  targets: [
184
188
  // color
185
189
  {
@@ -191,17 +195,15 @@ async function init(cobalt, nodeData) {
191
195
  },
192
196
  alpha: {
193
197
  srcFactor: 'zero',
194
- dstFactor: 'one'
195
- }
196
- }
198
+ dstFactor: 'one',
199
+ },
200
+ },
197
201
  },
198
202
  ],
199
203
  },
200
- primitive: { topology: "triangle-strip", cullMode: "none" },
204
+ primitive: { topology: 'triangle-strip', cullMode: 'none' },
201
205
  multisample: { count: 1 },
202
- });
203
-
204
- const bindGroupLayout = bgl;
206
+ })
205
207
 
206
208
  const bindGroup = device.createBindGroup({
207
209
  layout: bgl,
@@ -213,11 +215,11 @@ async function init(cobalt, nodeData) {
213
215
  { binding: 2, resource: nodeData.refs.spritesheet.data.colorTexture.view },
214
216
  { binding: 3, resource: { buffer: spriteBuf } },
215
217
  ],
216
- });
218
+ })
217
219
 
218
220
  return {
219
- sprites: [ ],
220
- visible: [ ],
221
+ sprites: [],
222
+ visible: [],
221
223
  visibleCount: 0,
222
224
  viewRect: { x: 0, y: 0, w: 0, h: 0 },
223
225
 
@@ -234,36 +236,29 @@ async function init(cobalt, nodeData) {
234
236
  }
235
237
  }
236
238
 
237
-
238
- function ensureCapacity (cobalt, node, nInstances) {
239
-
239
+ function ensureCapacity(cobalt, node, nInstances) {
240
240
  const { instanceCap } = node.data
241
241
 
242
- if (nInstances <= instanceCap)
243
- return;
242
+ if (nInstances <= instanceCap) return
244
243
 
245
244
  let newCap = instanceCap
246
- if (newCap === 0)
247
- newCap = 1024;
245
+ if (newCap === 0) newCap = 1024
248
246
 
249
- while (newCap < nInstances)
250
- newCap *= 2;
247
+ while (newCap < nInstances) newCap *= 2
251
248
 
252
- node.data.instanceBuf.destroy();
249
+ node.data.instanceBuf.destroy()
253
250
  node.data.instanceBuf = cobalt.device.createBuffer({
254
251
  size: INSTANCE_STRIDE * newCap,
255
252
  usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
256
- });
253
+ })
257
254
 
258
- node.data.instanceStaging = new ArrayBuffer(INSTANCE_STRIDE * newCap);
259
- node.data.instanceView = new DataView(node.data.instanceStaging);
260
- node.data.instanceCap = newCap;
255
+ node.data.instanceStaging = new ArrayBuffer(INSTANCE_STRIDE * newCap)
256
+ node.data.instanceView = new DataView(node.data.instanceStaging)
257
+ node.data.instanceCap = newCap
261
258
  }
262
259
 
263
-
264
- function draw (cobalt, node, commandEncoder) {
265
-
266
- const { device, context } = cobalt;
260
+ function draw(cobalt, node, commandEncoder) {
261
+ const { device, context } = cobalt
267
262
 
268
263
  const { instanceView, instanceBuf, instanceStaging, pipeline, bindGroup } = node.data
269
264
 
@@ -275,21 +270,26 @@ function draw (cobalt, node, commandEncoder) {
275
270
  viewRect.y = cobalt.viewport.position[1]
276
271
  viewRect.w = cobalt.viewport.width
277
272
  viewRect.h = cobalt.viewport.height
278
-
273
+
279
274
  node.data.visibleCount = 0
280
275
 
281
276
  for (const s of node.data.sprites) {
282
- const d = descs[s.spriteID];
283
- if (!d)
284
- continue;
277
+ const d = descs[s.spriteID]
278
+ if (!d) continue
285
279
 
286
280
  // avoid sprite viewport culling when drawing in screenspace mode (typically ui/hud layers)
287
281
  if (!node.options.isScreenSpace) {
288
- const sx = (d.FrameSize[0] * (s.sizeX) * s.scale[0]) * 0.5;
289
- const sy = (d.FrameSize[1] * (s.sizeY) * s.scale[1]) * 0.5;
290
- const rad = Math.hypot(sx, sy);
291
- const x = s.position[0], y = s.position[1];
292
- if (x + rad < viewRect.x || x - rad > viewRect.x + viewRect.w || y + rad < viewRect.y || y - rad > viewRect.y + viewRect.h)
282
+ const sx = d.FrameSize[0] * s.sizeX * s.scale[0] * 0.5
283
+ const sy = d.FrameSize[1] * s.sizeY * s.scale[1] * 0.5
284
+ const rad = Math.hypot(sx, sy)
285
+ const x = s.position[0],
286
+ y = s.position[1]
287
+ if (
288
+ x + rad < viewRect.x ||
289
+ x - rad > viewRect.x + viewRect.w ||
290
+ y + rad < viewRect.y ||
291
+ y - rad > viewRect.y + viewRect.h
292
+ )
293
293
  continue
294
294
  }
295
295
 
@@ -300,38 +300,44 @@ function draw (cobalt, node, commandEncoder) {
300
300
  ensureCapacity(cobalt, node, node.data.visibleCount)
301
301
 
302
302
  // Pack instances into staging buffer
303
- for (let i=0; i < node.data.visibleCount; i++){
304
- const base = i * INSTANCE_STRIDE;
305
- const s = node.data.visible[i];
306
- const tint = s.tint;
307
-
308
- instanceView.setFloat32(base + OFF_POS + 0, s.position[0], true);
309
- instanceView.setFloat32(base + OFF_POS + 4, s.position[1], true);
310
-
311
- instanceView.setFloat32(base + OFF_SIZE + 0, s.sizeX, true);
312
- instanceView.setFloat32(base + OFF_SIZE + 4, s.sizeY, true);
313
-
314
- instanceView.setFloat32(base + OFF_SCALE + 0, s.scale[0], true);
315
- instanceView.setFloat32(base + OFF_SCALE + 4, s.scale[1], true);
316
-
317
- instanceView.setFloat32(base + OFF_TINT + 0, tint[0], true);
318
- instanceView.setFloat32(base + OFF_TINT + 4, tint[1], true);
319
- instanceView.setFloat32(base + OFF_TINT + 8, tint[2], true);
320
- instanceView.setFloat32(base + OFF_TINT + 12, tint[3], true);
321
-
322
- instanceView.setUint32(base + OFF_SPRITEID, s.spriteID >>> 0, true);
323
-
324
- instanceView.setFloat32(base + OFF_OPACITY, s.opacity, true);
325
-
326
- instanceView.setFloat32(base + OFF_ROT, s.rotation, true);
303
+ for (let i = 0; i < node.data.visibleCount; i++) {
304
+ const base = i * INSTANCE_STRIDE
305
+ const s = node.data.visible[i]
306
+ const tint = s.tint
307
+
308
+ instanceView.setFloat32(base + OFF_POS + 0, s.position[0], true)
309
+ instanceView.setFloat32(base + OFF_POS + 4, s.position[1], true)
310
+
311
+ instanceView.setFloat32(base + OFF_SIZE + 0, s.sizeX, true)
312
+ instanceView.setFloat32(base + OFF_SIZE + 4, s.sizeY, true)
313
+
314
+ instanceView.setFloat32(base + OFF_SCALE + 0, s.scale[0], true)
315
+ instanceView.setFloat32(base + OFF_SCALE + 4, s.scale[1], true)
316
+
317
+ instanceView.setFloat32(base + OFF_TINT + 0, tint[0], true)
318
+ instanceView.setFloat32(base + OFF_TINT + 4, tint[1], true)
319
+ instanceView.setFloat32(base + OFF_TINT + 8, tint[2], true)
320
+ instanceView.setFloat32(base + OFF_TINT + 12, tint[3], true)
321
+
322
+ instanceView.setUint32(base + OFF_SPRITEID, s.spriteID >>> 0, true)
323
+
324
+ instanceView.setFloat32(base + OFF_OPACITY, s.opacity, true)
325
+
326
+ instanceView.setFloat32(base + OFF_ROT, s.rotation, true)
327
327
  }
328
328
 
329
- device.queue.writeBuffer(instanceBuf, 0, instanceStaging, 0, node.data.visibleCount * INSTANCE_STRIDE);
329
+ device.queue.writeBuffer(
330
+ instanceBuf,
331
+ 0,
332
+ instanceStaging,
333
+ 0,
334
+ node.data.visibleCount * INSTANCE_STRIDE,
335
+ )
330
336
 
331
337
  const loadOp = node.options.loadOp || 'load'
332
338
 
333
339
  const pass = commandEncoder.beginRenderPass({
334
- label: "sprite renderpass",
340
+ label: 'sprite renderpass',
335
341
  colorAttachments: [
336
342
  // color
337
343
  {
@@ -341,43 +347,39 @@ function draw (cobalt, node, commandEncoder) {
341
347
  storeOp: 'store',
342
348
  },
343
349
  ],
344
- });
345
-
346
- pass.setPipeline(pipeline);
347
- pass.setBindGroup(0, bindGroup);
348
- pass.setVertexBuffer(0, instanceBuf);
349
- if (node.data.visibleCount)
350
- pass.draw(4, node.data.visibleCount, 0, 0); // triangle strip, 4 verts per instance
351
- pass.end();
352
- }
353
-
350
+ })
354
351
 
355
- function _writeSpriteBuffer (cobalt, node) {
352
+ pass.setPipeline(pipeline)
353
+ pass.setBindGroup(0, bindGroup)
354
+ pass.setVertexBuffer(0, instanceBuf)
355
+ if (node.data.visibleCount) pass.draw(4, node.data.visibleCount, 0, 0) // triangle strip, 4 verts per instance
356
+ pass.end()
357
+ }
356
358
 
359
+ function _writeSpriteBuffer(cobalt, node) {
357
360
  const { device, viewport } = cobalt
358
361
 
359
362
  const GAME_WIDTH = viewport.width / viewport.zoom
360
363
  const GAME_HEIGHT = viewport.height / viewport.zoom
361
364
 
362
365
  // left right bottom top near far
363
- const projection = mat4.ortho(0, GAME_WIDTH, GAME_HEIGHT, 0, -10.0, 10.0)
366
+ const projection = mat4.ortho(0, GAME_WIDTH, GAME_HEIGHT, 0, -10.0, 10.0)
364
367
 
365
368
  // set 3d camera position
366
- if (!!node.options.isScreenSpace) {
369
+ if (node.options.isScreenSpace) {
367
370
  vec3.set(0, 0, 0, _tmpVec3)
368
- }
369
- else {
371
+ } else {
370
372
  // TODO: if this doesn't introduce jitter into the crossroads render, remove this disabled code entirely.
371
373
  //
372
374
  // I'm disabling the rounding because I think it fails in cases where units are not expressed in pixels
373
- // e.g., most physics engines operate on meters, not pixels, so we don't want to round to the nearest integer as that
375
+ // e.g., most physics engines operate on meters, not pixels, so we don't want to round to the nearest integer as that
374
376
  // probably isn't high enough resolution. That would mean the camera could be snapped by up to 0.5 meters
375
377
  // in that case. I think the better solution for expressing camera position in pixels is to round before calling
376
378
  // cobalt.setViewportPosition(...)
377
379
  //
378
380
  vec3.set(-round(viewport.position[0]), -round(viewport.position[1]), 0, _tmpVec3)
379
381
  //vec3.set(-viewport.position[0], -viewport.position[1], 0, _tmpVec3)
380
- }
382
+ }
381
383
 
382
384
  const view = mat4.translation(_tmpVec3)
383
385