@footgun/cobalt 0.6.14 → 0.7.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 (41) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/bundle.js +1318 -1304
  3. package/examples/01-primitives/index.html +1 -1
  4. package/examples/02-sprites/entity-sprite.js +10 -15
  5. package/examples/02-sprites/hdr.html +321 -0
  6. package/examples/02-sprites/index.html +21 -120
  7. package/examples/02-sprites/system-renderer.js +2 -2
  8. package/examples/03-tiles/index.html +87 -32
  9. package/examples/03-tiles/system-renderer.js +2 -2
  10. package/examples/04-overlay/index.html +178 -21
  11. package/examples/05-bloom/index.html +23 -23
  12. package/examples/05-bloom/system-renderer.js +2 -2
  13. package/examples/06-displacement/index.html +20 -112
  14. package/examples/06-displacement/system-renderer.js +2 -2
  15. package/examples/08-light/index.html +51 -123
  16. package/package.json +1 -1
  17. package/src/cobalt.js +8 -8
  18. package/src/sprite/public-api.js +57 -177
  19. package/src/sprite/sprite.js +301 -177
  20. package/src/sprite/sprite.wgsl +68 -87
  21. package/src/sprite-hdr/public-api.js +95 -0
  22. package/src/sprite-hdr/sprite.js +414 -0
  23. package/src/sprite-hdr/sprite.wgsl +101 -0
  24. package/src/{sprite → spritesheet}/create-sprite-quads.js +11 -11
  25. package/src/{sprite → spritesheet}/read-spritesheet.js +62 -28
  26. package/src/spritesheet/spritesheet.js +75 -0
  27. package/src/{tile → tile-hdr}/atlas.js +5 -3
  28. package/src/{tile → tile-hdr}/tile.js +15 -6
  29. package/examples/04-overlay/deps.js +0 -1
  30. package/src/overlay/constants.js +0 -1
  31. package/src/overlay/overlay.js +0 -343
  32. package/src/overlay/overlay.wgsl +0 -88
  33. package/src/sprite/constants.js +0 -1
  34. package/src/sprite/sorted-binary-insert.js +0 -45
  35. package/src/sprite/spritesheet.js +0 -215
  36. /package/examples/02-sprites/{Game.js → Global.js} +0 -0
  37. /package/examples/03-tiles/{Game.js → Global.js} +0 -0
  38. /package/examples/05-bloom/{Game.js → Global.js} +0 -0
  39. /package/examples/06-displacement/{Game.js → Global.js} +0 -0
  40. /package/examples/08-light/{Game.js → Global.js} +0 -0
  41. /package/src/{tile → tile-hdr}/tile.wgsl +0 -0
@@ -1,215 +1,95 @@
1
- import sortedBinaryInsert from './sorted-binary-insert.js'
2
- import uuid from '../uuid.js'
3
- import { FLOAT32S_PER_SPRITE } from './constants.js'
1
+ import uuid from '../uuid.js'
2
+ import { vec2, vec4 } from 'wgpu-matrix'
4
3
 
5
4
 
6
5
  // returns a unique identifier for the created sprite
7
- export function addSprite (cobalt, renderPass, name, position, scale, tint, opacity, rotation, zIndex) {
8
-
9
- const spritesheet = renderPass.refs.spritesheet.data.spritesheet
10
- renderPass = renderPass.data
11
-
12
- const spriteType = spritesheet.locations.indexOf(name)
13
-
14
- // find the place in our spriteData where this sprite belongs.
15
- const insertIdx = sortedBinaryInsert(zIndex, spriteType, renderPass)
16
-
17
- // shift down all the data in spriteData from insertIdx to spriteCount-1
18
- // https://stackoverflow.com/questions/35563529/how-to-copy-typedarray-into-another-typedarray
19
- const offset = (insertIdx + 1) * FLOAT32S_PER_SPRITE
20
- renderPass.spriteData.set(
21
- renderPass.spriteData.subarray(insertIdx * FLOAT32S_PER_SPRITE, renderPass.spriteCount * FLOAT32S_PER_SPRITE),
22
- offset
23
- )
24
-
25
- copySpriteDataToBuffer(renderPass, spritesheet, insertIdx, name, position, scale, tint, opacity, rotation, zIndex)
26
-
27
- // shift down all of the sprite indices
28
- for (const [ spriteId, idx ] of renderPass.spriteIndices)
29
- if (idx >= insertIdx)
30
- renderPass.spriteIndices.set(spriteId, idx+1)
31
-
32
- // store the location of this sprite's data in the renderPass's float32array so that we can
33
- // reference it later, when we need to remove or update this sprite component
34
- const spriteId = uuid()
35
-
36
- renderPass.spriteIndices.set(spriteId, insertIdx)
37
- renderPass.spriteCount++
38
- renderPass.dirty = true
39
-
40
- return spriteId
6
+ export function addSprite (cobalt, renderPass, name, position, scale, tint, opacity, rotation) {
7
+
8
+ const { idByName } = renderPass.refs.spritesheet.data
9
+
10
+ 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
41
22
  }
42
23
 
43
24
 
44
- export function removeSprite (cobalt, renderPass, spriteId) {
45
- renderPass = renderPass.data
46
- const removeIdx = renderPass.spriteIndices.get(spriteId)
47
-
48
- // shift up all of the sprites after the remove location by 1
49
- for (const [ spriteId, idx ] of renderPass.spriteIndices)
50
- if (idx > removeIdx)
51
- renderPass.spriteIndices.set(spriteId, idx-1)
52
-
53
- // shift up all the data in spriteData from removeIdx to spriteCount-1
54
- // https://stackoverflow.com/questions/35563529/how-to-copy-typedarray-into-another-typedarray
55
- let offset = removeIdx * FLOAT32S_PER_SPRITE
56
- renderPass.spriteData.set(
57
- renderPass.spriteData.subarray((removeIdx + 1) * FLOAT32S_PER_SPRITE, renderPass.spriteCount * FLOAT32S_PER_SPRITE),
58
- offset
59
- )
60
-
61
- renderPass.spriteIndices.delete(spriteId)
62
- renderPass.spriteCount--
63
- renderPass.dirty = true
25
+ export function removeSprite (cobalt, renderPass, id) {
26
+ for (let i=0; i < renderPass.data.sprites.length; i++) {
27
+ if (renderPass.data.sprites[i].id === id) {
28
+ renderPass.data.sprites.splice(i, 1)
29
+ return
30
+ }
31
+ }
64
32
  }
65
33
 
66
34
 
67
35
  // remove all sprites
68
36
  export function clear (cobalt, renderPass) {
69
- renderPass = renderPass.data
70
- renderPass.spriteIndices.clear()
71
- renderPass.spriteCount = 0
72
- renderPass.instancedDrawCallCount = 0
73
- renderPass.dirty = true
37
+ renderPass.data.sprites.length = 0
74
38
  }
75
39
 
76
40
 
77
- export function setSpriteName (cobalt, renderPass, spriteId, name, scale) {
78
- const spritesheet = renderPass.refs.spritesheet.data.spritesheet
79
- renderPass = renderPass.data
80
-
81
- const spriteType = spritesheet.locations.indexOf(name)
41
+ export function setSpriteName (cobalt, renderPass, id, name) {
42
+ const sprite = renderPass.data.sprites.find((s) => s.id === id)
82
43
 
83
- const SPRITE_WIDTH = spritesheet.spriteMeta[name].w
84
- const SPRITE_HEIGHT = spritesheet.spriteMeta[name].h
44
+ if (!sprite)
45
+ return
85
46
 
86
- const spriteIdx = renderPass.spriteIndices.get(spriteId)
87
- const offset = spriteIdx * FLOAT32S_PER_SPRITE
47
+ const { idByName } = renderPass.refs.spritesheet.data
88
48
 
89
- renderPass.spriteData[offset+2] = SPRITE_WIDTH * scale[0]
90
- renderPass.spriteData[offset+3] = SPRITE_HEIGHT * scale[1]
91
-
92
- // 12th float is order. lower bits 0-15 are spriteType, bits 16-23 are sprite Z index
93
- const zIndex = renderPass.spriteData[offset + 11] >> 16 & 0xFF
94
-
95
- // sortValue is used to sort the sprite by layer, then sprite type
96
- // zIndex 0-255 (8 bits)
97
- // spriteType 0-65,535 (16 bits)
98
- const sortValue = (zIndex << 16 & 0xFF0000) | (spriteType & 0xFFFF)
99
- renderPass.spriteData[offset+11] = sortValue
100
-
101
- renderPass.dirty = true
49
+ sprite.spriteID = idByName.get(name)
102
50
  }
103
51
 
104
52
 
105
- export function setSpritePosition (cobalt, renderPass, spriteId, position) {
106
- renderPass = renderPass.data
107
-
108
- const spriteIdx = renderPass.spriteIndices.get(spriteId)
109
- const offset = spriteIdx * FLOAT32S_PER_SPRITE
53
+ export function setSpritePosition (cobalt, renderPass, id, position) {
54
+ const sprite = renderPass.data.sprites.find((s) => s.id === id)
55
+ if (!sprite)
56
+ return
110
57
 
111
- renderPass.spriteData[offset] = position[0]
112
- renderPass.spriteData[offset+1] = position[1]
113
-
114
- renderPass.dirty = true
115
- }
116
-
117
-
118
- export function setSpriteTint (cobalt, renderPass, spriteId, tint) {
119
- renderPass = renderPass.data
120
-
121
- const spriteIdx = renderPass.spriteIndices.get(spriteId)
122
- const offset = spriteIdx * FLOAT32S_PER_SPRITE
123
-
124
- renderPass.spriteData[offset+4] = tint[0]
125
- renderPass.spriteData[offset+5] = tint[1]
126
- renderPass.spriteData[offset+6] = tint[2]
127
- renderPass.spriteData[offset+7] = tint[3]
128
-
129
- renderPass.dirty = true
58
+ vec2.copy(position, sprite.position)
130
59
  }
131
60
 
132
61
 
133
- export function setSpriteOpacity (cobalt, renderPass, spriteId, opacity) {
134
- renderPass = renderPass.data
135
-
136
- const spriteIdx = renderPass.spriteIndices.get(spriteId)
137
- const offset = spriteIdx * FLOAT32S_PER_SPRITE
138
-
139
- renderPass.spriteData[offset+8] = opacity
62
+ export function setSpriteTint (cobalt, renderPass, id, tint) {
63
+ const sprite = renderPass.data.sprites.find((s) => s.id === id)
64
+ if (!sprite)
65
+ return
140
66
 
141
- renderPass.dirty = true
67
+ vec4.copy(tint, sprite.tint)
142
68
  }
143
69
 
144
70
 
145
- export function setSpriteRotation (cobalt, renderPass, spriteId, rotation) {
146
- renderPass = renderPass.data
71
+ export function setSpriteOpacity (cobalt, renderPass, id, opacity) {
72
+ const sprite = renderPass.data.sprites.find((s) => s.id === id)
73
+ if (!sprite)
74
+ return
147
75
 
148
- const spriteIdx = renderPass.spriteIndices.get(spriteId)
149
- const offset = spriteIdx * FLOAT32S_PER_SPRITE
150
-
151
- renderPass.spriteData[offset+9] = rotation
152
- renderPass.dirty = true
76
+ sprite.opacity = opacity
153
77
  }
154
78
 
155
79
 
156
- export function setSpriteScale (cobalt, renderPass, spriteId, name, scale) {
157
- const spritesheet = renderPass.refs.spritesheet.data.spritesheet
158
- renderPass = renderPass.data
159
-
160
- const spriteIdx = renderPass.spriteIndices.get(spriteId)
161
- const offset = spriteIdx * FLOAT32S_PER_SPRITE
162
-
163
- const SPRITE_WIDTH = spritesheet.spriteMeta[name].w
164
- const SPRITE_HEIGHT = spritesheet.spriteMeta[name].h
165
-
166
- renderPass.spriteData[offset+2] = SPRITE_WIDTH * scale[0]
167
- renderPass.spriteData[offset+3] = SPRITE_HEIGHT * scale[1]
80
+ export function setSpriteRotation (cobalt, renderPass, id, rotation) {
81
+ const sprite = renderPass.data.sprites.find((s) => s.id === id)
82
+ if (!sprite)
83
+ return
168
84
 
169
- renderPass.dirty = true
85
+ sprite.rotation = rotation
170
86
  }
171
87
 
172
88
 
173
- export function setSprite (cobalt, renderPass, spriteId, name, position, scale, tint, opacity, rotation, zIndex) {
174
- const spritesheet = renderPass.refs.spritesheet.data.spritesheet
175
- renderPass = renderPass.data
176
-
177
- const spriteIdx = renderPass.spriteIndices.get(spriteId)
178
- copySpriteDataToBuffer(renderPass, spritesheet, spriteIdx, name, position, scale, tint, opacity, rotation, zIndex)
179
-
180
- renderPass.dirty = true
181
- }
182
-
89
+ export function setSpriteScale (cobalt, renderPass, id, scale) {
90
+ const sprite = renderPass.data.sprites.find((s) => s.id === id)
91
+ if (!sprite)
92
+ return
183
93
 
184
- // copy sprite data into the webgpu renderpass
185
- function copySpriteDataToBuffer (renderPass, spritesheet, insertIdx, name, position, scale, tint, opacity, rotation, zIndex) {
186
-
187
- if (!spritesheet.spriteMeta[name])
188
- throw new Error(`Sprite name ${name} could not be found in the spritesheet metaData`)
189
-
190
- const offset = insertIdx * FLOAT32S_PER_SPRITE
191
-
192
- const SPRITE_WIDTH = spritesheet.spriteMeta[name].w
193
- const SPRITE_HEIGHT = spritesheet.spriteMeta[name].h
194
-
195
- // sortValue is used to sort the sprite by layer, then sprite type
196
- // layer can be a value up to 255 (8 bits)
197
- // spriteType can be a value up to 65,535 (16 bits)
198
- const spriteType = spritesheet.locations.indexOf(name)
199
- const sortValue = (zIndex << 16 & 0xFF0000) | (spriteType & 0xFFFF)
200
-
201
- renderPass.spriteData[offset] = position[0]
202
- renderPass.spriteData[offset+1] = position[1]
203
- renderPass.spriteData[offset+2] = SPRITE_WIDTH * scale[0]
204
- renderPass.spriteData[offset+3] = SPRITE_HEIGHT * scale[1]
205
- renderPass.spriteData[offset+4] = tint[0]
206
- renderPass.spriteData[offset+5] = tint[1]
207
- renderPass.spriteData[offset+6] = tint[2]
208
- renderPass.spriteData[offset+7] = tint[3]
209
- renderPass.spriteData[offset+8] = opacity
210
- renderPass.spriteData[offset+9] = rotation
211
- // we used to set emissive intensity per-sprite, but now we use the alpha channel in the emissions texure,
212
- // which enables us to adjust emission strength on a per-pixel basis. Copying it into the sprite data is a leftover
213
- //renderPass.spriteData[offset+10] = emissiveIntensity
214
- renderPass.spriteData[offset+11] = sortValue
94
+ vec2.copy(scale, sprite.scale)
215
95
  }