@footgun/cobalt 0.8.0 → 0.9.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.
@@ -9,6 +9,8 @@ import publicAPI from './public-api.js'
9
9
 
10
10
  // temporary variables, allocated once to avoid garbage collection
11
11
  const _tmpVec3 = vec3.create(0, 0, 0)
12
+ const _projection = mat4.identity()
13
+ const _view = mat4.identity()
12
14
 
13
15
  export default {
14
16
  type: 'cobalt:primitives',
@@ -34,11 +36,11 @@ export default {
34
36
 
35
37
  onResize: function (cobalt, node) {
36
38
  // do whatever you need when the dimensions of the renderer change (resize textures, etc.)
37
- _writeMatricesBuffer(cobalt, node)
39
+ writeCameraBuffer(cobalt, node)
38
40
  },
39
41
 
40
42
  onViewportPosition: function (cobalt, node) {
41
- _writeMatricesBuffer(cobalt, node)
43
+ writeCameraBuffer(cobalt, node)
42
44
  },
43
45
 
44
46
  // optional
@@ -236,21 +238,21 @@ function destroy(node) {
236
238
  node.data.transforms.length = 0
237
239
  }
238
240
 
239
- function _writeMatricesBuffer(cobalt, node) {
241
+ function writeCameraBuffer(cobalt, node) {
240
242
  const { device } = cobalt
241
243
 
242
244
  const GAME_WIDTH = cobalt.viewport.width / cobalt.viewport.zoom
243
245
  const GAME_HEIGHT = cobalt.viewport.height / cobalt.viewport.zoom
244
246
 
245
- // left right bottom top near far
246
- const projection = mat4.ortho(0, GAME_WIDTH, GAME_HEIGHT, 0, -10.0, 10.0)
247
+ // left right bottom top near far
248
+ mat4.ortho(0, GAME_WIDTH, GAME_HEIGHT, 0, -10.0, 10.0, _projection)
247
249
 
248
250
  // TODO: 1.0 must be subtracted from both x and y values otherwise everything get shifted down and to the right
249
251
  // when rendered. This is true for both sdl and browser backed rendering. I don't understand why though!!
250
252
  vec3.set(-cobalt.viewport.position[0] - 1.0, -cobalt.viewport.position[1] - 1.0, 0, _tmpVec3)
251
253
 
252
- const view = mat4.translation(_tmpVec3)
254
+ mat4.translation(_tmpVec3, _view)
253
255
 
254
- device.queue.writeBuffer(node.data.uniformBuffer, 0, view.buffer)
255
- device.queue.writeBuffer(node.data.uniformBuffer, 64, projection.buffer)
256
+ device.queue.writeBuffer(node.data.uniformBuffer, 0, _view.buffer)
257
+ device.queue.writeBuffer(node.data.uniformBuffer, 64, _projection.buffer)
256
258
  }
@@ -35,46 +35,73 @@ export function clear(cobalt, renderPass) {
35
35
  }
36
36
 
37
37
  export function setSpriteName(cobalt, renderPass, id, name) {
38
- const sprite = renderPass.data.sprites.find((s) => s.id === id)
38
+ const sprites = renderPass.data.sprites
39
+ const len = sprites.length
39
40
 
40
- if (!sprite) return
41
-
42
- const { idByName } = renderPass.refs.spritesheet.data
43
-
44
- sprite.spriteID = idByName.get(name)
41
+ for (let i = 0; i < len; i++) {
42
+ if (sprites[i].id === id) {
43
+ sprites[i].spriteID = renderPass.refs.spritesheet.data.idByName.get(name)
44
+ return
45
+ }
46
+ }
45
47
  }
46
48
 
47
49
  export function setSpritePosition(cobalt, renderPass, id, position) {
48
- const sprite = renderPass.data.sprites.find((s) => s.id === id)
49
- if (!sprite) return
50
+ const sprites = renderPass.data.sprites
51
+ const len = sprites.length
50
52
 
51
- vec2.copy(position, sprite.position)
53
+ for (let i = 0; i < len; i++) {
54
+ if (sprites[i].id === id) {
55
+ vec2.copy(position, sprites[i].position)
56
+ return
57
+ }
58
+ }
52
59
  }
53
60
 
54
61
  export function setSpriteTint(cobalt, renderPass, id, tint) {
55
- const sprite = renderPass.data.sprites.find((s) => s.id === id)
56
- if (!sprite) return
62
+ const sprites = renderPass.data.sprites
63
+ const len = sprites.length
57
64
 
58
- vec4.copy(tint, sprite.tint)
65
+ for (let i = 0; i < len; i++) {
66
+ if (sprites[i].id === id) {
67
+ vec4.copy(tint, sprites[i].tint)
68
+ return
69
+ }
70
+ }
59
71
  }
60
72
 
61
73
  export function setSpriteOpacity(cobalt, renderPass, id, opacity) {
62
- const sprite = renderPass.data.sprites.find((s) => s.id === id)
63
- if (!sprite) return
74
+ const sprites = renderPass.data.sprites
75
+ const len = sprites.length
64
76
 
65
- sprite.opacity = opacity
77
+ for (let i = 0; i < len; i++) {
78
+ if (sprites[i].id === id) {
79
+ sprites[i].opacity = opacity
80
+ return
81
+ }
82
+ }
66
83
  }
67
84
 
68
85
  export function setSpriteRotation(cobalt, renderPass, id, rotation) {
69
- const sprite = renderPass.data.sprites.find((s) => s.id === id)
70
- if (!sprite) return
86
+ const sprites = renderPass.data.sprites
87
+ const len = sprites.length
71
88
 
72
- sprite.rotation = rotation
89
+ for (let i = 0; i < len; i++) {
90
+ if (sprites[i].id === id) {
91
+ sprites[i].rotation = rotation
92
+ return
93
+ }
94
+ }
73
95
  }
74
96
 
75
97
  export function setSpriteScale(cobalt, renderPass, id, scale) {
76
- const sprite = renderPass.data.sprites.find((s) => s.id === id)
77
- if (!sprite) return
98
+ const sprites = renderPass.data.sprites
99
+ const len = sprites.length
78
100
 
79
- vec2.copy(scale, sprite.scale)
101
+ for (let i = 0; i < len; i++) {
102
+ if (sprites[i].id === id) {
103
+ vec2.copy(scale, sprites[i].scale)
104
+ return
105
+ }
106
+ }
80
107
  }
@@ -6,6 +6,8 @@ import spriteWGSL from './sprite.wgsl'
6
6
 
7
7
  // temporary variables, allocated once to avoid garbage collection
8
8
  const _tmpVec3 = vec3.create(0, 0, 0)
9
+ const _projection = mat4.identity()
10
+ const _view = mat4.identity()
9
11
 
10
12
  // Packed instance layout: 48 bytes (aligned for vec4 fetch)
11
13
  const INSTANCE_STRIDE = 64
@@ -71,11 +73,11 @@ export default {
71
73
  },
72
74
 
73
75
  onResize: function (cobalt, node) {
74
- _writeSpriteBuffer(cobalt, node)
76
+ writeCameraBuffer(cobalt, node)
75
77
  },
76
78
 
77
79
  onViewportPosition: function (cobalt, node) {
78
- _writeSpriteBuffer(cobalt, node)
80
+ writeCameraBuffer(cobalt, node)
79
81
  },
80
82
 
81
83
  // optional
@@ -356,14 +358,14 @@ function draw(cobalt, node, commandEncoder) {
356
358
  pass.end()
357
359
  }
358
360
 
359
- function _writeSpriteBuffer(cobalt, node) {
361
+ function writeCameraBuffer(cobalt, node) {
360
362
  const { device, viewport } = cobalt
361
363
 
362
364
  const GAME_WIDTH = viewport.width / viewport.zoom
363
365
  const GAME_HEIGHT = viewport.height / viewport.zoom
364
366
 
365
- // left right bottom top near far
366
- const projection = mat4.ortho(0, GAME_WIDTH, GAME_HEIGHT, 0, -10.0, 10.0)
367
+ // left right bottom top near far
368
+ mat4.ortho(0, GAME_WIDTH, GAME_HEIGHT, 0, -10.0, 10.0, _projection)
367
369
 
368
370
  // set 3d camera position
369
371
  if (node.options.isScreenSpace) {
@@ -381,8 +383,8 @@ function _writeSpriteBuffer(cobalt, node) {
381
383
  //vec3.set(-viewport.position[0], -viewport.position[1], 0, _tmpVec3)
382
384
  }
383
385
 
384
- const view = mat4.translation(_tmpVec3)
386
+ mat4.translation(_tmpVec3, _view)
385
387
 
386
- device.queue.writeBuffer(node.data.uniformBuffer, 0, view.buffer)
387
- device.queue.writeBuffer(node.data.uniformBuffer, 64, projection.buffer)
388
+ device.queue.writeBuffer(node.data.uniformBuffer, 0, _view.buffer)
389
+ device.queue.writeBuffer(node.data.uniformBuffer, 64, _projection.buffer)
388
390
  }
@@ -5,6 +5,8 @@ import spriteWGSL from './sprite.wgsl'
5
5
 
6
6
  // temporary variables, allocated once to avoid garbage collection
7
7
  const _tmpVec3 = vec3.create(0, 0, 0)
8
+ const _projection = mat4.identity()
9
+ const _view = mat4.identity()
8
10
 
9
11
  // Packed instance layout: 48 bytes (aligned for vec4 fetch)
10
12
  const INSTANCE_STRIDE = 64
@@ -76,11 +78,11 @@ export default {
76
78
  },
77
79
 
78
80
  onResize: function (cobalt, node) {
79
- _writeSpriteBuffer(cobalt, node)
81
+ writeCameraBuffer(cobalt, node)
80
82
  },
81
83
 
82
84
  onViewportPosition: function (cobalt, node) {
83
- _writeSpriteBuffer(cobalt, node)
85
+ writeCameraBuffer(cobalt, node)
84
86
  },
85
87
 
86
88
  // optional
@@ -383,14 +385,14 @@ function draw(cobalt, node, commandEncoder) {
383
385
  pass.end()
384
386
  }
385
387
 
386
- function _writeSpriteBuffer(cobalt, node) {
388
+ function writeCameraBuffer(cobalt, node) {
387
389
  const { device, viewport } = cobalt
388
390
 
389
391
  const GAME_WIDTH = viewport.width / viewport.zoom
390
392
  const GAME_HEIGHT = viewport.height / viewport.zoom
391
393
 
392
- // left right bottom top near far
393
- const projection = mat4.ortho(0, GAME_WIDTH, GAME_HEIGHT, 0, -10.0, 10.0)
394
+ // left right bottom top near far
395
+ mat4.ortho(0, GAME_WIDTH, GAME_HEIGHT, 0, -10.0, 10.0, _projection)
394
396
 
395
397
  // set 3d camera position
396
398
  if (node.options.isScreenSpace) {
@@ -408,8 +410,8 @@ function _writeSpriteBuffer(cobalt, node) {
408
410
  //vec3.set(-viewport.position[0], -viewport.position[1], 0, _tmpVec3)
409
411
  }
410
412
 
411
- const view = mat4.translation(_tmpVec3)
413
+ mat4.translation(_tmpVec3, _view)
412
414
 
413
- device.queue.writeBuffer(node.data.uniformBuffer, 0, view.buffer)
414
- device.queue.writeBuffer(node.data.uniformBuffer, 64, projection.buffer)
415
+ device.queue.writeBuffer(node.data.uniformBuffer, 0, _view.buffer)
416
+ device.queue.writeBuffer(node.data.uniformBuffer, 64, _projection.buffer)
415
417
  }
@@ -1,44 +0,0 @@
1
- /// <reference types="@webgpu/types"/>
2
-
3
- type DisplacementParameters = {
4
- readonly offsetX: number;
5
- readonly offsetY: number;
6
- readonly scale: number;
7
- };
8
-
9
- type Parameters = {
10
- readonly device: GPUDevice;
11
- readonly initialParameters: DisplacementParameters;
12
- };
13
-
14
- class DisplacementParametersBuffer {
15
- private readonly device: GPUDevice;
16
-
17
- public readonly bufferGpu: GPUBuffer;
18
- private needsUpdate: boolean = true;
19
-
20
- public constructor(params: Parameters) {
21
- this.device = params.device;
22
-
23
- this.bufferGpu = this.device.createBuffer({
24
- label: "DisplacementParametersBuffer buffer",
25
- size: 16,
26
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
27
- });
28
-
29
- this.setParameters(params.initialParameters);
30
- }
31
-
32
- public setParameters(params: DisplacementParameters): void {
33
- this.device.queue.writeBuffer(this.bufferGpu, 0, new Float32Array([params.offsetX, params.offsetY, params.scale]));
34
- }
35
-
36
- public destroy(): void {
37
- this.bufferGpu.destroy();
38
- }
39
- }
40
-
41
- export {
42
- DisplacementParametersBuffer
43
- };
44
-
@@ -1,221 +0,0 @@
1
- /// <reference types="@webgpu/types"/>
2
-
3
- import displacementWGSL from './displacement.wgsl'
4
- import * as wgpuMatrix from "wgpu-matrix";
5
- import { TrianglesBuffer } from "./triangles-buffer";
6
-
7
-
8
- type Viewport = {
9
- readonly width: number;
10
- readonly height: number;
11
- readonly zoom: number;
12
- readonly position: [number, number];
13
- };
14
-
15
- type Parameters = {
16
- readonly device: GPUDevice;
17
-
18
- readonly width: number;
19
- readonly height: number;
20
-
21
- readonly blurFactor: number;
22
-
23
- readonly trianglesBuffer: TrianglesBuffer;
24
- };
25
-
26
- type TextureWithView = {
27
- readonly texture: GPUTexture;
28
- readonly view: GPUTextureView;
29
- };
30
-
31
- class DisplacementTexture {
32
- private readonly device: GPUDevice;
33
- private readonly format: GPUTextureFormat = "r8unorm";
34
- private readonly downsizeFactor: number;
35
- private readonly multisample: number;
36
-
37
- private textureSimple: TextureWithView;
38
- private textureMultisampled: TextureWithView | null = null;
39
-
40
- private readonly renderPipeline: GPURenderPipeline;
41
- private readonly bindgroup: GPUBindGroup;
42
- private readonly uniformsBuffer: GPUBuffer;
43
-
44
- private readonly trianglesBuffer: TrianglesBuffer;
45
-
46
- public constructor(params: Parameters) {
47
- this.device = params.device;
48
- this.downsizeFactor = params.blurFactor;
49
- this.multisample = this.downsizeFactor > 1 ? 4 : 1;
50
-
51
- [this.textureSimple, this.textureMultisampled] = this.createTextures(params.width, params.height);
52
-
53
- this.trianglesBuffer = params.trianglesBuffer;
54
-
55
- const shaderModule = this.device.createShaderModule({
56
- label: "DisplacementTexture shader module",
57
- code: displacementWGSL,
58
-
59
- });
60
-
61
- this.renderPipeline = this.device.createRenderPipeline({
62
- label: "DisplacementTexture renderpipeline",
63
- layout: "auto",
64
- vertex: {
65
- module: shaderModule,
66
- entryPoint: "main_vertex",
67
- buffers: [
68
- {
69
- attributes: [
70
- {
71
- shaderLocation: 0,
72
- offset: 0,
73
- format: "float32x2",
74
- },
75
- ],
76
- arrayStride: 2 * Float32Array.BYTES_PER_ELEMENT,
77
- stepMode: "vertex",
78
- },
79
- ],
80
- },
81
- fragment: {
82
- module: shaderModule,
83
- entryPoint: "main_fragment",
84
- targets: [{
85
- format: this.format,
86
- }],
87
- },
88
- primitive: {
89
- cullMode: "none",
90
- topology: "triangle-list",
91
- },
92
- multisample: {
93
- count: this.multisample,
94
- },
95
- });
96
-
97
- this.uniformsBuffer = this.device.createBuffer({
98
- label: "DisplacementTexture uniforms buffer",
99
- size: 64,
100
- usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
101
- });
102
-
103
- this.bindgroup = this.device.createBindGroup({
104
- label: "DisplacementTexture bindgroup",
105
- layout: this.renderPipeline.getBindGroupLayout(0),
106
- entries: [
107
- {
108
- binding: 0,
109
- resource: { buffer: this.uniformsBuffer },
110
- },
111
- ],
112
- });
113
- }
114
-
115
- public update(commandEncoder: GPUCommandEncoder): void {
116
- const targetTexture = this.textureMultisampled ?? this.textureSimple;
117
-
118
- const textureRenderpassColorAttachment: GPURenderPassColorAttachment = {
119
- view: targetTexture.view,
120
- clearValue: [0, 0, 0, 1],
121
- loadOp: "clear",
122
- storeOp: "store",
123
- };
124
- if (this.textureMultisampled) {
125
- textureRenderpassColorAttachment.resolveTarget = this.textureSimple.view;
126
- }
127
-
128
- const renderpassEncoder = commandEncoder.beginRenderPass({
129
- label: "DisplacementTexture render to texture renderpass",
130
- colorAttachments: [textureRenderpassColorAttachment],
131
- });
132
-
133
- const [textureWidth, textureHeight] = [targetTexture.texture.width, targetTexture.texture.height];
134
- renderpassEncoder.setViewport(0, 0, textureWidth, textureHeight, 0, 1);
135
- renderpassEncoder.setScissorRect(0, 0, textureWidth, textureHeight);
136
- renderpassEncoder.setPipeline(this.renderPipeline);
137
- renderpassEncoder.setBindGroup(0, this.bindgroup);
138
- renderpassEncoder.setVertexBuffer(0, this.trianglesBuffer.bufferGpu);
139
- renderpassEncoder.draw(3 * this.trianglesBuffer.spriteCount);
140
- renderpassEncoder.end();
141
- };
142
-
143
- public resize(width: number, height: number): void {
144
- this.textureSimple.texture.destroy();
145
- this.textureMultisampled?.texture.destroy();
146
-
147
- [this.textureSimple, this.textureMultisampled] = this.createTextures(width, height);
148
- }
149
-
150
- public setViewport(viewport: Viewport): void {
151
- const scaling = [1, 1, 1];
152
- const rotation = 0;
153
- const translation = [1, 1, 0];
154
-
155
- const modelMatrix = wgpuMatrix.mat4.identity();
156
- wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.scaling(scaling), modelMatrix, modelMatrix);
157
- wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.rotationZ(rotation), modelMatrix, modelMatrix);
158
- wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.translation(translation), modelMatrix, modelMatrix);
159
-
160
- const viewMatrix = wgpuMatrix.mat4.translation([-viewport.position[0], -viewport.position[1], 0]);
161
-
162
- const gameWidth = viewport.width / viewport.zoom
163
- const gameHeight = viewport.height / viewport.zoom
164
- // left right bottom top near far
165
- const projectionMatrix = wgpuMatrix.mat4.ortho(0, gameWidth, gameHeight, 0, -10.0, 10.0)
166
-
167
- const mvpMatrix = wgpuMatrix.mat4.identity();
168
- wgpuMatrix.mat4.multiply(viewMatrix, modelMatrix, mvpMatrix);
169
- wgpuMatrix.mat4.multiply(projectionMatrix, mvpMatrix, mvpMatrix);
170
-
171
- this.device.queue.writeBuffer(this.uniformsBuffer, 0, mvpMatrix);
172
- }
173
-
174
- public getView(): GPUTextureView {
175
- return this.textureSimple.view;
176
- }
177
-
178
- public destroy(): void {
179
- this.textureSimple.texture.destroy();
180
- this.textureMultisampled?.texture.destroy();
181
- this.uniformsBuffer.destroy();
182
- }
183
-
184
- private createTextures(width: number, height: number): [TextureWithView, TextureWithView | null] {
185
- const texture = this.device.createTexture({
186
- label: "DisplacementTexture texture",
187
- size: [
188
- Math.ceil(width / this.downsizeFactor),
189
- Math.ceil(height / this.downsizeFactor),
190
- ],
191
- format: this.format,
192
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
193
- });
194
- const textureSimple = {
195
- texture,
196
- view: texture.createView({ label: "DisplacementTexture texture view" }),
197
- };
198
-
199
- let textureMultisampled: TextureWithView | null = null;
200
- if (this.multisample > 1) {
201
- const textureMulti = this.device.createTexture({
202
- label: "DisplacementTexture texture multisampled",
203
- size: [texture.width, texture.height],
204
- format: texture.format,
205
- usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
206
- sampleCount: this.multisample,
207
- });
208
- textureMultisampled = {
209
- texture: textureMulti,
210
- view: textureMulti.createView({ label: "DisplacementTexture texture multisampled view" }),
211
- };
212
- }
213
-
214
- return [textureSimple, textureMultisampled];
215
- }
216
- }
217
-
218
- export {
219
- DisplacementTexture
220
- };
221
-
@@ -1,23 +0,0 @@
1
- type Point = [number, number];
2
-
3
- type Light = {
4
- readonly position: Point; // center of the light
5
- readonly radius: number; // radius of the light
6
- readonly color: [number, number, number]; // color (normalized)
7
- readonly intensity: number; // intensity at the center
8
- readonly attenuationLinear: number; // describes how the intensity declines with distance
9
- readonly attenuationExp: number; // describes how the intensity declines with distance
10
- };
11
- /* The light intensity is computed as follow:
12
- intensity
13
- ----------------------------------------------------- * cos(x * pi/2)
14
- 1 + attenuationLinear * x + attenuationExp * (x * x)
15
-
16
- where "x" is the normalized distance to the light position
17
- */
18
-
19
-
20
- export {
21
- type Light,
22
- type Point,
23
- };