@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.
- package/CHANGELOG.md +9 -0
- package/bundle.js +4 -4
- package/package.json +1 -1
- package/src/cobalt.js +1 -0
- package/src/displacement/{displacement-composition.ts → displacement-composition.js} +21 -57
- package/src/displacement/displacement-parameters-buffer.js +21 -0
- package/src/displacement/displacement-texture.js +174 -0
- package/src/displacement/{triangles-buffer.ts → triangles-buffer.js} +18 -44
- package/src/light/{lights-buffer.ts → lights-buffer.js} +13 -36
- package/src/light/{lights-renderer.ts → lights-renderer.js} +24 -72
- package/src/light/texture/{lights-texture-initializer.ts → lights-texture-initializer.js} +11 -27
- package/src/light/texture/{lights-texture-mask.ts → lights-texture-mask.js} +36 -87
- package/src/light/texture/{lights-texture.ts → lights-texture.js} +16 -52
- package/src/light/{viewport.ts → viewport.js} +11 -34
- package/src/primitives/primitives.js +10 -8
- package/src/sprite/public-api.js +48 -21
- package/src/sprite/sprite.js +10 -8
- package/src/sprite-hdr/sprite.js +10 -8
- package/src/displacement/displacement-parameters-buffer.ts +0 -44
- package/src/displacement/displacement-texture.ts +0 -221
- package/src/light/types.ts +0 -23
package/package.json
CHANGED
package/src/cobalt.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export { default as createTexture } from './create-texture.js'
|
|
2
2
|
export { default as createTextureFromBuffer } from './create-texture-from-buffer.js'
|
|
3
3
|
export { default as createTextureFromUrl } from './create-texture-from-url.js'
|
|
4
|
+
export { default as getPreferredFormat } from './get-preferred-format.js'
|
|
4
5
|
|
|
5
6
|
// built-in run nodes
|
|
6
7
|
import bloomNode from './bloom/bloom.js'
|
|
@@ -1,50 +1,27 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import { DisplacementParametersBuffer } from "./displacement-parameters-buffer";
|
|
4
|
-
import compositionWGSL from "./composition.wgsl"
|
|
5
|
-
|
|
6
|
-
type Parameters = {
|
|
7
|
-
readonly device: GPUDevice;
|
|
8
|
-
readonly targetFormat: GPUTextureFormat;
|
|
9
|
-
|
|
10
|
-
readonly colorTextureView: GPUTextureView;
|
|
11
|
-
readonly noiseMapTextureView: GPUTextureView;
|
|
12
|
-
readonly displacementTextureView: GPUTextureView;
|
|
13
|
-
|
|
14
|
-
readonly displacementParametersBuffer: DisplacementParametersBuffer;
|
|
15
|
-
};
|
|
1
|
+
import compositionWGSL from "./composition.wgsl";
|
|
16
2
|
|
|
17
3
|
class DisplacementComposition {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
private colorTextureView: GPUTextureView;
|
|
30
|
-
private noiseMapTextureView: GPUTextureView;
|
|
31
|
-
private displacementTextureView: GPUTextureView;
|
|
32
|
-
|
|
33
|
-
public constructor(params: Parameters) {
|
|
4
|
+
device;
|
|
5
|
+
targetFormat;
|
|
6
|
+
renderPipeline;
|
|
7
|
+
colorSampler;
|
|
8
|
+
noiseSampler;
|
|
9
|
+
displacementParametersBuffer;
|
|
10
|
+
renderBundle = null;
|
|
11
|
+
colorTextureView;
|
|
12
|
+
noiseMapTextureView;
|
|
13
|
+
displacementTextureView;
|
|
14
|
+
constructor(params) {
|
|
34
15
|
this.device = params.device;
|
|
35
|
-
|
|
36
16
|
this.targetFormat = params.targetFormat;
|
|
37
17
|
this.colorTextureView = params.colorTextureView;
|
|
38
18
|
this.noiseMapTextureView = params.noiseMapTextureView;
|
|
39
19
|
this.displacementTextureView = params.displacementTextureView;
|
|
40
|
-
|
|
41
20
|
this.displacementParametersBuffer = params.displacementParametersBuffer;
|
|
42
|
-
|
|
43
21
|
const shaderModule = this.device.createShaderModule({
|
|
44
22
|
label: "DisplacementComposition shader module",
|
|
45
23
|
code: compositionWGSL,
|
|
46
24
|
});
|
|
47
|
-
|
|
48
25
|
this.renderPipeline = this.device.createRenderPipeline({
|
|
49
26
|
label: "DisplacementComposition renderpipeline",
|
|
50
27
|
layout: "auto",
|
|
@@ -56,15 +33,14 @@ class DisplacementComposition {
|
|
|
56
33
|
module: shaderModule,
|
|
57
34
|
entryPoint: "main_fragment",
|
|
58
35
|
targets: [{
|
|
59
|
-
|
|
60
|
-
|
|
36
|
+
format: params.targetFormat,
|
|
37
|
+
}],
|
|
61
38
|
},
|
|
62
39
|
primitive: {
|
|
63
40
|
cullMode: "none",
|
|
64
41
|
topology: "triangle-strip",
|
|
65
42
|
},
|
|
66
43
|
});
|
|
67
|
-
|
|
68
44
|
this.noiseSampler = this.device.createSampler({
|
|
69
45
|
label: "DisplacementComposition noisesampler",
|
|
70
46
|
addressModeU: "repeat",
|
|
@@ -74,7 +50,6 @@ class DisplacementComposition {
|
|
|
74
50
|
minFilter: "linear",
|
|
75
51
|
mipmapFilter: "linear",
|
|
76
52
|
});
|
|
77
|
-
|
|
78
53
|
this.colorSampler = this.device.createSampler({
|
|
79
54
|
label: "DisplacementComposition colorSampler",
|
|
80
55
|
addressModeU: "clamp-to-edge",
|
|
@@ -85,34 +60,28 @@ class DisplacementComposition {
|
|
|
85
60
|
mipmapFilter: "linear",
|
|
86
61
|
});
|
|
87
62
|
}
|
|
88
|
-
|
|
89
|
-
public getRenderBundle(): GPURenderBundle {
|
|
63
|
+
getRenderBundle() {
|
|
90
64
|
if (!this.renderBundle) {
|
|
91
65
|
this.renderBundle = this.buildRenderBundle();
|
|
92
66
|
}
|
|
93
67
|
return this.renderBundle;
|
|
94
68
|
}
|
|
95
|
-
|
|
96
|
-
public destroy(): void {
|
|
69
|
+
destroy() {
|
|
97
70
|
// nothing to do
|
|
98
71
|
}
|
|
99
|
-
|
|
100
|
-
public setColorTextureView(textureView: GPUTextureView): void {
|
|
72
|
+
setColorTextureView(textureView) {
|
|
101
73
|
this.colorTextureView = textureView;
|
|
102
74
|
this.renderBundle = null;
|
|
103
75
|
}
|
|
104
|
-
|
|
105
|
-
public setNoiseMapTextureView(textureView: GPUTextureView): void {
|
|
76
|
+
setNoiseMapTextureView(textureView) {
|
|
106
77
|
this.noiseMapTextureView = textureView;
|
|
107
78
|
this.renderBundle = null;
|
|
108
79
|
}
|
|
109
|
-
|
|
110
|
-
public setDisplacementTextureView(textureView: GPUTextureView): void {
|
|
80
|
+
setDisplacementTextureView(textureView) {
|
|
111
81
|
this.displacementTextureView = textureView;
|
|
112
82
|
this.renderBundle = null;
|
|
113
83
|
}
|
|
114
|
-
|
|
115
|
-
private buildRenderBundle(): GPURenderBundle {
|
|
84
|
+
buildRenderBundle() {
|
|
116
85
|
const bindgroup = this.device.createBindGroup({
|
|
117
86
|
label: "DisplacementComposition bindgroup 0",
|
|
118
87
|
layout: this.renderPipeline.getBindGroupLayout(0),
|
|
@@ -143,7 +112,6 @@ class DisplacementComposition {
|
|
|
143
112
|
},
|
|
144
113
|
],
|
|
145
114
|
});
|
|
146
|
-
|
|
147
115
|
const renderBundleEncoder = this.device.createRenderBundleEncoder({
|
|
148
116
|
label: "DisplacementComposition renderbundle encoder",
|
|
149
117
|
colorFormats: [this.targetFormat],
|
|
@@ -154,8 +122,4 @@ class DisplacementComposition {
|
|
|
154
122
|
return renderBundleEncoder.finish({ label: "DisplacementComposition renderbundle" });
|
|
155
123
|
}
|
|
156
124
|
}
|
|
157
|
-
|
|
158
|
-
export {
|
|
159
|
-
DisplacementComposition
|
|
160
|
-
};
|
|
161
|
-
|
|
125
|
+
export { DisplacementComposition };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
class DisplacementParametersBuffer {
|
|
2
|
+
device;
|
|
3
|
+
bufferGpu;
|
|
4
|
+
needsUpdate = true;
|
|
5
|
+
constructor(params) {
|
|
6
|
+
this.device = params.device;
|
|
7
|
+
this.bufferGpu = this.device.createBuffer({
|
|
8
|
+
label: "DisplacementParametersBuffer buffer",
|
|
9
|
+
size: 16,
|
|
10
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
11
|
+
});
|
|
12
|
+
this.setParameters(params.initialParameters);
|
|
13
|
+
}
|
|
14
|
+
setParameters(params) {
|
|
15
|
+
this.device.queue.writeBuffer(this.bufferGpu, 0, new Float32Array([params.offsetX, params.offsetY, params.scale]));
|
|
16
|
+
}
|
|
17
|
+
destroy() {
|
|
18
|
+
this.bufferGpu.destroy();
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
export { DisplacementParametersBuffer };
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import displacementWGSL from './displacement.wgsl'
|
|
2
|
+
import * as wgpuMatrix from 'wgpu-matrix'
|
|
3
|
+
|
|
4
|
+
class DisplacementTexture {
|
|
5
|
+
device
|
|
6
|
+
format = 'r8unorm'
|
|
7
|
+
downsizeFactor
|
|
8
|
+
multisample
|
|
9
|
+
textureSimple
|
|
10
|
+
textureMultisampled = null
|
|
11
|
+
renderPipeline
|
|
12
|
+
bindgroup
|
|
13
|
+
uniformsBuffer
|
|
14
|
+
trianglesBuffer
|
|
15
|
+
constructor(params) {
|
|
16
|
+
this.device = params.device
|
|
17
|
+
this.downsizeFactor = params.blurFactor
|
|
18
|
+
this.multisample = this.downsizeFactor > 1 ? 4 : 1
|
|
19
|
+
;[this.textureSimple, this.textureMultisampled] = this.createTextures(
|
|
20
|
+
params.width,
|
|
21
|
+
params.height,
|
|
22
|
+
)
|
|
23
|
+
this.trianglesBuffer = params.trianglesBuffer
|
|
24
|
+
const shaderModule = this.device.createShaderModule({
|
|
25
|
+
label: 'DisplacementTexture shader module',
|
|
26
|
+
code: displacementWGSL,
|
|
27
|
+
})
|
|
28
|
+
this.renderPipeline = this.device.createRenderPipeline({
|
|
29
|
+
label: 'DisplacementTexture renderpipeline',
|
|
30
|
+
layout: 'auto',
|
|
31
|
+
vertex: {
|
|
32
|
+
module: shaderModule,
|
|
33
|
+
entryPoint: 'main_vertex',
|
|
34
|
+
buffers: [
|
|
35
|
+
{
|
|
36
|
+
attributes: [
|
|
37
|
+
{
|
|
38
|
+
shaderLocation: 0,
|
|
39
|
+
offset: 0,
|
|
40
|
+
format: 'float32x2',
|
|
41
|
+
},
|
|
42
|
+
],
|
|
43
|
+
arrayStride: 2 * Float32Array.BYTES_PER_ELEMENT,
|
|
44
|
+
stepMode: 'vertex',
|
|
45
|
+
},
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
fragment: {
|
|
49
|
+
module: shaderModule,
|
|
50
|
+
entryPoint: 'main_fragment',
|
|
51
|
+
targets: [
|
|
52
|
+
{
|
|
53
|
+
format: this.format,
|
|
54
|
+
},
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
primitive: {
|
|
58
|
+
cullMode: 'none',
|
|
59
|
+
topology: 'triangle-list',
|
|
60
|
+
},
|
|
61
|
+
multisample: {
|
|
62
|
+
count: this.multisample,
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
this.uniformsBuffer = this.device.createBuffer({
|
|
66
|
+
label: 'DisplacementTexture uniforms buffer',
|
|
67
|
+
size: 64,
|
|
68
|
+
usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
|
|
69
|
+
})
|
|
70
|
+
this.bindgroup = this.device.createBindGroup({
|
|
71
|
+
label: 'DisplacementTexture bindgroup',
|
|
72
|
+
layout: this.renderPipeline.getBindGroupLayout(0),
|
|
73
|
+
entries: [
|
|
74
|
+
{
|
|
75
|
+
binding: 0,
|
|
76
|
+
resource: { buffer: this.uniformsBuffer },
|
|
77
|
+
},
|
|
78
|
+
],
|
|
79
|
+
})
|
|
80
|
+
}
|
|
81
|
+
update(commandEncoder) {
|
|
82
|
+
const targetTexture = this.textureMultisampled ?? this.textureSimple
|
|
83
|
+
const textureRenderpassColorAttachment = {
|
|
84
|
+
view: targetTexture.view,
|
|
85
|
+
clearValue: [0, 0, 0, 1],
|
|
86
|
+
loadOp: 'clear',
|
|
87
|
+
storeOp: 'store',
|
|
88
|
+
}
|
|
89
|
+
if (this.textureMultisampled) {
|
|
90
|
+
textureRenderpassColorAttachment.resolveTarget = this.textureSimple.view
|
|
91
|
+
}
|
|
92
|
+
const renderpassEncoder = commandEncoder.beginRenderPass({
|
|
93
|
+
label: 'DisplacementTexture render to texture renderpass',
|
|
94
|
+
colorAttachments: [textureRenderpassColorAttachment],
|
|
95
|
+
})
|
|
96
|
+
const [textureWidth, textureHeight] = [
|
|
97
|
+
targetTexture.texture.width,
|
|
98
|
+
targetTexture.texture.height,
|
|
99
|
+
]
|
|
100
|
+
renderpassEncoder.setViewport(0, 0, textureWidth, textureHeight, 0, 1)
|
|
101
|
+
renderpassEncoder.setScissorRect(0, 0, textureWidth, textureHeight)
|
|
102
|
+
renderpassEncoder.setPipeline(this.renderPipeline)
|
|
103
|
+
renderpassEncoder.setBindGroup(0, this.bindgroup)
|
|
104
|
+
renderpassEncoder.setVertexBuffer(0, this.trianglesBuffer.bufferGpu)
|
|
105
|
+
renderpassEncoder.draw(3 * this.trianglesBuffer.spriteCount)
|
|
106
|
+
renderpassEncoder.end()
|
|
107
|
+
}
|
|
108
|
+
resize(width, height) {
|
|
109
|
+
this.textureSimple.texture.destroy()
|
|
110
|
+
this.textureMultisampled?.texture.destroy()
|
|
111
|
+
;[this.textureSimple, this.textureMultisampled] = this.createTextures(width, height)
|
|
112
|
+
}
|
|
113
|
+
setViewport(viewport) {
|
|
114
|
+
// TODO: don't re-create these arrays and matrices every tick
|
|
115
|
+
const scaling = [1, 1, 1]
|
|
116
|
+
const rotation = 0
|
|
117
|
+
const translation = [1, 1, 0]
|
|
118
|
+
const modelMatrix = wgpuMatrix.mat4.identity()
|
|
119
|
+
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.scaling(scaling), modelMatrix, modelMatrix)
|
|
120
|
+
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.rotationZ(rotation), modelMatrix, modelMatrix)
|
|
121
|
+
wgpuMatrix.mat4.multiply(wgpuMatrix.mat4.translation(translation), modelMatrix, modelMatrix)
|
|
122
|
+
const viewMatrix = wgpuMatrix.mat4.translation([
|
|
123
|
+
-viewport.position[0],
|
|
124
|
+
-viewport.position[1],
|
|
125
|
+
0,
|
|
126
|
+
])
|
|
127
|
+
const gameWidth = viewport.width / viewport.zoom
|
|
128
|
+
const gameHeight = viewport.height / viewport.zoom
|
|
129
|
+
// left right bottom top near far
|
|
130
|
+
const projectionMatrix = wgpuMatrix.mat4.ortho(0, gameWidth, gameHeight, 0, -10.0, 10.0)
|
|
131
|
+
const mvpMatrix = wgpuMatrix.mat4.identity()
|
|
132
|
+
wgpuMatrix.mat4.multiply(viewMatrix, modelMatrix, mvpMatrix)
|
|
133
|
+
wgpuMatrix.mat4.multiply(projectionMatrix, mvpMatrix, mvpMatrix)
|
|
134
|
+
this.device.queue.writeBuffer(this.uniformsBuffer, 0, mvpMatrix)
|
|
135
|
+
}
|
|
136
|
+
getView() {
|
|
137
|
+
return this.textureSimple.view
|
|
138
|
+
}
|
|
139
|
+
destroy() {
|
|
140
|
+
this.textureSimple.texture.destroy()
|
|
141
|
+
this.textureMultisampled?.texture.destroy()
|
|
142
|
+
this.uniformsBuffer.destroy()
|
|
143
|
+
}
|
|
144
|
+
createTextures(width, height) {
|
|
145
|
+
const texture = this.device.createTexture({
|
|
146
|
+
label: 'DisplacementTexture texture',
|
|
147
|
+
size: [Math.ceil(width / this.downsizeFactor), Math.ceil(height / this.downsizeFactor)],
|
|
148
|
+
format: this.format,
|
|
149
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
150
|
+
})
|
|
151
|
+
const textureSimple = {
|
|
152
|
+
texture,
|
|
153
|
+
view: texture.createView({ label: 'DisplacementTexture texture view' }),
|
|
154
|
+
}
|
|
155
|
+
let textureMultisampled = null
|
|
156
|
+
if (this.multisample > 1) {
|
|
157
|
+
const textureMulti = this.device.createTexture({
|
|
158
|
+
label: 'DisplacementTexture texture multisampled',
|
|
159
|
+
size: [texture.width, texture.height],
|
|
160
|
+
format: texture.format,
|
|
161
|
+
usage: GPUTextureUsage.TEXTURE_BINDING | GPUTextureUsage.RENDER_ATTACHMENT,
|
|
162
|
+
sampleCount: this.multisample,
|
|
163
|
+
})
|
|
164
|
+
textureMultisampled = {
|
|
165
|
+
texture: textureMulti,
|
|
166
|
+
view: textureMulti.createView({
|
|
167
|
+
label: 'DisplacementTexture texture multisampled view',
|
|
168
|
+
}),
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return [textureSimple, textureMultisampled]
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
export { DisplacementTexture }
|
|
@@ -1,74 +1,53 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
import uuid from '../uuid.js'
|
|
4
|
-
|
|
5
|
-
type Parameters = {
|
|
6
|
-
readonly device: GPUDevice;
|
|
7
|
-
readonly maxSpriteCount: number;
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
type Point = [number, number];
|
|
11
|
-
type TriangleVertices = [Point, Point, Point];
|
|
12
|
-
type TriangleData = [number, number, number, number, number, number];
|
|
1
|
+
import uuid from '../uuid.js';
|
|
13
2
|
|
|
14
3
|
class TrianglesBuffer {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
private readonly sprites: Map<number, TriangleData> = new Map();
|
|
22
|
-
public get spriteCount(): number {
|
|
4
|
+
device;
|
|
5
|
+
floatsPerSprite = 6; // vec2(translate) + vec2(scale) + rotation + opacity
|
|
6
|
+
bufferGpu;
|
|
7
|
+
bufferNeedsUpdate = false;
|
|
8
|
+
sprites = new Map();
|
|
9
|
+
get spriteCount() {
|
|
23
10
|
return this.sprites.size;
|
|
24
11
|
}
|
|
25
|
-
|
|
26
|
-
public constructor(params: Parameters) {
|
|
12
|
+
constructor(params) {
|
|
27
13
|
this.device = params.device;
|
|
28
|
-
|
|
29
14
|
this.bufferGpu = this.device.createBuffer({
|
|
30
15
|
size: params.maxSpriteCount * this.floatsPerSprite * Float32Array.BYTES_PER_ELEMENT,
|
|
31
16
|
usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST,
|
|
32
17
|
});
|
|
33
18
|
}
|
|
34
|
-
|
|
35
|
-
public destroy(): void {
|
|
19
|
+
destroy() {
|
|
36
20
|
this.bufferGpu.destroy;
|
|
37
21
|
}
|
|
38
|
-
|
|
39
|
-
public update(): void {
|
|
22
|
+
update() {
|
|
40
23
|
if (this.bufferNeedsUpdate) {
|
|
41
|
-
const bufferData
|
|
24
|
+
const bufferData = [];
|
|
42
25
|
for (const sprite of this.sprites.values()) {
|
|
43
26
|
bufferData.push(...sprite);
|
|
44
|
-
}
|
|
27
|
+
}
|
|
28
|
+
;
|
|
45
29
|
const buffer = new Float32Array(bufferData);
|
|
46
30
|
this.device.queue.writeBuffer(this.bufferGpu, 0, buffer);
|
|
47
31
|
}
|
|
48
32
|
}
|
|
49
|
-
|
|
50
|
-
public addTriangle(triangleVertices: TriangleVertices): number {
|
|
33
|
+
addTriangle(triangleVertices) {
|
|
51
34
|
const triangleId = uuid();
|
|
52
35
|
if (this.sprites.has(triangleId)) {
|
|
53
36
|
throw new Error(`Duplicate triangle "${triangleId}".`);
|
|
54
37
|
}
|
|
55
|
-
|
|
56
38
|
const triangleData = this.buildTriangleData(triangleVertices);
|
|
57
39
|
this.sprites.set(triangleId, triangleData);
|
|
58
40
|
this.bufferNeedsUpdate = true;
|
|
59
|
-
|
|
60
41
|
return triangleId;
|
|
61
42
|
}
|
|
62
|
-
|
|
63
|
-
public removeTriangle(triangleId: number): void {
|
|
43
|
+
removeTriangle(triangleId) {
|
|
64
44
|
if (!this.sprites.has(triangleId)) {
|
|
65
45
|
throw new Error(`Unknown triangle "${triangleId}".`);
|
|
66
46
|
}
|
|
67
47
|
this.sprites.delete(triangleId);
|
|
68
48
|
this.bufferNeedsUpdate = true;
|
|
69
49
|
}
|
|
70
|
-
|
|
71
|
-
public setTriangle(triangleId: number, triangleVertices: TriangleVertices): void {
|
|
50
|
+
setTriangle(triangleId, triangleVertices) {
|
|
72
51
|
if (!this.sprites.has(triangleId)) {
|
|
73
52
|
throw new Error(`Unknown triangle "${triangleId}".`);
|
|
74
53
|
}
|
|
@@ -76,8 +55,7 @@ class TrianglesBuffer {
|
|
|
76
55
|
this.sprites.set(triangleId, triangleData);
|
|
77
56
|
this.bufferNeedsUpdate = true;
|
|
78
57
|
}
|
|
79
|
-
|
|
80
|
-
private buildTriangleData(triangleVertices: TriangleVertices): TriangleData {
|
|
58
|
+
buildTriangleData(triangleVertices) {
|
|
81
59
|
return [
|
|
82
60
|
triangleVertices[0][0],
|
|
83
61
|
triangleVertices[0][1],
|
|
@@ -88,8 +66,4 @@ class TrianglesBuffer {
|
|
|
88
66
|
];
|
|
89
67
|
}
|
|
90
68
|
}
|
|
91
|
-
|
|
92
|
-
export {
|
|
93
|
-
TrianglesBuffer
|
|
94
|
-
};
|
|
95
|
-
|
|
69
|
+
export { TrianglesBuffer };
|
|
@@ -1,9 +1,5 @@
|
|
|
1
|
-
/// <reference types="@webgpu/types"/>
|
|
2
|
-
|
|
3
|
-
import { type Light } from "./types";
|
|
4
|
-
|
|
5
1
|
class LightsBuffer {
|
|
6
|
-
|
|
2
|
+
static structs = {
|
|
7
3
|
definition: `
|
|
8
4
|
struct Light { // align(16) size(48)
|
|
9
5
|
color: vec3<f32>, // offset(0) align(16) size(12)
|
|
@@ -28,24 +24,16 @@ struct LightsBuffer { // align(16)
|
|
|
28
24
|
lights: { offset: 16, stride: 48 },
|
|
29
25
|
},
|
|
30
26
|
};
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
private readonly buffer: {
|
|
38
|
-
readonly bufferCpu: ArrayBuffer;
|
|
39
|
-
readonly bufferGpu: GPUBuffer;
|
|
40
|
-
};
|
|
41
|
-
public get gpuBuffer(): GPUBuffer {
|
|
27
|
+
device;
|
|
28
|
+
maxLightsCount;
|
|
29
|
+
currentLightsCount = 0;
|
|
30
|
+
buffer;
|
|
31
|
+
get gpuBuffer() {
|
|
42
32
|
return this.buffer.bufferGpu;
|
|
43
33
|
}
|
|
44
|
-
|
|
45
|
-
public constructor(device: GPUDevice, maxLightsCount: number) {
|
|
34
|
+
constructor(device, maxLightsCount) {
|
|
46
35
|
this.device = device;
|
|
47
36
|
this.maxLightsCount = maxLightsCount;
|
|
48
|
-
|
|
49
37
|
const bufferCpu = new ArrayBuffer(LightsBuffer.computeBufferBytesLength(maxLightsCount));
|
|
50
38
|
const bufferGpu = device.createBuffer({
|
|
51
39
|
label: "LightsBuffer buffer",
|
|
@@ -53,19 +41,15 @@ struct LightsBuffer { // align(16)
|
|
|
53
41
|
usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_DST | GPUBufferUsage.VERTEX,
|
|
54
42
|
});
|
|
55
43
|
this.buffer = { bufferCpu, bufferGpu };
|
|
56
|
-
|
|
57
44
|
this.setLights([]);
|
|
58
45
|
}
|
|
59
|
-
|
|
60
|
-
public setLights(lights: ReadonlyArray<Light>): void {
|
|
46
|
+
setLights(lights) {
|
|
61
47
|
if (lights.length > this.maxLightsCount) {
|
|
62
48
|
throw new Error(`Too many lights "${lights.length}", max is "${this.maxLightsCount}".`);
|
|
63
49
|
}
|
|
64
|
-
|
|
65
50
|
const newBufferLength = LightsBuffer.computeBufferBytesLength(lights.length);
|
|
66
51
|
new Uint32Array(this.buffer.bufferCpu, 0, 1).set([lights.length]);
|
|
67
|
-
|
|
68
|
-
lights.forEach((light: Light, index: number) => {
|
|
52
|
+
lights.forEach((light, index) => {
|
|
69
53
|
new Float32Array(this.buffer.bufferCpu, LightsBuffer.structs.lightsBuffer.lights.offset + LightsBuffer.structs.lightsBuffer.lights.stride * index, 9).set([
|
|
70
54
|
...light.color,
|
|
71
55
|
light.radius,
|
|
@@ -75,24 +59,17 @@ struct LightsBuffer { // align(16)
|
|
|
75
59
|
light.attenuationExp
|
|
76
60
|
]);
|
|
77
61
|
});
|
|
78
|
-
|
|
79
62
|
this.device.queue.writeBuffer(this.buffer.bufferGpu, 0, this.buffer.bufferCpu, 0, newBufferLength);
|
|
80
63
|
this.currentLightsCount = lights.length;
|
|
81
64
|
}
|
|
82
|
-
|
|
83
|
-
public get lightsCount(): number {
|
|
65
|
+
get lightsCount() {
|
|
84
66
|
return this.currentLightsCount;
|
|
85
67
|
}
|
|
86
|
-
|
|
87
|
-
public destroy(): void {
|
|
68
|
+
destroy() {
|
|
88
69
|
this.buffer.bufferGpu.destroy();
|
|
89
70
|
}
|
|
90
|
-
|
|
91
|
-
private static computeBufferBytesLength(lightsCount: number): number {
|
|
71
|
+
static computeBufferBytesLength(lightsCount) {
|
|
92
72
|
return LightsBuffer.structs.lightsBuffer.lights.offset + LightsBuffer.structs.lightsBuffer.lights.stride * lightsCount;
|
|
93
73
|
}
|
|
94
74
|
}
|
|
95
|
-
|
|
96
|
-
export {
|
|
97
|
-
LightsBuffer
|
|
98
|
-
};
|
|
75
|
+
export { LightsBuffer };
|