refactor sand to use base-set
This commit is contained in:
parent
e8d64cc907
commit
c9afe5e935
|
|
@ -23,11 +23,6 @@
|
||||||
border-radius: 2px;
|
border-radius: 2px;
|
||||||
}
|
}
|
||||||
|
|
||||||
folk-sand {
|
|
||||||
position: absolute;
|
|
||||||
inset: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
.key-helper {
|
.key-helper {
|
||||||
position: fixed;
|
position: fixed;
|
||||||
top: 20px;
|
top: 20px;
|
||||||
|
|
@ -50,6 +45,15 @@
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
box-sizing: border-box;
|
||||||
|
color: white;
|
||||||
|
position: absolute;
|
||||||
|
top: 150px;
|
||||||
|
left: 25px;
|
||||||
|
border: 1px solid white;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
@ -64,6 +68,7 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<folk-sand>
|
<folk-sand>
|
||||||
|
<p>Sanding</p>
|
||||||
<folk-shape x="100" y="100" width="50" height="50"></folk-shape>
|
<folk-shape x="100" y="100" width="50" height="50"></folk-shape>
|
||||||
<folk-shape x="100" y="200" width="50" height="50"></folk-shape>
|
<folk-shape x="100" y="200" width="50" height="50"></folk-shape>
|
||||||
<folk-shape x="100" y="300" width="50" height="50"></folk-shape>
|
<folk-shape x="100" y="300" width="50" height="50"></folk-shape>
|
||||||
|
|
|
||||||
120
src/folk-sand.ts
120
src/folk-sand.ts
|
|
@ -8,13 +8,26 @@ import {
|
||||||
visualizationShader,
|
visualizationShader,
|
||||||
vertexShader,
|
vertexShader,
|
||||||
} from './folk-sand.glsl.ts';
|
} from './folk-sand.glsl.ts';
|
||||||
import { FolkShape } from './folk-shape.ts';
|
|
||||||
import { requestAnimationFrame } from './common/rAF.ts';
|
import { requestAnimationFrame } from './common/rAF.ts';
|
||||||
|
import { FolkBaseSet } from './folk-base-set.ts';
|
||||||
|
import { css, PropertyValues } from '@lit/reactive-element';
|
||||||
|
import { DOMRectTransformReadonly } from './common/DOMRectTransform.ts';
|
||||||
|
|
||||||
export class FolkSand extends HTMLElement {
|
export class FolkSand extends FolkBaseSet {
|
||||||
static tagName = 'folk-sand';
|
static override tagName = 'folk-sand';
|
||||||
|
|
||||||
private canvas!: HTMLCanvasElement;
|
static styles = [
|
||||||
|
FolkBaseSet.styles,
|
||||||
|
css`
|
||||||
|
canvas {
|
||||||
|
height: 100%;
|
||||||
|
width: 100%;
|
||||||
|
pointer-events: auto;
|
||||||
|
}
|
||||||
|
`,
|
||||||
|
];
|
||||||
|
|
||||||
|
private canvas = document.createElement('canvas');
|
||||||
private gl!: WebGL2RenderingContext;
|
private gl!: WebGL2RenderingContext;
|
||||||
|
|
||||||
private program!: WebGLProgram;
|
private program!: WebGLProgram;
|
||||||
|
|
@ -47,8 +60,6 @@ export class FolkSand extends HTMLElement {
|
||||||
private materialType = 4;
|
private materialType = 4;
|
||||||
private brushRadius = 5;
|
private brushRadius = 5;
|
||||||
|
|
||||||
private shapes: NodeListOf<FolkShape> = document.querySelectorAll('folk-shape');
|
|
||||||
|
|
||||||
private frames = 0;
|
private frames = 0;
|
||||||
private swap = 0;
|
private swap = 0;
|
||||||
private shadowSwap = 0;
|
private shadowSwap = 0;
|
||||||
|
|
@ -64,53 +75,21 @@ export class FolkSand extends HTMLElement {
|
||||||
private shapeIndexBuffer!: WebGLBuffer;
|
private shapeIndexBuffer!: WebGLBuffer;
|
||||||
private shapeIndexCount = 0;
|
private shapeIndexCount = 0;
|
||||||
|
|
||||||
static define() {
|
connectedCallback(): void {
|
||||||
if (customElements.get(this.tagName)) return;
|
super.connectedCallback();
|
||||||
FolkShape.define();
|
|
||||||
customElements.define(this.tagName, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
connectedCallback() {
|
this.renderRoot.appendChild(this.canvas);
|
||||||
this.setupCanvas();
|
|
||||||
this.initializeWebGL();
|
this.initializeWebGL();
|
||||||
this.initializeSimulation();
|
this.initializeSimulation();
|
||||||
this.initializeCollisionDetection();
|
this.initializeCollisionDetection();
|
||||||
|
|
||||||
// Collect all FolkShape elements
|
|
||||||
this.shapes = document.querySelectorAll('folk-shape');
|
|
||||||
|
|
||||||
// Attach event listeners to shapes
|
|
||||||
this.shapes.forEach((shape) => {
|
|
||||||
shape.addEventListener('transform', this.handleShapeTransform);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Initialize collision texture with current shapes
|
|
||||||
this.collectShapeData();
|
|
||||||
this.updateCollisionTexture();
|
|
||||||
|
|
||||||
this.attachEventListeners();
|
this.attachEventListeners();
|
||||||
|
this.handleShapeTransform();
|
||||||
this.render();
|
this.render();
|
||||||
}
|
}
|
||||||
|
|
||||||
disconnectedCallback() {
|
disconnectedCallback() {
|
||||||
|
super.disconnectedCallback();
|
||||||
this.detachEventListeners();
|
this.detachEventListeners();
|
||||||
|
|
||||||
// Remove event listeners from shapes
|
|
||||||
this.shapes.forEach((shape) => {
|
|
||||||
shape.removeEventListener('transform', this.handleShapeTransform);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private setupCanvas() {
|
|
||||||
this.canvas = document.createElement('canvas');
|
|
||||||
this.canvas.id = 'main-canvas';
|
|
||||||
this.canvas.style.width = '100%';
|
|
||||||
this.canvas.style.height = '100%';
|
|
||||||
this.canvas.style.display = 'block';
|
|
||||||
this.style.display = 'block';
|
|
||||||
this.style.width = '100%';
|
|
||||||
this.style.height = '100%';
|
|
||||||
this.appendChild(this.canvas);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private initializeWebGL() {
|
private initializeWebGL() {
|
||||||
|
|
@ -206,10 +185,6 @@ export class FolkSand extends HTMLElement {
|
||||||
gl.vertexAttribPointer(posAttribLoc, 2, gl.FLOAT, false, 0, 0);
|
gl.vertexAttribPointer(posAttribLoc, 2, gl.FLOAT, false, 0, 0);
|
||||||
|
|
||||||
gl.bindVertexArray(null);
|
gl.bindVertexArray(null);
|
||||||
|
|
||||||
// Initial collection and render of shape data
|
|
||||||
this.collectShapeData();
|
|
||||||
this.updateCollisionTexture();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private setupBuffers() {
|
private setupBuffers() {
|
||||||
|
|
@ -295,11 +270,6 @@ export class FolkSand extends HTMLElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
private attachEventListeners() {
|
private attachEventListeners() {
|
||||||
this.handlePointerDown = this.handlePointerDown.bind(this);
|
|
||||||
this.handlePointerMove = this.handlePointerMove.bind(this);
|
|
||||||
this.handlePointerUp = this.handlePointerUp.bind(this);
|
|
||||||
this.handleKeyDown = this.handleKeyDown.bind(this);
|
|
||||||
|
|
||||||
this.canvas.addEventListener('pointerdown', this.handlePointerDown);
|
this.canvas.addEventListener('pointerdown', this.handlePointerDown);
|
||||||
this.canvas.addEventListener('pointermove', this.handlePointerMove);
|
this.canvas.addEventListener('pointermove', this.handlePointerMove);
|
||||||
this.canvas.addEventListener('pointerup', this.handlePointerUp);
|
this.canvas.addEventListener('pointerup', this.handlePointerUp);
|
||||||
|
|
@ -313,7 +283,7 @@ export class FolkSand extends HTMLElement {
|
||||||
document.removeEventListener('keydown', this.handleKeyDown);
|
document.removeEventListener('keydown', this.handleKeyDown);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handlePointerMove(event: PointerEvent) {
|
private handlePointerMove = (event: PointerEvent) => {
|
||||||
const rect = this.canvas.getBoundingClientRect();
|
const rect = this.canvas.getBoundingClientRect();
|
||||||
const x = event.clientX - rect.left;
|
const x = event.clientX - rect.left;
|
||||||
const y = event.clientY - rect.top;
|
const y = event.clientY - rect.top;
|
||||||
|
|
@ -325,9 +295,9 @@ export class FolkSand extends HTMLElement {
|
||||||
// Scale coordinates relative to canvas size
|
// Scale coordinates relative to canvas size
|
||||||
this.pointer.x = (x / rect.width) * this.canvas.width;
|
this.pointer.x = (x / rect.width) * this.canvas.width;
|
||||||
this.pointer.y = (y / rect.height) * this.canvas.height;
|
this.pointer.y = (y / rect.height) * this.canvas.height;
|
||||||
}
|
};
|
||||||
|
|
||||||
private handlePointerDown(event: PointerEvent) {
|
private handlePointerDown = (event: PointerEvent) => {
|
||||||
const rect = this.canvas.getBoundingClientRect();
|
const rect = this.canvas.getBoundingClientRect();
|
||||||
const x = event.clientX - rect.left;
|
const x = event.clientX - rect.left;
|
||||||
const y = event.clientY - rect.top;
|
const y = event.clientY - rect.top;
|
||||||
|
|
@ -338,18 +308,18 @@ export class FolkSand extends HTMLElement {
|
||||||
this.pointer.prevX = this.pointer.x;
|
this.pointer.prevX = this.pointer.x;
|
||||||
this.pointer.prevY = this.pointer.y;
|
this.pointer.prevY = this.pointer.y;
|
||||||
this.pointer.down = true;
|
this.pointer.down = true;
|
||||||
}
|
};
|
||||||
|
|
||||||
private handlePointerUp() {
|
private handlePointerUp = () => {
|
||||||
this.pointer.down = false;
|
this.pointer.down = false;
|
||||||
}
|
};
|
||||||
|
|
||||||
private handleKeyDown(event: KeyboardEvent) {
|
private handleKeyDown = (event: KeyboardEvent) => {
|
||||||
const key = parseInt(event.key);
|
const key = parseInt(event.key);
|
||||||
if (!isNaN(key)) {
|
if (!isNaN(key)) {
|
||||||
this.setMaterialType(key);
|
this.setMaterialType(key);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
private setMaterialType(type: number) {
|
private setMaterialType(type: number) {
|
||||||
this.materialType = Math.min(Math.max(type, 0), 9);
|
this.materialType = Math.min(Math.max(type, 0), 9);
|
||||||
|
|
@ -636,12 +606,20 @@ export class FolkSand extends HTMLElement {
|
||||||
const indices: number[] = [];
|
const indices: number[] = [];
|
||||||
let vertexOffset = 0;
|
let vertexOffset = 0;
|
||||||
|
|
||||||
this.shapes.forEach((shape) => {
|
this.sourceRects.forEach((rect) => {
|
||||||
const rect = shape.getTransformDOMRect();
|
|
||||||
if (!rect) return;
|
|
||||||
|
|
||||||
// Get the transformed vertices in parent space
|
// Get the transformed vertices in parent space
|
||||||
const transformedPoints = rect.vertices().map((point) => rect.toParentSpace(point));
|
let transformedPoints;
|
||||||
|
|
||||||
|
if (rect instanceof DOMRectTransformReadonly) {
|
||||||
|
transformedPoints = rect.vertices().map((point) => rect.toParentSpace(point));
|
||||||
|
} else {
|
||||||
|
transformedPoints = [
|
||||||
|
{ x: rect.left, y: rect.top },
|
||||||
|
{ x: rect.right, y: rect.top },
|
||||||
|
{ x: rect.left, y: rect.bottom },
|
||||||
|
{ x: rect.right, y: rect.bottom },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
// Convert the transformed points to buffer coordinates
|
// Convert the transformed points to buffer coordinates
|
||||||
const bufferPoints = transformedPoints.map((point) => this.convertToBufferCoordinates(point.x, point.y));
|
const bufferPoints = transformedPoints.map((point) => this.convertToBufferCoordinates(point.x, point.y));
|
||||||
|
|
@ -704,10 +682,18 @@ export class FolkSand extends HTMLElement {
|
||||||
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
private handleShapeTransform = () => {
|
override update(changedProperties: PropertyValues<this>) {
|
||||||
|
super.update(changedProperties);
|
||||||
|
|
||||||
|
if (this.sourcesMap.size !== this.sourceElements.size) return;
|
||||||
|
|
||||||
|
this.handleShapeTransform();
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleShapeTransform() {
|
||||||
// Recollect and update all shape data when any shape changes
|
// Recollect and update all shape data when any shape changes
|
||||||
// TODO: do this more piecemeal
|
// TODO: do this more piecemeal
|
||||||
this.collectShapeData();
|
this.collectShapeData();
|
||||||
this.updateCollisionTexture();
|
this.updateCollisionTexture();
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue