@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,88 +1,3 @@
1
- // take a texturepacker json hash export and convert it into a Float32Array
2
- // copied into the renderer's vertex buffer
3
- //
4
- // @return Float32Array vertices (interleaved positions and uvs)
5
- /*
6
- export default function readSpriteSheet (spritesheetJson) {
7
-
8
- // a sprite is a quad (2 triangles) so it has 6 vertices
9
- // each vertex has 4 float32 (interleaved vec2 position, vec2 uv)
10
- const spriteFloatCount = 4 * 6
11
-
12
- // each key in the spritesheet is a unique sprite type
13
- const spriteCount = Object.keys(spritesheetJson.frames).length
14
-
15
- const vertices = new Float32Array(spriteCount * spriteFloatCount)
16
-
17
- const locations = [ ]
18
-
19
- const spriteMeta = { }
20
-
21
- let i = 0
22
-
23
- for (const frameName in spritesheetJson.frames) {
24
- const frame = spritesheetJson.frames[frameName]
25
-
26
- locations.push(frameName)
27
-
28
- spriteMeta[frameName] = frame.sourceSize
29
-
30
- // iterate over each sprite and fill it's position and u,v coords in the output
31
-
32
- // calculate normalized vertex coordinates, accounting for trimmed space
33
- const minX = -0.5 + (frame.spriteSourceSize.x / frame.sourceSize.w)
34
- const minY = -0.5 + (frame.spriteSourceSize.y / frame.sourceSize.h)
35
-
36
- const maxX = -0.5 + ((frame.spriteSourceSize.x + frame.spriteSourceSize.w) / frame.sourceSize.w)
37
- const maxY = -0.5 + ((frame.spriteSourceSize.y + frame.spriteSourceSize.h) / frame.sourceSize.h)
38
-
39
- const p0 = [ minX, minY ]
40
- const p1 = [ minX, maxY ]
41
- const p2 = [ maxX, maxY ]
42
- const p3 = [ maxX, minY ]
43
-
44
-
45
- // calculate uvs
46
- // u,v coordinates specify top left as 0,0 bottom right as 1,1
47
- const minU = 0.0 + (frame.frame.x / spritesheetJson.meta.size.w)
48
- const minV = 0.0 + (frame.frame.y / spritesheetJson.meta.size.h)
49
- const maxU = 0.0 + ((frame.frame.x + frame.frame.w) / spritesheetJson.meta.size.w)
50
- const maxV = 0.0 + ((frame.frame.y + frame.frame.h) / spritesheetJson.meta.size.h)
51
-
52
- const uv0 = [ minU, minV ]
53
- const uv1 = [ minU, maxV ]
54
- const uv2 = [ maxU, maxV ]
55
- const uv3 = [ maxU, minV ]
56
-
57
-
58
- // quad triangles are [ p0, p1, p2 ] , [ p0, p2, p3 ]
59
- // vertex data is interleaved; a single vertex has a vec2 position followed immediately by vec2 uv
60
- vertices.set(p0, i)
61
- vertices.set(uv0, i + 2)
62
-
63
- vertices.set(p1, i + 4)
64
- vertices.set(uv1, i + 6)
65
-
66
- vertices.set(p2, i + 8)
67
- vertices.set(uv2, i + 10)
68
-
69
- vertices.set(p0, i + 12)
70
- vertices.set(uv0, i + 14)
71
-
72
- vertices.set(p2, i + 16)
73
- vertices.set(uv2, i + 18)
74
-
75
- vertices.set(p3, i + 20)
76
- vertices.set(uv3, i + 22)
77
-
78
- i += spriteFloatCount
79
- }
80
-
81
- return { spriteMeta, locations, vertices }
82
- }
83
- */
84
-
85
-
86
1
  /**
87
2
  * ------------------------------ TexturePacker (no rotation) ------------------------------
88
3
  * Accepts the "Hash" JSON format from TexturePacker. Assumes rotated=false.
@@ -97,41 +12,35 @@ export default function readSpriteSheet (spritesheetJson) {
97
12
  "sourceSize": {"w":32,"h":32}
98
13
  },
99
14
  */
100
- export default function buildSpriteTableFromTexturePacker (doc) {
101
- const atlasW = doc.meta.size.w;
102
- const atlasH = doc.meta.size.h;
103
- const names = Object.keys(doc.frames).sort();
104
- const descs = new Array(names.length);
105
-
106
- for (let i=0; i<names.length; i++) {
107
- const fr = doc.frames[names[i]];
108
-
109
- const fx = fr.frame.x, fy = fr.frame.y, fw = fr.frame.w, fh = fr.frame.h;
110
- const offX = fx / atlasW, offY = fy / atlasH;
111
- const spanX = fw / atlasW, spanY = fh / atlasH;
112
- const sw = fr.sourceSize.w, sh = fr.sourceSize.h;
113
- const ox = fr.spriteSourceSize.x, oy = fr.spriteSourceSize.y;
114
- const cx = (ox + fw*0.5) - (sw*0.5);
115
- const cy = (oy + fh*0.5) - (sh*0.5);
15
+ export default function buildSpriteTableFromTexturePacker(doc) {
16
+ const atlasW = doc.meta.size.w
17
+ const atlasH = doc.meta.size.h
18
+ const names = Object.keys(doc.frames).sort()
19
+ const descs = new Array(names.length)
20
+
21
+ for (let i = 0; i < names.length; i++) {
22
+ const fr = doc.frames[names[i]]
23
+
24
+ const fx = fr.frame.x,
25
+ fy = fr.frame.y,
26
+ fw = fr.frame.w,
27
+ fh = fr.frame.h
28
+ const offX = fx / atlasW,
29
+ offY = fy / atlasH
30
+ const spanX = fw / atlasW,
31
+ spanY = fh / atlasH
32
+ const sw = fr.sourceSize.w,
33
+ sh = fr.sourceSize.h
34
+ const ox = fr.spriteSourceSize.x,
35
+ oy = fr.spriteSourceSize.y
36
+ const cx = ox + fw * 0.5 - sw * 0.5
37
+ const cy = oy + fh * 0.5 - sh * 0.5
116
38
  descs[i] = {
117
39
  UvOrigin: [offX, offY],
118
40
  UvSpan: [spanX, spanY],
119
- FrameSize:[fw, fh],
120
- CenterOffset:[cx, cy],
121
- };
41
+ FrameSize: [fw, fh],
42
+ CenterOffset: [cx, cy],
43
+ }
122
44
  }
123
- return { descs, names };
45
+ return { descs, names }
124
46
  }
125
-
126
-
127
- /*
128
- texturepacker frame structure:
129
- "f2.png":
130
- {
131
- "frame": {"x":15,"y":1,"w":10,"h":15},
132
- "rotated": false,
133
- "trimmed": true,
134
- "spriteSourceSize": {"x":22,"y":17,"w":10,"h":15},
135
- "sourceSize": {"w":32,"h":32}
136
- },
137
- */
@@ -1,35 +1,33 @@
1
1
  import createTextureFromBuffer from '../create-texture-from-buffer.js'
2
- import createTextureFromUrl from '../create-texture-from-url.js'
3
- import readSpriteSheet from './read-spritesheet.js'
4
-
2
+ import createTextureFromUrl from '../create-texture-from-url.js'
3
+ import readSpriteSheet from './read-spritesheet.js'
5
4
 
6
5
  // shared spritesheet resource, used by each sprite render node
7
6
 
8
7
  export default {
9
8
  type: 'cobalt:spritesheet',
10
- refs: [ ],
9
+ refs: [],
11
10
 
12
11
  // @params Object cobalt renderer world object
13
12
  // @params Object options optional data passed when initing this node
14
- onInit: async function (cobalt, options={}) {
13
+ onInit: async function (cobalt, options = {}) {
15
14
  return init(cobalt, options)
16
15
  },
17
16
 
18
- onRun: function (cobalt, node, webGpuCommandEncoder) { },
17
+ onRun: function (cobalt, node, webGpuCommandEncoder) {},
19
18
 
20
19
  onDestroy: function (cobalt, node) {
21
20
  // any cleanup for your node should go here (releasing textures, etc.)
22
21
  destroy(node)
23
22
  },
24
23
 
25
- onResize: function (cobalt, node) { },
24
+ onResize: function (cobalt, node) {},
26
25
 
27
- onViewportPosition: function (cobalt, node) { },
26
+ onViewportPosition: function (cobalt, node) {},
28
27
  }
29
28
 
30
-
31
29
  // configure the common settings for sprite rendering
32
- async function init (cobalt, node) {
30
+ async function init(cobalt, node) {
33
31
  const { canvas, device } = cobalt
34
32
 
35
33
  let spritesheet, colorTexture, emissiveTexture
@@ -42,23 +40,42 @@ async function init (cobalt, node) {
42
40
  spritesheet = await spritesheet.json()
43
41
  spritesheet = readSpriteSheet(spritesheet)
44
42
 
45
- colorTexture = await createTextureFromUrl(cobalt, 'sprite', node.options.colorTextureUrl, format)
46
- emissiveTexture = await createTextureFromUrl(cobalt, 'emissive sprite', node.options.emissiveTextureUrl, format)
47
-
43
+ colorTexture = await createTextureFromUrl(
44
+ cobalt,
45
+ 'sprite',
46
+ node.options.colorTextureUrl,
47
+ format,
48
+ )
49
+ emissiveTexture = await createTextureFromUrl(
50
+ cobalt,
51
+ 'emissive sprite',
52
+ node.options.emissiveTextureUrl,
53
+ format,
54
+ )
55
+
48
56
  // for some reason this needs to be done _after_ creating the material, or the rendering will be blurry
49
57
  canvas.style.imageRendering = 'pixelated'
50
- }
51
- else {
58
+ } else {
52
59
  // sdl + gpu path
53
60
  spritesheet = readSpriteSheet(node.options.spriteSheetJson)
54
61
 
55
- colorTexture = await createTextureFromBuffer(cobalt, 'sprite', node.options.colorTexture, format)
56
- emissiveTexture = await createTextureFromBuffer(cobalt, 'emissive sprite', node.options.emissiveTexture, format)
62
+ colorTexture = await createTextureFromBuffer(
63
+ cobalt,
64
+ 'sprite',
65
+ node.options.colorTexture,
66
+ format,
67
+ )
68
+ emissiveTexture = await createTextureFromBuffer(
69
+ cobalt,
70
+ 'emissive sprite',
71
+ node.options.emissiveTexture,
72
+ format,
73
+ )
57
74
  }
58
75
 
59
76
  // Map sprite name → ID
60
- const idByName = new Map(spritesheet.names.map((n,i)=>[n,i]))
61
-
77
+ const idByName = new Map(spritesheet.names.map((n, i) => [n, i]))
78
+
62
79
  return {
63
80
  colorTexture,
64
81
  emissiveTexture,
@@ -67,8 +84,7 @@ async function init (cobalt, node) {
67
84
  }
68
85
  }
69
86
 
70
-
71
- function destroy (node) {
87
+ function destroy(node) {
72
88
  node.data.quads.buffer.destroy()
73
89
  node.data.colorTexture.buffer.destroy()
74
90
  node.data.emissiveTexture.texture.destroy()
@@ -1,21 +1,19 @@
1
+ import round from 'round-half-up-symmetric'
1
2
  import createTextureFromBuffer from '../create-texture-from-buffer.js'
2
- import createTextureFromUrl from '../create-texture-from-url.js'
3
- import getPreferredFormat from '../get-preferred-format.js'
4
- import tileWGSL from './tile.wgsl'
5
- import round from 'round-half-up-symmetric'
6
-
3
+ import createTextureFromUrl from '../create-texture-from-url.js'
4
+ import getPreferredFormat from '../get-preferred-format.js'
5
+ import tileWGSL from './tile.wgsl'
7
6
 
8
7
  const _buf = new Float32Array(8) //(136) // tile instance data stored in a UBO
9
8
 
10
-
11
9
  // shared tile atlas resource, used by each tile render node
12
10
  export default {
13
11
  type: 'cobalt:tileAtlas',
14
- refs: [ ],
12
+ refs: [],
15
13
 
16
14
  // @params Object cobalt renderer world object
17
15
  // @params Object options optional data passed when initing this node
18
- onInit: async function (cobalt, options={}) {
16
+ onInit: async function (cobalt, options = {}) {
19
17
  return init(cobalt, options)
20
18
  },
21
19
 
@@ -25,7 +23,7 @@ export default {
25
23
 
26
24
  onDestroy: function (cobalt, node) {
27
25
  // any cleanup for your node should go here (releasing textures, etc.)
28
- destroy(data)
26
+ destroy(node)
29
27
  },
30
28
 
31
29
  onResize: function (cobalt, node) {
@@ -38,8 +36,7 @@ export default {
38
36
  },
39
37
  }
40
38
 
41
-
42
- async function init (cobalt, nodeData) {
39
+ async function init(cobalt, nodeData) {
43
40
  const { canvas, device } = cobalt
44
41
 
45
42
  const format = nodeData.options.format || 'rgba8unorm'
@@ -48,16 +45,25 @@ async function init (cobalt, nodeData) {
48
45
 
49
46
  if (canvas) {
50
47
  // browser (canvas) path
51
- atlasMaterial = await createTextureFromUrl(cobalt, 'tile atlas', nodeData.options.textureUrl, format)
52
- }
53
- else {
48
+ atlasMaterial = await createTextureFromUrl(
49
+ cobalt,
50
+ 'tile atlas',
51
+ nodeData.options.textureUrl,
52
+ format,
53
+ )
54
+ } else {
54
55
  // sdl + gpu path
55
- atlasMaterial = await createTextureFromBuffer(cobalt, 'tile atlas', nodeData.options.texture, format)
56
+ atlasMaterial = await createTextureFromBuffer(
57
+ cobalt,
58
+ 'tile atlas',
59
+ nodeData.options.texture,
60
+ format,
61
+ )
56
62
  }
57
63
 
58
64
  const uniformBuffer = device.createBuffer({
59
65
  size: 32, //32 + (16 * 32), // in bytes. 32 for common data + (32 max tile layers * 16 bytes per tile layer)
60
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST
66
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
61
67
  })
62
68
 
63
69
  const atlasBindGroupLayout = device.createBindGroupLayout({
@@ -65,18 +71,18 @@ async function init (cobalt, nodeData) {
65
71
  {
66
72
  binding: 0,
67
73
  visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
68
- buffer: { }
74
+ buffer: {},
69
75
  },
70
76
  {
71
77
  binding: 1,
72
78
  visibility: GPUShaderStage.FRAGMENT,
73
- texture: { }
79
+ texture: {},
74
80
  },
75
81
  {
76
82
  binding: 2,
77
83
  visibility: GPUShaderStage.FRAGMENT,
78
- sampler: { }
79
- }
84
+ sampler: {},
85
+ },
80
86
  ],
81
87
  })
82
88
 
@@ -86,18 +92,18 @@ async function init (cobalt, nodeData) {
86
92
  {
87
93
  binding: 0,
88
94
  resource: {
89
- buffer: uniformBuffer
90
- }
95
+ buffer: uniformBuffer,
96
+ },
91
97
  },
92
98
  {
93
99
  binding: 1,
94
- resource: atlasMaterial.view
100
+ resource: atlasMaterial.view,
95
101
  },
96
102
  {
97
103
  binding: 2,
98
- resource: atlasMaterial.sampler
99
- }
100
- ]
104
+ resource: atlasMaterial.sampler,
105
+ },
106
+ ],
101
107
  })
102
108
 
103
109
  const tileBindGroupLayout = device.createBindGroupLayout({
@@ -105,38 +111,38 @@ async function init (cobalt, nodeData) {
105
111
  {
106
112
  binding: 0,
107
113
  visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
108
- buffer: { }
114
+ buffer: {},
109
115
  },
110
116
  {
111
117
  binding: 1,
112
118
  visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT,
113
- texture: { }
119
+ texture: {},
114
120
  },
115
121
  {
116
122
  binding: 2,
117
123
  visibility: GPUShaderStage.FRAGMENT,
118
- sampler: { }
124
+ sampler: {},
119
125
  },
120
126
  ],
121
127
  })
122
128
 
123
129
  const pipelineLayout = device.createPipelineLayout({
124
- bindGroupLayouts: [ tileBindGroupLayout, atlasBindGroupLayout ]
130
+ bindGroupLayouts: [tileBindGroupLayout, atlasBindGroupLayout],
125
131
  })
126
132
 
127
133
  const pipeline = device.createRenderPipeline({
128
134
  label: 'tileatlas',
129
135
  vertex: {
130
136
  module: device.createShaderModule({
131
- code: tileWGSL
137
+ code: tileWGSL,
132
138
  }),
133
139
  entryPoint: 'vs_main',
134
- buffers: [ ]
140
+ buffers: [],
135
141
  },
136
142
 
137
143
  fragment: {
138
144
  module: device.createShaderModule({
139
- code: tileWGSL
145
+ code: tileWGSL,
140
146
  }),
141
147
  entryPoint: 'fs_main',
142
148
  targets: [
@@ -149,24 +155,24 @@ async function init (cobalt, nodeData) {
149
155
  },
150
156
  alpha: {
151
157
  srcFactor: 'zero',
152
- dstFactor: 'one'
153
- }
154
- }
155
- }
156
- ]
158
+ dstFactor: 'one',
159
+ },
160
+ },
161
+ },
162
+ ],
157
163
  },
158
164
 
159
165
  primitive: {
160
- topology: 'triangle-list'
166
+ topology: 'triangle-list',
161
167
  },
162
168
 
163
- layout: pipelineLayout
169
+ layout: pipelineLayout,
164
170
  })
165
171
 
166
172
  return {
167
173
  pipeline,
168
174
  uniformBuffer,
169
- atlasBindGroup, // tile atlas texture, transform UBO
175
+ atlasBindGroup, // tile atlas texture, transform UBO
170
176
  atlasMaterial,
171
177
 
172
178
  tileBindGroupLayout,
@@ -176,14 +182,12 @@ async function init (cobalt, nodeData) {
176
182
  }
177
183
  }
178
184
 
179
-
180
- function destroy (data) {
185
+ function destroy(data) {
181
186
  data.atlasMaterial.texture.destroy()
182
187
  data.atlasMaterial.texture = undefined
183
188
  }
184
189
 
185
-
186
- function _writeTileBuffer (c, nodeData) {
190
+ function _writeTileBuffer(c, nodeData) {
187
191
  // c.viewport.position is the top left visible corner of the level
188
192
  _buf[0] = round(c.viewport.position[0])
189
193
  _buf[1] = round(c.viewport.position[1])
@@ -194,14 +198,14 @@ function _writeTileBuffer (c, nodeData) {
194
198
  const GAME_WIDTH = c.viewport.width / c.viewport.zoom
195
199
  const GAME_HEIGHT = c.viewport.height / c.viewport.zoom
196
200
 
197
- _buf[2] = GAME_WIDTH / tileScale // viewportSize[0]
198
- _buf[3] = GAME_HEIGHT / tileScale // viewportSize[1]
201
+ _buf[2] = GAME_WIDTH / tileScale // viewportSize[0]
202
+ _buf[3] = GAME_HEIGHT / tileScale // viewportSize[1]
199
203
 
200
- _buf[4] = 1 / tile.atlasMaterial.texture.width // inverseAtlasTextureSize[0]
204
+ _buf[4] = 1 / tile.atlasMaterial.texture.width // inverseAtlasTextureSize[0]
201
205
  _buf[5] = 1 / tile.atlasMaterial.texture.height // inverseAtlasTextureSize[1]
202
206
 
203
207
  _buf[6] = tileSize
204
- _buf[7] = 1.0 / tileSize // inverseTileSize
205
-
208
+ _buf[7] = 1.0 / tileSize // inverseTileSize
209
+
206
210
  c.device.queue.writeBuffer(tile.uniformBuffer, 0, _buf, 0, 8)
207
211
  }