Skip to content

Commit

Permalink
feat: use earcut for path triangulation
Browse files Browse the repository at this point in the history
  • Loading branch information
xiaoiver committed Oct 31, 2024
1 parent f19f24e commit e57ef56
Show file tree
Hide file tree
Showing 91 changed files with 13,857 additions and 59 deletions.
13 changes: 12 additions & 1 deletion packages/core/examples/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Ellipse,
parsePath,
} from '../src';
import { CheckboardStyle } from '../src/plugins';

const $canvas = document.getElementById('canvas') as HTMLCanvasElement;
const resize = (width: number, height: number) => {
Expand Down Expand Up @@ -66,10 +67,20 @@ const svg = {
};

const path = new Path({
d: 'M 100 100 L 200 200 L 300 100 Z',
d: svg.circle,
fill: 'black',
opacity: 0.5,
});
canvas.appendChild(path);

const path2 = new Path({
d: svg.circle,
fill: 'black',
opacity: 0.5,
});
path2.position.x = 100;
canvas.appendChild(path2);

// console.log(parsePath(svg.circle).subPaths[0].getPoints());

// const polyline1 = new Polyline({
Expand Down
78 changes: 31 additions & 47 deletions packages/core/src/drawcalls/Mesh.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import {
} from '@antv/g-device-api';
import { Path } from '../shapes';
import { Drawcall, ZINDEX_FACTOR } from './Drawcall';
import { vert, frag } from '../shaders/sdf_path';
import { isString, paddingMat3, parsePath } from '../utils';
import { vert, frag } from '../shaders/mesh';
import { isString, paddingMat3 } from '../utils';
import earcut from 'earcut';

const strokeAlignmentMap = {
Expand All @@ -32,7 +32,7 @@ const strokeAlignmentMap = {

export class Mesh extends Drawcall {
#program: Program;
#fragUnitBuffer: Buffer;
#pointsBuffer: Buffer;
#instancedBuffer: Buffer;
#instancedMatrixBuffer: Buffer;
#indexBuffer: Buffer;
Expand All @@ -42,6 +42,9 @@ export class Mesh extends Drawcall {
#bindings: Bindings;
#texture: Texture;

points: number[];
triangles: number[];

static useDash(shape: Path) {
const { strokeDasharray } = shape;
return (
Expand Down Expand Up @@ -82,25 +85,23 @@ export class Mesh extends Drawcall {
}

createGeometry(): void {
const { d } = this.shapes[0] as Path;
const { subPaths } = parsePath(d);
const points = subPaths
.map((subPath) =>
subPath.getPoints().map((point) => [point[0], point[1]]),
)
.flat(2);
const triangles = earcut(points);
const points = (this.shapes[0] as Path).points.flat(2);

console.log(triangles);
const triangles = earcut(points);
this.points = points;
this.triangles = triangles;

if (!this.#fragUnitBuffer) {
this.#fragUnitBuffer = this.device.createBuffer({
viewOrSize: new Float32Array([-1, -1, 1, -1, 1, 1, -1, 1]),
if (!this.#pointsBuffer) {
this.#pointsBuffer = this.device.createBuffer({
viewOrSize: new Float32Array(points),
usage: BufferUsage.VERTEX,
hint: BufferFrequencyHint.STATIC,
});
}

if (!this.#indexBuffer) {
this.#indexBuffer = this.device.createBuffer({
viewOrSize: new Uint32Array([0, 1, 2, 0, 2, 3]),
viewOrSize: new Uint32Array(triangles),
usage: BufferUsage.INDEX,
hint: BufferFrequencyHint.STATIC,
});
Expand Down Expand Up @@ -133,7 +134,6 @@ export class Mesh extends Drawcall {
if (this.instanced) {
defines += '#define USE_INSTANCES\n';
}
defines += '#define USE_FILLIMAGE\n';

if (this.#program) {
this.#program.destroy();
Expand Down Expand Up @@ -162,7 +162,7 @@ export class Mesh extends Drawcall {
stepMode: VertexStepMode.VERTEX,
attributes: [
{
shaderLocation: 0, // a_FragCoord
shaderLocation: 1, // a_Position
offset: 0,
format: Format.F32_RG,
},
Expand All @@ -173,42 +173,37 @@ export class Mesh extends Drawcall {
if (this.instanced) {
vertexBufferDescriptors.push(
{
arrayStride: 4 * 28,
arrayStride: 4 * 24,
stepMode: VertexStepMode.INSTANCE,
attributes: [
{
shaderLocation: 1, // a_PositionSize
offset: 0,
format: Format.F32_RGBA,
},
{
shaderLocation: 2, // a_FillColor
offset: 4 * 4,
offset: 4 * 0,
format: Format.F32_RGBA,
},
{
shaderLocation: 3, // a_StrokeColor
offset: 4 * 8,
offset: 4 * 4,
format: Format.F32_RGBA,
},
{
shaderLocation: 4, // a_ZIndexStrokeWidth
offset: 4 * 12,
offset: 4 * 8,
format: Format.F32_RGBA,
},
{
shaderLocation: 5, // a_Opacity
offset: 4 * 16,
offset: 4 * 12,
format: Format.F32_RGBA,
},
{
shaderLocation: 6, // a_InnerShadowColor
offset: 4 * 20,
offset: 4 * 16,
format: Format.F32_RGBA,
},
{
shaderLocation: 7, // a_InnerShadow
offset: 4 * 24,
offset: 4 * 20,
format: Format.F32_RGBA,
},
],
Expand Down Expand Up @@ -243,8 +238,7 @@ export class Mesh extends Drawcall {
});
if (!this.#uniformBuffer) {
this.#uniformBuffer = this.device.createBuffer({
viewOrSize:
Float32Array.BYTES_PER_ELEMENT * (16 + 4 + 4 + 4 + 4 + 4 + 4),
viewOrSize: Float32Array.BYTES_PER_ELEMENT * (16 + 4 + 4 + 4 + 4 + 4),
usage: BufferUsage.UNIFORM,
hint: BufferFrequencyHint.DYNAMIC,
});
Expand Down Expand Up @@ -290,7 +284,7 @@ export class Mesh extends Drawcall {
},
},
});
this.device.setResourceName(this.#pipeline, 'SDFPipeline');
this.device.setResourceName(this.#pipeline, 'MeshPipeline');

const bindings: BindingsDescriptor = {
pipeline: this.#pipeline,
Expand Down Expand Up @@ -365,7 +359,7 @@ export class Mesh extends Drawcall {

const buffers = [
{
buffer: this.#fragUnitBuffer,
buffer: this.#pointsBuffer,
},
];
if (this.instanced) {
Expand All @@ -383,14 +377,13 @@ export class Mesh extends Drawcall {
buffer: this.#indexBuffer,
});
renderPass.setBindings(this.#bindings);
renderPass.drawIndexed(6, this.shapes.length);
renderPass.drawIndexed(this.triangles.length, this.shapes.length);
}

destroy(): void {
if (this.#program) {
this.#instancedMatrixBuffer?.destroy();
this.#instancedBuffer?.destroy();
this.#fragUnitBuffer?.destroy();
this.#indexBuffer?.destroy();
this.#uniformBuffer?.destroy();
this.#texture?.destroy();
Expand All @@ -412,24 +405,17 @@ export class Mesh extends Drawcall {
innerShadowBlurRadius,
} = shape;

let size: [number, number, number, number] = [0, 0, 0, 0];
const type: number = 0;
const cornerRadius = 0;

size = [0, 0, 100, 100];

const { r: fr, g: fg, b: fb, opacity: fo } = fillRGB || {};

const u_PositionSize = size;
const u_FillColor = [fr / 255, fg / 255, fb / 255, fo];
const u_StrokeColor = [sr / 255, sg / 255, sb / 255, so];
const u_ZIndexStrokeWidth = [
shape.globalRenderOrder / ZINDEX_FACTOR,
Mesh.useDash(shape) ? 0 : strokeWidth,
cornerRadius,
0,
strokeAlignmentMap[strokeAlignment],
];
const u_Opacity = [opacity, fillOpacity, strokeOpacity, type];
const u_Opacity = [opacity, fillOpacity, strokeOpacity, 0];
const u_InnerShadowColor = [isr / 255, isg / 255, isb / 255, iso];
const u_InnerShadow = [
innerShadowOffsetX,
Expand All @@ -440,7 +426,6 @@ export class Mesh extends Drawcall {

return [
[
...u_PositionSize,
...u_FillColor,
...u_StrokeColor,
...u_ZIndexStrokeWidth,
Expand All @@ -449,7 +434,6 @@ export class Mesh extends Drawcall {
...u_InnerShadow,
],
{
u_PositionSize,
u_FillColor,
u_StrokeColor,
u_ZIndexStrokeWidth,
Expand Down
Loading

0 comments on commit e57ef56

Please sign in to comment.