Files
Foundry-VTT-Docker/resources/app/node_modules/@pixi/graphics-smooth/lib/SmoothGraphics.mjs

542 lines
16 KiB
JavaScript
Raw Normal View History

2025-01-04 00:34:03 +01:00
import { Point, State, Color, BLEND_MODES, Texture, Polygon, PI_2, Rectangle, RoundedRectangle, Circle, Ellipse, SHAPES, utils, MSAA_QUALITY, DRAW_MODES } from '@pixi/core';
import { curves, LINE_CAP, LINE_JOIN, Graphics, graphicsUtils } from '@pixi/graphics';
import { SmoothGraphicsGeometry } from './SmoothGraphicsGeometry.mjs';
import { Container } from '@pixi/display';
import { FillStyle } from './core/FillStyle.mjs';
import { LineStyle, LINE_SCALE_MODE } from './core/LineStyle.mjs';
import { SmoothGraphicsShader } from './SmoothShader.mjs';
import { settings } from './settings.mjs';
const UnsmoothGraphics = Graphics;
const { BezierUtils, QuadraticUtils, ArcUtils } = graphicsUtils;
const DEFAULT_SHADERS = {};
const _SmoothGraphics = class extends Container {
constructor(geometry = null) {
super();
this._geometry = geometry || new SmoothGraphicsGeometry();
this._geometry.refCount++;
this.shader = null;
this.shaderSettings = {
maxStyles: settings.SHADER_MAX_STYLES,
maxTextures: settings.SHADER_MAX_TEXTURES,
pixelLine: settings.PIXEL_LINE
};
this.state = State.for2d();
this._fillStyle = new FillStyle();
this._lineStyle = new LineStyle();
this._matrix = null;
this._holeMode = false;
this.currentPath = null;
this.batches = [];
this.batchTint = -1;
this.batchDirty = -1;
this.vertexData = null;
this.pluginName = "smooth";
this._transformID = -1;
this._tintColor = new Color(16777215);
this.blendMode = BLEND_MODES.NORMAL;
}
get geometry() {
return this._geometry;
}
clone() {
this.finishPoly();
return new _SmoothGraphics(this._geometry);
}
set blendMode(value) {
this.state.blendMode = value;
}
get blendMode() {
return this.state.blendMode;
}
get tint() {
return this._tintColor.value;
}
set tint(value) {
this._tintColor.setValue(value);
}
get fill() {
return this._fillStyle;
}
get line() {
return this._lineStyle;
}
lineStyle(options = null, color = 0, alpha = 1, alignment = 0.5, scaleMode = settings.LINE_SCALE_MODE) {
if (typeof options === "number") {
if (typeof scaleMode === "boolean") {
scaleMode = scaleMode ? LINE_SCALE_MODE.NONE : LINE_SCALE_MODE.NORMAL;
}
options = { width: options, color, alpha, alignment, scaleMode };
} else {
const native = options.native;
if (native !== void 0) {
options.scaleMode = native ? LINE_SCALE_MODE.NONE : LINE_SCALE_MODE.NORMAL;
}
}
return this.lineTextureStyle(options);
}
lineTextureStyle(options) {
options = Object.assign({
width: 0,
texture: Texture.WHITE,
color: options && options.texture ? 16777215 : 0,
alpha: 1,
matrix: null,
alignment: 0.5,
native: false,
cap: LINE_CAP.BUTT,
join: LINE_JOIN.MITER,
miterLimit: 10,
shader: null,
scaleMode: settings.LINE_SCALE_MODE
}, options);
this.normalizeColor(options);
if (this.currentPath) {
this.startPoly();
}
const visible = options.width > 0 && options.alpha > 0;
if (!visible) {
this._lineStyle.reset();
} else {
if (options.matrix) {
options.matrix = options.matrix.clone();
options.matrix.invert();
}
Object.assign(this._lineStyle, { visible }, options);
}
return this;
}
startPoly() {
if (this.currentPath) {
const points = this.currentPath.points;
const len = this.currentPath.points.length;
if (len > 2) {
this.drawShape(this.currentPath);
this.currentPath = new Polygon();
this.currentPath.closeStroke = false;
this.currentPath.points.push(points[len - 2], points[len - 1]);
}
} else {
this.currentPath = new Polygon();
this.currentPath.closeStroke = false;
}
}
finishPoly() {
if (this.currentPath) {
if (this.currentPath.points.length > 2) {
this.drawShape(this.currentPath);
this.currentPath = null;
} else {
this.currentPath.points.length = 0;
}
}
}
moveTo(x, y) {
this.startPoly();
this.currentPath.points[0] = x;
this.currentPath.points[1] = y;
return this;
}
lineTo(x, y) {
if (!this.currentPath) {
this.moveTo(0, 0);
}
const points = this.currentPath.points;
const fromX = points[points.length - 2];
const fromY = points[points.length - 1];
if (fromX !== x || fromY !== y) {
points.push(x, y);
}
return this;
}
_initCurve(x = 0, y = 0) {
if (this.currentPath) {
if (this.currentPath.points.length === 0) {
this.currentPath.points = [x, y];
}
} else {
this.moveTo(x, y);
}
}
quadraticCurveTo(cpX, cpY, toX, toY) {
this._initCurve();
const points = this.currentPath.points;
if (points.length === 0) {
this.moveTo(0, 0);
}
QuadraticUtils.curveTo(cpX, cpY, toX, toY, points);
return this;
}
bezierCurveTo(cpX, cpY, cpX2, cpY2, toX, toY) {
this._initCurve();
BezierUtils.curveTo(cpX, cpY, cpX2, cpY2, toX, toY, this.currentPath.points);
return this;
}
arcTo(x1, y1, x2, y2, radius) {
this._initCurve(x1, y1);
const points = this.currentPath.points;
const result = ArcUtils.curveTo(x1, y1, x2, y2, radius, points);
if (result) {
const { cx, cy, radius: radius2, startAngle, endAngle, anticlockwise } = result;
this.arc(cx, cy, radius2, startAngle, endAngle, anticlockwise);
}
return this;
}
arc(cx, cy, radius, startAngle, endAngle, anticlockwise = false) {
if (startAngle === endAngle) {
return this;
}
if (!anticlockwise && endAngle <= startAngle) {
endAngle += PI_2;
} else if (anticlockwise && startAngle <= endAngle) {
startAngle += PI_2;
}
const sweep = endAngle - startAngle;
if (sweep === 0) {
return this;
}
const startX = cx + Math.cos(startAngle) * radius;
const startY = cy + Math.sin(startAngle) * radius;
const eps = this._geometry.closePointEps;
let points = this.currentPath ? this.currentPath.points : null;
if (points) {
const xDiff = Math.abs(points[points.length - 2] - startX);
const yDiff = Math.abs(points[points.length - 1] - startY);
if (xDiff < eps && yDiff < eps) ; else {
points.push(startX, startY);
}
} else {
this.moveTo(startX, startY);
points = this.currentPath.points;
}
ArcUtils.arc(startX, startY, cx, cy, radius, startAngle, endAngle, anticlockwise, points);
return this;
}
beginFill(color = 0, alpha = 1, smooth = false) {
return this.beginTextureFill({ texture: Texture.WHITE, color, alpha, smooth });
}
normalizeColor(options) {
const temp = Color.shared.setValue(options.color ?? 0);
options.color = temp.toNumber();
options.alpha ?? (options.alpha = temp.alpha);
}
beginTextureFill(options) {
options = Object.assign({
texture: Texture.WHITE,
color: 16777215,
alpha: 1,
matrix: null,
smooth: false
}, options);
this.normalizeColor(options);
if (this.currentPath) {
this.startPoly();
}
const visible = options.alpha > 0;
if (!visible) {
this._fillStyle.reset();
} else {
if (options.matrix) {
options.matrix = options.matrix.clone();
options.matrix.invert();
}
Object.assign(this._fillStyle, { visible }, options);
}
return this;
}
endFill() {
this.finishPoly();
this._fillStyle.reset();
return this;
}
drawRect(x, y, width, height) {
return this.drawShape(new Rectangle(x, y, width, height));
}
drawRoundedRect(x, y, width, height, radius) {
return this.drawShape(new RoundedRectangle(x, y, width, height, radius));
}
drawCircle(x, y, radius) {
return this.drawShape(new Circle(x, y, radius));
}
drawEllipse(x, y, width, height) {
return this.drawShape(new Ellipse(x, y, width, height));
}
drawPolygon(...path) {
let points;
let closeStroke = true;
const poly = path[0];
if (poly.points) {
closeStroke = poly.closeStroke;
points = poly.points;
} else if (Array.isArray(path[0])) {
points = path[0];
} else {
points = path;
}
const shape = new Polygon(points);
shape.closeStroke = closeStroke;
this.drawShape(shape);
return this;
}
drawShape(shape) {
if (!this._holeMode) {
this._geometry.drawShape(
shape,
this._fillStyle.clone(),
this._lineStyle.clone(),
this._matrix
);
} else {
this._geometry.drawHole(shape, this._matrix);
}
return this;
}
clear() {
this._geometry.clear();
this._lineStyle.reset();
this._fillStyle.reset();
this._boundsID++;
this._matrix = null;
this._holeMode = false;
this.currentPath = null;
return this;
}
isFastRect() {
const data = this._geometry.graphicsData;
return data.length === 1 && data[0].shape.type === SHAPES.RECT && !data[0].matrix && !data[0].holes.length && !(data[0].lineStyle.visible && data[0].lineStyle.width);
}
_renderCanvas(renderer) {
UnsmoothGraphics.prototype._renderCanvas.call(this, renderer);
}
_render(renderer) {
this.finishPoly();
const geometry = this._geometry;
const hasuint32 = renderer.context.supports.uint32Indices;
geometry.checkInstancing(renderer.geometry.hasInstance, hasuint32);
geometry.updateBatches(this.shaderSettings);
if (geometry.batchable) {
if (this.batchDirty !== geometry.batchDirty) {
this._populateBatches();
}
this._renderBatched(renderer);
} else {
renderer.batch.flush();
this._renderDirect(renderer);
}
}
_populateBatches() {
const geometry = this._geometry;
const blendMode = this.blendMode;
const len = geometry.batches.length;
this.batchTint = -1;
this._transformID = -1;
this.batchDirty = geometry.batchDirty;
this.batches.length = len;
this.vertexData = new Float32Array(geometry.points);
for (let i = 0; i < len; i++) {
const gI = geometry.batches[i];
const color = gI.style.color;
const vertexData = new Float32Array(
this.vertexData.buffer,
gI.attribStart * 4 * 2,
gI.attribSize * 2
);
const batch = {
vertexData,
blendMode,
// indices,
// uvs,
_batchRGB: utils.hex2rgb(color),
_tintRGB: color,
_texture: gI.style.texture,
alpha: gI.style.alpha,
worldAlpha: 1
};
this.batches[i] = batch;
}
}
_renderBatched(renderer) {
if (!this.batches.length) {
return;
}
renderer.batch.setObjectRenderer(renderer.plugins[this.pluginName]);
this.calculateVertices();
this.calculateTints();
for (let i = 0, l = this.batches.length; i < l; i++) {
const batch = this.batches[i];
batch.worldAlpha = this.worldAlpha * batch.alpha;
renderer.plugins[this.pluginName].render(batch);
}
}
_renderDirect(renderer) {
const directShader = this._resolveDirectShader(renderer);
let shader = directShader;
const geometry = this._geometry;
const worldAlpha = this.worldAlpha;
const uniforms = shader.uniforms;
const drawCalls = geometry.drawCalls;
uniforms.translationMatrix = this.transform.worldTransform;
Color.shared.setValue(this._tintColor).premultiply(worldAlpha).toArray(uniforms.tint);
uniforms.resolution = renderer.renderTexture.current ? renderer.renderTexture.current.resolution : renderer.resolution;
const projTrans = renderer.projection.transform;
if (projTrans) {
const scale = Math.sqrt(projTrans.a * projTrans.a + projTrans.b * projTrans.b);
uniforms.resolution *= scale;
}
const multisample = renderer.renderTexture.current ? renderer.renderTexture.current.multisample : renderer.multisample;
uniforms.expand = (multisample !== MSAA_QUALITY.NONE ? 2 : 1) / uniforms.resolution;
renderer.shader.bind(shader);
renderer.geometry.bind(geometry, shader);
renderer.state.set(this.state);
shader = null;
for (let i = 0, l = drawCalls.length; i < l; i++) {
const drawCall = geometry.drawCalls[i];
const shaderChange = shader !== drawCall.shader;
if (shaderChange) {
shader = drawCall.shader;
if (shader) {
shader.uniforms.translationMatrix = this.transform.worldTransform;
if (shader.uniforms.tint) {
shader.uniforms.tint[0] = uniforms.tint[0];
shader.uniforms.tint[1] = uniforms.tint[1];
shader.uniforms.tint[2] = uniforms.tint[2];
shader.uniforms.tint[3] = uniforms.tint[3];
}
}
}
const { texArray, styleArray, size, start } = drawCall;
const groupTextureCount = texArray.count;
const shaderHere = shader || directShader;
const texs = shaderHere.uniforms.styleTextureId;
const mats = shaderHere.uniforms.styleMatrix;
const lines = shaderHere.uniforms.styleLine;
for (let i2 = 0; i2 < styleArray.count; i2++) {
texs[i2] = styleArray.textureIds[i2];
lines[i2 * 2] = styleArray.lines[i2 * 2];
lines[i2 * 2 + 1] = styleArray.lines[i2 * 2 + 1];
const m = styleArray.matrices[i2];
mats[i2 * 6] = m.a;
mats[i2 * 6 + 1] = m.c;
mats[i2 * 6 + 2] = m.tx;
mats[i2 * 6 + 3] = m.b;
mats[i2 * 6 + 4] = m.d;
mats[i2 * 6 + 5] = m.ty;
}
const sizes = shaderHere.uniforms.samplerSize;
for (let i2 = 0; i2 < groupTextureCount; i2++) {
sizes[i2 * 2] = texArray.elements[i2].width;
sizes[i2 * 2 + 1] = texArray.elements[i2].height;
}
renderer.shader.bind(shaderHere);
if (shaderChange) {
renderer.geometry.bind(geometry);
}
for (let j = 0; j < groupTextureCount; j++) {
renderer.texture.bind(texArray.elements[j], j);
}
renderer.geometry.draw(DRAW_MODES.TRIANGLES, size, start);
}
}
_resolveDirectShader(_renderer) {
let shader = this.shader;
const pluginName = this.pluginName;
if (!shader) {
if (!DEFAULT_SHADERS[pluginName]) {
DEFAULT_SHADERS[pluginName] = new SmoothGraphicsShader(this.shaderSettings);
}
shader = DEFAULT_SHADERS[pluginName];
}
return shader;
}
_calculateBounds() {
this.finishPoly();
const geometry = this._geometry;
if (!geometry.graphicsData.length) {
return;
}
const { minX, minY, maxX, maxY } = geometry.bounds;
this._bounds.addFrame(this.transform, minX, minY, maxX, maxY);
}
containsPoint(point) {
this.worldTransform.applyInverse(point, _SmoothGraphics._TEMP_POINT);
return this._geometry.containsPoint(_SmoothGraphics._TEMP_POINT);
}
calculateTints() {
if (this.batchTint !== this.tint) {
this.batchTint = this._tintColor.toNumber();
for (let i = 0; i < this.batches.length; i++) {
const batch = this.batches[i];
batch._tintRGB = Color.shared.setValue(this._tintColor).multiply(batch._batchRGB).toLittleEndianNumber();
}
}
}
calculateVertices() {
const wtID = this.transform._worldID;
if (this._transformID === wtID) {
return;
}
this._transformID = wtID;
const wt = this.transform.worldTransform;
const a = wt.a;
const b = wt.b;
const c = wt.c;
const d = wt.d;
const tx = wt.tx;
const ty = wt.ty;
const data = this._geometry.points;
const vertexData = this.vertexData;
let count = 0;
for (let i = 0; i < data.length; i += 2) {
const x = data[i];
const y = data[i + 1];
vertexData[count++] = a * x + c * y + tx;
vertexData[count++] = d * y + b * x + ty;
}
}
closePath() {
const currentPath = this.currentPath;
if (currentPath) {
currentPath.closeStroke = true;
}
return this;
}
setMatrix(matrix) {
this._matrix = matrix;
return this;
}
beginHole() {
this.finishPoly();
this._holeMode = true;
return this;
}
endHole() {
this.finishPoly();
this._holeMode = false;
return this;
}
destroy(options) {
this._geometry.refCount--;
if (this._geometry.refCount === 0) {
this._geometry.dispose();
}
this._matrix = null;
this.currentPath = null;
this._lineStyle.destroy();
this._lineStyle = null;
this._fillStyle.destroy();
this._fillStyle = null;
this._geometry = null;
this.shader = null;
this.vertexData = null;
this.batches.length = 0;
this.batches = null;
super.destroy(options);
}
};
let SmoothGraphics = _SmoothGraphics;
SmoothGraphics.curves = curves;
SmoothGraphics._TEMP_POINT = new Point();
export { SmoothGraphics };
//# sourceMappingURL=SmoothGraphics.mjs.map