Skip to content

Commit 22ee6f2

Browse files
committed
chore: layer separation
1 parent 41e45b9 commit 22ee6f2

File tree

20 files changed

+393
-60
lines changed

20 files changed

+393
-60
lines changed
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
import { field, Type } from '@lastolivegames/becsy';
2+
3+
export class Filter {
4+
@field({ type: Type.object, default: '' }) declare filter: string;
5+
6+
constructor(props?: Partial<Filter>) {
7+
Object.assign(this, props);
8+
}
9+
}

packages/ecs/src/components/renderable/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,4 @@ export * from './TextDecoration';
2121
export * from './Marker';
2222
export * from './LockAspectRatio';
2323
export * from './Editable';
24+
export * from './Filter';

packages/ecs/src/drawcalls/Drawcall.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import {
1111
BufferFrequencyHint,
1212
VertexStepMode,
1313
Format,
14+
SwapChain,
1415
} from '@antv/g-device-api';
1516
import { Entity } from '@lastolivegames/becsy';
1617
import { RenderCache, uid } from '../utils';
@@ -21,6 +22,7 @@ import {
2122
FillImage,
2223
FillPattern,
2324
FillTexture,
25+
Filter,
2426
Wireframe,
2527
} from '../components';
2628

@@ -69,6 +71,7 @@ export abstract class Drawcall {
6971

7072
constructor(
7173
protected device: Device,
74+
protected swapChain: SwapChain,
7275
protected renderCache: RenderCache,
7376
protected texturePool: TexturePool,
7477
protected instanced: boolean,
@@ -165,11 +168,13 @@ export abstract class Drawcall {
165168
}
166169

167170
protected get useFillImage() {
168-
return this.shapes[0]?.hasSomeOf(
169-
FillImage,
170-
FillTexture,
171-
FillGradient,
172-
FillPattern,
171+
return (
172+
this.shapes[0]?.hasSomeOf(
173+
FillImage,
174+
FillTexture,
175+
FillGradient,
176+
FillPattern,
177+
) || this.shapes[0]?.has(Filter)
173178
);
174179
}
175180

packages/ecs/src/drawcalls/SDF.ts

Lines changed: 165 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,18 @@ import {
1717
TransparentBlack,
1818
Texture,
1919
StencilOp,
20+
TransparentWhite,
21+
Program,
22+
RenderPipeline,
23+
InputLayout,
24+
RenderTarget,
2025
} from '@antv/g-device-api';
2126
import { mat3 } from 'gl-matrix';
2227
import { Entity } from '@lastolivegames/becsy';
2328
import { Drawcall, ZINDEX_FACTOR } from './Drawcall';
2429
import { vert, frag, Location } from '../shaders/sdf';
30+
import { vert as postProcessingVert } from '../shaders/post-processing/vert';
31+
import { frag as brightness } from '../shaders/post-processing/brightness';
2532
import { paddingMat3, parseColor, parseGradient } from '../utils';
2633
import {
2734
Circle,
@@ -41,6 +48,7 @@ import {
4148
SizeAttenuation,
4249
StrokeAttenuation,
4350
Stroke,
51+
Filter,
4452
} from '../components';
4553

4654
const strokeAlignmentMap = {
@@ -55,6 +63,15 @@ export class SDF extends Drawcall {
5563
#uniformBuffer: Buffer;
5664
#texture: Texture;
5765

66+
#filterProgram: Program;
67+
#filterPipeline: RenderPipeline;
68+
#filterInputLayout: InputLayout;
69+
#filterVertexBuffer: Buffer;
70+
#filterTexture: Texture;
71+
#filterRenderTarget: RenderTarget;
72+
#filterTextureWidth: number;
73+
#filterTextureHeight: number;
74+
5875
static useDash(shape: Entity) {
5976
const { dasharray } = shape.has(Stroke)
6077
? shape.read(Stroke)
@@ -96,6 +113,10 @@ export class SDF extends Drawcall {
96113
return false;
97114
}
98115

116+
if (this.shapes[0].has(Filter) || shape.has(Filter)) {
117+
return false;
118+
}
119+
99120
return true;
100121
}
101122

@@ -300,44 +321,122 @@ export class SDF extends Drawcall {
300321

301322
const instance = this.shapes[0];
302323

303-
if (instance.has(FillGradient) || instance.has(FillPattern)) {
304-
const { minX, minY, maxX, maxY } =
305-
instance.read(ComputedBounds).geometryBounds;
306-
const width = maxX - minX;
307-
const height = maxY - minY;
308-
309-
const canvas = instance.has(FillPattern)
310-
? this.texturePool.getOrCreatePattern({
311-
pattern: instance.read(FillPattern),
312-
width,
313-
height,
314-
})
315-
: this.texturePool.getOrCreateGradient({
316-
gradients: parseGradient(instance.read(FillGradient).value),
317-
min: [minX, minY],
318-
width,
319-
height,
320-
});
321-
const texture = this.device.createTexture({
324+
if (instance.has(Filter)) {
325+
let width = 0;
326+
let height = 0;
327+
if (this.shapes[0].has(Rect)) {
328+
const { minX, minY, maxX, maxY } = Rect.getGeometryBounds(
329+
this.shapes[0].read(Rect),
330+
);
331+
width = maxX - minX;
332+
height = maxY - minY;
333+
}
334+
this.#filterTextureWidth = width;
335+
this.#filterTextureHeight = height;
336+
this.#filterTexture = this.device.createTexture({
322337
format: Format.U8_RGBA_NORM,
323-
width: 128,
324-
height: 128,
325-
usage: TextureUsage.SAMPLED,
338+
width,
339+
height,
340+
usage: TextureUsage.RENDER_TARGET,
326341
});
327-
texture.setImageData([canvas]);
328-
this.#texture = texture;
329-
} else if (instance.has(FillTexture)) {
330-
this.#texture = instance.read(FillTexture).value;
331-
} else if (instance.has(FillImage)) {
332-
const src = instance.read(FillImage).src as ImageBitmap;
333-
const texture = this.device.createTexture({
334-
format: Format.U8_RGBA_NORM,
335-
width: src.width,
336-
height: src.height,
337-
usage: TextureUsage.SAMPLED,
342+
343+
this.#filterRenderTarget = this.device.createRenderTargetFromTexture(
344+
this.#filterTexture,
345+
);
346+
347+
const diagnosticDerivativeUniformityHeader =
348+
this.device.queryVendorInfo().platformString === 'WebGPU'
349+
? 'diagnostic(off,derivative_uniformity);\n'
350+
: '';
351+
352+
this.#filterProgram = this.renderCache.createProgram({
353+
vertex: {
354+
glsl: postProcessingVert,
355+
},
356+
fragment: {
357+
glsl: brightness,
358+
postprocess: (fs) => diagnosticDerivativeUniformityHeader + fs,
359+
},
360+
});
361+
362+
this.#filterVertexBuffer = this.device.createBuffer({
363+
viewOrSize: new Float32Array([
364+
0, 0.5, -1, -1, -0.5, -0.5, -1, 1, 0.5, -0.5, 1, 1,
365+
]),
366+
usage: BufferUsage.VERTEX,
367+
hint: BufferFrequencyHint.DYNAMIC,
338368
});
339-
texture.setImageData([src]);
340-
this.#texture = texture;
369+
370+
this.#filterInputLayout = this.device.createInputLayout({
371+
vertexBufferDescriptors: [
372+
{
373+
arrayStride: 4 * 4,
374+
stepMode: VertexStepMode.VERTEX,
375+
attributes: [
376+
{
377+
shaderLocation: 0,
378+
offset: 0,
379+
format: Format.F32_RG,
380+
},
381+
{
382+
shaderLocation: 1,
383+
offset: 4 * 2,
384+
format: Format.F32_RG,
385+
},
386+
],
387+
},
388+
],
389+
indexBufferFormat: null,
390+
program: this.#filterProgram,
391+
});
392+
393+
this.#filterPipeline = this.device.createRenderPipeline({
394+
inputLayout: this.#filterInputLayout,
395+
program: this.#filterProgram,
396+
colorAttachmentFormats: [Format.U8_RGBA_NORM],
397+
});
398+
399+
this.#texture = this.#filterTexture;
400+
} else {
401+
if (instance.has(FillGradient) || instance.has(FillPattern)) {
402+
const { minX, minY, maxX, maxY } =
403+
instance.read(ComputedBounds).geometryBounds;
404+
const width = maxX - minX;
405+
const height = maxY - minY;
406+
407+
const canvas = instance.has(FillPattern)
408+
? this.texturePool.getOrCreatePattern({
409+
pattern: instance.read(FillPattern),
410+
width,
411+
height,
412+
})
413+
: this.texturePool.getOrCreateGradient({
414+
gradients: parseGradient(instance.read(FillGradient).value),
415+
min: [minX, minY],
416+
width,
417+
height,
418+
});
419+
const texture = this.device.createTexture({
420+
format: Format.U8_RGBA_NORM,
421+
width: 128,
422+
height: 128,
423+
usage: TextureUsage.SAMPLED,
424+
});
425+
texture.setImageData([canvas]);
426+
this.#texture = texture;
427+
} else if (instance.has(FillTexture)) {
428+
this.#texture = instance.read(FillTexture).value;
429+
} else if (instance.has(FillImage)) {
430+
const src = instance.read(FillImage).src as ImageBitmap;
431+
const texture = this.device.createTexture({
432+
format: Format.U8_RGBA_NORM,
433+
width: src.width,
434+
height: src.height,
435+
usage: TextureUsage.SAMPLED,
436+
});
437+
texture.setImageData([src]);
438+
this.#texture = texture;
439+
}
341440
}
342441

343442
const sampler = this.renderCache.createSampler({
@@ -364,6 +463,8 @@ export class SDF extends Drawcall {
364463
renderPass: RenderPass,
365464
sceneUniformLegacyObject: Record<string, unknown>,
366465
) {
466+
const hasFilter = this.shapes[0].has(Filter);
467+
367468
if (this.instanced) {
368469
const instancedData: number[] = [];
369470
this.shapes.forEach((shape, i, total) => {
@@ -410,13 +511,6 @@ export class SDF extends Drawcall {
410511
matrix.m22,
411512
] as mat3;
412513

413-
// if (this.shapes[0].has(Rect)) {
414-
// const { x, width } = this.shapes[0].read(Rect);
415-
// const { children } = (this.shapes[0].has(Parent) &&
416-
// this.shapes[0].read(Parent)) || { children: [] };
417-
// console.log(children.length, x, width, matrix.m20);
418-
// }
419-
420514
this.#uniformBuffer.setSubData(
421515
0,
422516
new Uint8Array(
@@ -440,6 +534,35 @@ export class SDF extends Drawcall {
440534
this.generateWireframe();
441535
}
442536

537+
if (hasFilter) {
538+
console.log('filter');
539+
const filterRenderPass = this.device.createRenderPass({
540+
colorAttachment: [this.#filterRenderTarget],
541+
colorResolveTo: [null],
542+
colorClearColor: [TransparentWhite],
543+
colorStore: [true],
544+
depthStencilAttachment: null,
545+
depthStencilResolveTo: null,
546+
});
547+
// this.program.setUniformsLegacy(sceneUniformLegacyObject);
548+
filterRenderPass.setViewport(
549+
0,
550+
0,
551+
this.#filterTextureWidth,
552+
this.#filterTextureHeight,
553+
);
554+
filterRenderPass.setPipeline(this.#filterPipeline);
555+
filterRenderPass.setVertexInput(
556+
this.#filterInputLayout,
557+
[{ buffer: this.#filterVertexBuffer }],
558+
null,
559+
);
560+
filterRenderPass.draw(3);
561+
this.device.submitPass(filterRenderPass);
562+
const { width, height } = this.swapChain.getCanvas();
563+
renderPass.setViewport(0, 0, width, height);
564+
}
565+
443566
this.program.setUniformsLegacy(sceneUniformLegacyObject);
444567
renderPass.setPipeline(this.pipeline);
445568

packages/ecs/src/history/ElementsChange.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import {
4646
HTML,
4747
Embed,
4848
Editable,
49+
Filter,
4950
} from '../components';
5051

5152
export type SceneElementsMap = Map<SerializedNode['id'], SerializedNode>;
@@ -635,6 +636,7 @@ export const mutateElement = <TElement extends Mutable<SerializedNode>>(
635636
lockAspectRatio,
636637
editable,
637638
isEditing,
639+
filter,
638640
} = updates as unknown as SerializedNodeAttributes;
639641

640642
if (!isNil(name)) {
@@ -926,6 +928,10 @@ export const mutateElement = <TElement extends Mutable<SerializedNode>>(
926928
entity.write(Editable).isEditing = !!isEditing;
927929
}
928930

931+
if (!isNil(filter)) {
932+
safeAddComponent(entity, Filter, { filter });
933+
}
934+
929935
if (isNil(element.version)) {
930936
element.version = 0;
931937
}

packages/ecs/src/plugins/Renderer.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ import {
6060
Line,
6161
LockAspectRatio,
6262
Editable,
63+
Filter,
6364
} from '../components';
6465

6566
export const RendererPlugin: Plugin = () => {
@@ -97,6 +98,7 @@ export const RendererPlugin: Plugin = () => {
9798
component(Font);
9899
component(TextDecoration);
99100
component(Marker);
101+
component(Filter);
100102

101103
/**
102104
* Geometry
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
export const frag = /* wgsl */ `
2+
3+
in vec2 v_Uv;
4+
5+
out vec4 outputColor;
6+
7+
void main() {
8+
outputColor = vec4(0.0, 1.0, 0.0, 1.0);
9+
}
10+
`;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
export enum Location {
2+
POSITION = 0,
3+
UV = 1,
4+
}
5+
6+
export const vert = /* wgsl */ `
7+
layout(location = ${Location.POSITION}) in vec2 a_Position;
8+
layout(location = ${Location.UV}) in vec2 a_Uv;
9+
10+
out vec2 v_Uv;
11+
12+
void main() {
13+
v_Uv = a_Uv;
14+
gl_Position = vec4(a_Position, 0.0, 1.0);
15+
}
16+
`;

0 commit comments

Comments
 (0)