@pixerate/editor 0.266.2 → 0.267.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/dist/agent/index.cjs +2 -2
- package/dist/agent/index.js +1 -1
- package/dist/animation-editor/controller.d.cts +8 -0
- package/dist/animation-editor/controller.d.ts +8 -0
- package/dist/animation-editor/effect-tools.d.cts +1 -1
- package/dist/animation-editor/effect-tools.d.ts +1 -1
- package/dist/animation-editor/index.cjs +172 -105
- package/dist/animation-editor/index.js +91 -24
- package/dist/brushes/index.cjs +59 -59
- package/dist/brushes/index.js +5 -5
- package/dist/brushes/profiles.d.cts +6 -1
- package/dist/brushes/profiles.d.ts +6 -1
- package/dist/{brushstrokeRender-FSUWXUZY.cjs → brushstrokeRender-L7JYRR2R.cjs} +16 -16
- package/dist/{brushstrokeRender-KD453OBX.js → brushstrokeRender-NLFPEBGI.js} +4 -4
- package/dist/canvas/brushTypes.d.cts +12 -0
- package/dist/canvas/brushTypes.d.ts +12 -0
- package/dist/canvas/brushstroke.d.cts +1 -1
- package/dist/canvas/brushstroke.d.ts +1 -1
- package/dist/canvas/drawController.d.cts +19 -4
- package/dist/canvas/drawController.d.ts +19 -4
- package/dist/canvas/index.cjs +144 -105
- package/dist/canvas/index.js +46 -7
- package/dist/{chunk-XORJ7UZO.cjs → chunk-3VHH6V67.cjs} +13 -12
- package/dist/{chunk-T2LDTEXK.js → chunk-4IDUYB45.js} +2217 -56
- package/dist/chunk-7UKFXXWL.js +802 -0
- package/dist/chunk-ADMRNWR7.js +340 -0
- package/dist/{chunk-CIJBSUM5.js → chunk-AGNUD5BI.js} +2 -2
- package/dist/{chunk-WLUVZKVD.cjs → chunk-DT4YQUGT.cjs} +32 -32
- package/dist/{chunk-DXYHQ2VN.js → chunk-EF7LZAXQ.js} +1 -1
- package/dist/chunk-EXB2EGBE.cjs +802 -0
- package/dist/{chunk-4ODRXQRW.js → chunk-EYSHTYLG.js} +1 -1
- package/dist/{chunk-R44Y3EFS.js → chunk-FGJHJIMN.js} +8 -336
- package/dist/{chunk-AQZQWXEU.cjs → chunk-G7NHE2VD.cjs} +35 -35
- package/dist/{chunk-XC6DPRYI.js → chunk-GSTSZPSR.js} +154 -949
- package/dist/{chunk-VRK322ZC.cjs → chunk-HIO6E7LC.cjs} +2 -2
- package/dist/{chunk-TOID45I2.cjs → chunk-J2TNIZ55.cjs} +1 -1
- package/dist/{chunk-YHDHFJUC.cjs → chunk-J5VQYK7T.cjs} +217 -1012
- package/dist/{chunk-3C33YTNN.js → chunk-JGWVZPT6.js} +2 -2
- package/dist/{chunk-ACFSFUQH.js → chunk-JL6YH5WD.js} +4 -0
- package/dist/{chunk-3SBLVGOM.cjs → chunk-LA5Y4ETA.cjs} +23 -23
- package/dist/{chunk-MVUQSK5J.cjs → chunk-LHPEG5AU.cjs} +107 -435
- package/dist/{chunk-DOZ6F2K2.js → chunk-NSETJI74.js} +3 -2
- package/dist/{chunk-XRXFVRGY.cjs → chunk-OKHKA43L.cjs} +2364 -203
- package/dist/{chunk-LK4SXL3V.js → chunk-OSEXT7JL.js} +1 -1
- package/dist/{chunk-PE6YJMQT.cjs → chunk-PFHJS4HE.cjs} +20 -19
- package/dist/{chunk-7KNW3WXZ.cjs → chunk-QEVLRLUN.cjs} +63 -0
- package/dist/{chunk-OTN6VB5S.cjs → chunk-RDFHWAHL.cjs} +5 -1
- package/dist/{chunk-6JL2D5SG.js → chunk-VE6UKYQ2.js} +3 -2
- package/dist/{chunk-RFJZGTHA.cjs → chunk-XVOP3CGQ.cjs} +9 -9
- package/dist/{chunk-EZOJBP4D.js → chunk-YIC6MAJ2.js} +1 -1
- package/dist/chunk-YZWM6ZIP.cjs +340 -0
- package/dist/{chunk-472INMWH.js → chunk-ZA7L5YJB.js} +63 -0
- package/dist/commands/builtins.d.cts +12 -1
- package/dist/commands/builtins.d.ts +12 -1
- package/dist/commands/index.cjs +2 -2
- package/dist/commands/index.js +1 -1
- package/dist/image-editor/controller.d.cts +1 -1
- package/dist/image-editor/controller.d.ts +1 -1
- package/dist/image-editor/index.cjs +837 -833
- package/dist/image-editor/index.js +105 -101
- package/dist/paint/index.cjs +5 -3
- package/dist/paint/index.js +46 -44
- package/dist/paint-editor/controller.d.cts +5 -3
- package/dist/paint-editor/controller.d.ts +5 -3
- package/dist/paint-editor/index.cjs +832 -2295
- package/dist/paint-editor/index.js +285 -1748
- package/dist/paint-editor/path-samples.d.cts +2 -0
- package/dist/paint-editor/path-samples.d.ts +2 -0
- package/dist/paint-editor/presence.d.cts +20 -1
- package/dist/paint-editor/presence.d.ts +20 -1
- package/dist/stickers/helpers.d.cts +2 -0
- package/dist/stickers/helpers.d.ts +2 -0
- package/dist/stickers/index.cjs +41 -35
- package/dist/stickers/index.js +22 -16
- package/dist/stickers/types.d.cts +4 -2
- package/dist/stickers/types.d.ts +4 -2
- package/dist/vector/backdrop.d.cts +13 -0
- package/dist/vector/backdrop.d.ts +13 -0
- package/dist/vector/brushstroke.d.cts +54 -7
- package/dist/vector/brushstroke.d.ts +54 -7
- package/dist/vector/brushstrokeMedia.d.cts +96 -0
- package/dist/vector/brushstrokeMedia.d.ts +96 -0
- package/dist/vector/controller.d.cts +17 -3
- package/dist/vector/controller.d.ts +17 -3
- package/dist/vector/index.cjs +1846 -1386
- package/dist/vector/index.d.cts +2 -0
- package/dist/vector/index.d.ts +2 -0
- package/dist/vector/index.js +517 -57
- package/dist/vector/render.d.cts +6 -0
- package/dist/vector/render.d.ts +6 -0
- package/dist/vector/types.d.cts +14 -0
- package/dist/vector/types.d.ts +14 -0
- package/package.json +1 -1
- package/skills/pixerate-animation-editor/SKILL.md +1 -0
- package/skills/pixerate-brushes/SKILL.md +2 -2
- package/skills/pixerate-brushes-design/SKILL.md +7 -4
- package/skills/pixerate-brushes-design/evals/port-to-vector.json +8 -8
- package/skills/pixerate-canvas/SKILL.md +11 -1
- package/skills/pixerate-image-editor/SKILL.md +19 -64
- package/skills/pixerate-image-editor/references/color-management.md +2 -1
- package/skills/pixerate-image-editor/references/free-transform.md +12 -0
- package/skills/pixerate-image-editor/references/layer-effects.md +10 -0
- package/skills/pixerate-image-editor/references/painting.md +17 -0
- package/skills/pixerate-image-editor/references/photoshop-files.md +1 -1
- package/skills/pixerate-image-editor/references/shapes-and-type.md +14 -0
- package/skills/pixerate-image-editor/references/smart-objects.md +10 -0
- package/skills/pixerate-paint-editor/SKILL.md +8 -4
- package/skills/pixerate-paint-editor/references/wet-media.md +9 -0
- package/skills/pixerate-vector/SKILL.md +16 -6
- package/skills/pixerate-vector/references/best-practices.md +1 -0
- package/skills/pixerate-vector/references/commands.md +19 -0
|
@@ -1,26 +1,3 @@
|
|
|
1
|
-
import {
|
|
2
|
-
bestOffset,
|
|
3
|
-
contentAwareFill,
|
|
4
|
-
dilateMask,
|
|
5
|
-
maskBounds,
|
|
6
|
-
membraneFill,
|
|
7
|
-
seamlessClone
|
|
8
|
-
} from "./chunk-VWEWY4FY.js";
|
|
9
|
-
import {
|
|
10
|
-
DabWalker,
|
|
11
|
-
SmudgeTip,
|
|
12
|
-
TileMedium,
|
|
13
|
-
dabRect,
|
|
14
|
-
put255,
|
|
15
|
-
rasterizeDab
|
|
16
|
-
} from "./chunk-GCVFEPJG.js";
|
|
17
|
-
import {
|
|
18
|
-
blendPixel,
|
|
19
|
-
createPigment,
|
|
20
|
-
mixPigments,
|
|
21
|
-
srgbDecode,
|
|
22
|
-
srgbEncode
|
|
23
|
-
} from "./chunk-IRSTHLQQ.js";
|
|
24
1
|
import {
|
|
25
2
|
TILE,
|
|
26
3
|
TiledSurface,
|
|
@@ -28,852 +5,6 @@ import {
|
|
|
28
5
|
tileKey
|
|
29
6
|
} from "./chunk-HVVR5PZW.js";
|
|
30
7
|
|
|
31
|
-
// src/paint/pigment-tools.ts
|
|
32
|
-
var HEX = /^#?([0-9a-f]{6})$/i;
|
|
33
|
-
function parseHex(value, index) {
|
|
34
|
-
const m = typeof value === "string" ? HEX.exec(value.trim()) : null;
|
|
35
|
-
if (!m) throw new Error(`colors[${index}].color is ${JSON.stringify(value)}; use #rrggbb, e.g. "#1e40af".`);
|
|
36
|
-
const n = parseInt(m[1], 16);
|
|
37
|
-
return [(n >> 16 & 255) / 255, (n >> 8 & 255) / 255, (n & 255) / 255];
|
|
38
|
-
}
|
|
39
|
-
function toHex(rgb) {
|
|
40
|
-
return "#" + rgb.map((v) => Math.round(Math.min(1, Math.max(0, v)) * 255).toString(16).padStart(2, "0")).join("");
|
|
41
|
-
}
|
|
42
|
-
function createPigmentTools() {
|
|
43
|
-
const mixColors = {
|
|
44
|
-
name: "mix_colors",
|
|
45
|
-
title: "Mix colours like paint",
|
|
46
|
-
description: "Mixes colours as paint would (model pigment, the default: Kubelka-Munk mixing over reflectance spectra, so blue and yellow make green and white lightens a colour into a tint instead of greying it), or as light on screen (model rgb: the weighted RGB average). Changes nothing. Returns mixed (#rrggbb, by the chosen model), the other model's result for comparison (rgbLerp and pigment), the normalised weights and the model.",
|
|
47
|
-
inputSchema: {
|
|
48
|
-
type: "object",
|
|
49
|
-
properties: {
|
|
50
|
-
colors: {
|
|
51
|
-
type: "array",
|
|
52
|
-
minItems: 1,
|
|
53
|
-
maxItems: 16,
|
|
54
|
-
description: "The paints to mix (1 to 16).",
|
|
55
|
-
items: {
|
|
56
|
-
type: "object",
|
|
57
|
-
properties: {
|
|
58
|
-
color: { type: "string", description: "Paint colour #rrggbb." },
|
|
59
|
-
weight: { type: "number", minimum: 0, description: "Parts of this paint, any scale (e.g. 1 and 3 for a 1:3 mix). At least one weight must be above 0." },
|
|
60
|
-
strength: {
|
|
61
|
-
type: "number",
|
|
62
|
-
exclusiveMinimum: 0,
|
|
63
|
-
maximum: 100,
|
|
64
|
-
description: "Tinting strength (default 1): each part counts as this many, so a strong dark paint (e.g. 4) tints a lot of white."
|
|
65
|
-
}
|
|
66
|
-
},
|
|
67
|
-
required: ["color", "weight"],
|
|
68
|
-
additionalProperties: false
|
|
69
|
-
}
|
|
70
|
-
},
|
|
71
|
-
model: {
|
|
72
|
-
type: "string",
|
|
73
|
-
enum: ["pigment", "rgb"],
|
|
74
|
-
description: "pigment (default): mix like paint (Kubelka-Munk), as the pigment blend mode, Mixer Brush and mixing pad do; rgb: average the RGB values, as normal blending and rgb mixing brushes do (strength is ignored)."
|
|
75
|
-
}
|
|
76
|
-
},
|
|
77
|
-
required: ["colors"],
|
|
78
|
-
additionalProperties: false
|
|
79
|
-
},
|
|
80
|
-
annotations: { title: "Mix colours like paint", readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: false },
|
|
81
|
-
handler: (args) => {
|
|
82
|
-
const items = args.colors;
|
|
83
|
-
const rgbs = items.map((item, i) => parseHex(item.color, i));
|
|
84
|
-
const total = items.reduce((sum, item) => sum + item.weight, 0);
|
|
85
|
-
if (!(total > 0)) throw new Error("Every weight is 0; give at least one colour a weight above 0.");
|
|
86
|
-
const pigments = rgbs.map((rgb2, i) => createPigment(rgb2, { strength: items[i].strength }));
|
|
87
|
-
const mixed = mixPigments(pigments, items.map((item) => item.weight));
|
|
88
|
-
const lerp = [0, 1, 2].map((c) => rgbs.reduce((sum, rgb2, i) => sum + rgb2[c] * items[i].weight, 0) / total);
|
|
89
|
-
const rgb = args.model === "rgb";
|
|
90
|
-
return {
|
|
91
|
-
mixed: toHex(rgb ? lerp : mixed),
|
|
92
|
-
rgbLerp: toHex(lerp),
|
|
93
|
-
pigment: toHex(mixed),
|
|
94
|
-
weights: items.map((item) => item.weight / total),
|
|
95
|
-
model: rgb ? "rgb" : "kubelka-munk"
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
};
|
|
99
|
-
return [mixColors];
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// src/paint/retouch.ts
|
|
103
|
-
var TONE_RANGES = ["shadows", "midtones", "highlights"];
|
|
104
|
-
function luma(r, g, b) {
|
|
105
|
-
return 0.299 * r + 0.587 * g + 0.114 * b;
|
|
106
|
-
}
|
|
107
|
-
function dodgeBurnCurve(v, e, range, burn) {
|
|
108
|
-
const x = Math.max(0, v);
|
|
109
|
-
const k = Math.min(1, Math.max(0, e));
|
|
110
|
-
const c = Math.min(1, x);
|
|
111
|
-
if (range === "midtones") {
|
|
112
|
-
const w2 = Math.min(1, Math.max(0, 4 * x * (1 - x)));
|
|
113
|
-
return x + w2 * (Math.pow(c, burn ? 1 + k : 1 / (1 + k)) - x);
|
|
114
|
-
}
|
|
115
|
-
const w = range === "shadows" ? (1 - c) * (1 - c) : c * c;
|
|
116
|
-
return burn ? x - k * w * x : x + k * w * (1 - c);
|
|
117
|
-
}
|
|
118
|
-
function compressGamut(c, l) {
|
|
119
|
-
const L = Math.min(1, Math.max(0, l));
|
|
120
|
-
const lo = Math.min(c[0], c[1], c[2]);
|
|
121
|
-
const hi = Math.max(c[0], c[1], c[2]);
|
|
122
|
-
let t = 1;
|
|
123
|
-
if (hi > 1 && hi - L > 1e-9) t = Math.min(t, (1 - L) / (hi - L));
|
|
124
|
-
if (lo < 0 && L - lo > 1e-9) t = Math.min(t, L / (L - lo));
|
|
125
|
-
for (let i = 0; i < 3; i++) c[i] = L + (c[i] - L) * t;
|
|
126
|
-
}
|
|
127
|
-
function dodgeBurn(c, e, range, burn, protectTones) {
|
|
128
|
-
if (!(e > 0)) return c;
|
|
129
|
-
if (protectTones) {
|
|
130
|
-
const l = luma(c[0], c[1], c[2]);
|
|
131
|
-
const nl = dodgeBurnCurve(l, e, range, burn);
|
|
132
|
-
if (l > 1e-6) for (let i = 0; i < 3; i++) c[i] *= nl / l;
|
|
133
|
-
else c[0] = c[1] = c[2] = nl;
|
|
134
|
-
compressGamut(c, nl);
|
|
135
|
-
} else for (let i = 0; i < 3; i++) c[i] = dodgeBurnCurve(c[i], e, range, burn);
|
|
136
|
-
return c;
|
|
137
|
-
}
|
|
138
|
-
function saturationOf(r, g, b) {
|
|
139
|
-
const lo = Math.min(r, g, b);
|
|
140
|
-
const hi = Math.max(r, g, b);
|
|
141
|
-
return hi <= 1e-6 ? 0 : Math.min(1, Math.max(0, (hi - lo) / hi));
|
|
142
|
-
}
|
|
143
|
-
function sponge(c, amount, saturate, vibrance) {
|
|
144
|
-
let a = Math.min(1, Math.max(0, amount));
|
|
145
|
-
if (!(a > 0)) return c;
|
|
146
|
-
if (vibrance) {
|
|
147
|
-
const s = saturationOf(c[0], c[1], c[2]);
|
|
148
|
-
a *= saturate ? 1 - s : 0.25 + 0.75 * s;
|
|
149
|
-
}
|
|
150
|
-
const l = luma(c[0], c[1], c[2]);
|
|
151
|
-
const k = saturate ? 1 + a : 1 - a;
|
|
152
|
-
for (let i = 0; i < 3; i++) c[i] = l + (c[i] - l) * k;
|
|
153
|
-
compressGamut(c, l);
|
|
154
|
-
return c;
|
|
155
|
-
}
|
|
156
|
-
function perDabStrength(e, spacing) {
|
|
157
|
-
return 1 - Math.pow(1 - Math.min(1, Math.max(0, e)), Math.min(1, Math.max(0.01, spacing)));
|
|
158
|
-
}
|
|
159
|
-
var RETOUCH_SAMPLES = ["current", "current-below", "all"];
|
|
160
|
-
var SPOT_HEAL_TYPES = ["proximity-match", "content-aware", "smooth"];
|
|
161
|
-
var DEFAULT_RETOUCH = {
|
|
162
|
-
aligned: true,
|
|
163
|
-
sample: "current",
|
|
164
|
-
spotType: "proximity-match",
|
|
165
|
-
range: "midtones",
|
|
166
|
-
exposure: 0.5,
|
|
167
|
-
protectTones: true,
|
|
168
|
-
spongeMode: "desaturate",
|
|
169
|
-
vibrance: true,
|
|
170
|
-
strength: 0.5,
|
|
171
|
-
historySteps: 0
|
|
172
|
-
};
|
|
173
|
-
function normalizeRetouch(raw = {}, base = DEFAULT_RETOUCH) {
|
|
174
|
-
const unit2 = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
|
|
175
|
-
const bool = (v, d) => typeof v === "boolean" ? v : d;
|
|
176
|
-
const pick = (v, all, d) => all.includes(v) ? v : d;
|
|
177
|
-
return {
|
|
178
|
-
aligned: bool(raw.aligned, base.aligned),
|
|
179
|
-
sample: pick(raw.sample, RETOUCH_SAMPLES, base.sample),
|
|
180
|
-
spotType: pick(raw.spotType, SPOT_HEAL_TYPES, base.spotType),
|
|
181
|
-
range: pick(raw.range, TONE_RANGES, base.range),
|
|
182
|
-
exposure: unit2(raw.exposure, base.exposure),
|
|
183
|
-
protectTones: bool(raw.protectTones, base.protectTones),
|
|
184
|
-
spongeMode: pick(raw.spongeMode, ["desaturate", "saturate"], base.spongeMode),
|
|
185
|
-
vibrance: bool(raw.vibrance, base.vibrance),
|
|
186
|
-
strength: unit2(raw.strength, base.strength),
|
|
187
|
-
historySteps: typeof raw.historySteps === "number" && Number.isFinite(raw.historySteps) ? Math.min(1e3, Math.max(0, Math.round(raw.historySteps))) : base.historySteps
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
function boxBlurPixels(data, w, h, n, r) {
|
|
191
|
-
if (r < 1) return;
|
|
192
|
-
if (n === 4) for (let i = 0; i < data.length; i += 4) for (let c = 0; c < 3; c++) data[i + c] *= data[i + 3] / 255;
|
|
193
|
-
const tmp = new Float32Array(data.length);
|
|
194
|
-
const k = 1 / (2 * r + 1);
|
|
195
|
-
for (let y = 0; y < h; y++) {
|
|
196
|
-
for (let x = 0; x < w; x++) {
|
|
197
|
-
for (let c = 0; c < n; c++) {
|
|
198
|
-
let s = 0;
|
|
199
|
-
for (let d = -r; d <= r; d++) s += data[(y * w + Math.min(w - 1, Math.max(0, x + d))) * n + c];
|
|
200
|
-
tmp[(y * w + x) * n + c] = s * k;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
for (let y = 0; y < h; y++) {
|
|
205
|
-
for (let x = 0; x < w; x++) {
|
|
206
|
-
for (let c = 0; c < n; c++) {
|
|
207
|
-
let s = 0;
|
|
208
|
-
for (let d = -r; d <= r; d++) s += tmp[(Math.min(h - 1, Math.max(0, y + d)) * w + x) * n + c];
|
|
209
|
-
data[(y * w + x) * n + c] = s * k;
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
if (n === 4) {
|
|
214
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
215
|
-
const a = data[i + 3] / 255;
|
|
216
|
-
for (let c = 0; c < 3; c++) data[i + c] = a > 0 ? data[i + c] / a : 0;
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
function retouchFilter(data, w, h, n, kind, radius = 2, amount = 1) {
|
|
221
|
-
if (kind === "blur") {
|
|
222
|
-
boxBlurPixels(data, w, h, n, radius);
|
|
223
|
-
boxBlurPixels(data, w, h, n, radius);
|
|
224
|
-
return;
|
|
225
|
-
}
|
|
226
|
-
const soft = data.slice();
|
|
227
|
-
boxBlurPixels(soft, w, h, n, 1);
|
|
228
|
-
for (let i = 0; i < data.length; i++) {
|
|
229
|
-
if (n === 4 && (i & 3) === 3) continue;
|
|
230
|
-
const v = data[i] + amount * (data[i] - soft[i]);
|
|
231
|
-
data[i] = v > 0 ? v : 0;
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
var IDENTITY_CLONE_TRANSFORM = { scaleX: 1, scaleY: 1, rotate: 0 };
|
|
235
|
-
function isIdentityCloneTransform(t) {
|
|
236
|
-
return t.scaleX === 1 && t.scaleY === 1 && (t.rotate % 360 + 360) % 360 === 0;
|
|
237
|
-
}
|
|
238
|
-
function cloneSamplePoint(t, source, anchor, x, y) {
|
|
239
|
-
const a = -t.rotate * Math.PI / 180;
|
|
240
|
-
const c = Math.cos(a);
|
|
241
|
-
const s = Math.sin(a);
|
|
242
|
-
const dx = x - anchor.x;
|
|
243
|
-
const dy = y - anchor.y;
|
|
244
|
-
return [source.x + (c * dx - s * dy) / t.scaleX, source.y + (s * dx + c * dy) / t.scaleY];
|
|
245
|
-
}
|
|
246
|
-
var TransformedPixelSource = class {
|
|
247
|
-
constructor(inner, map) {
|
|
248
|
-
this.inner = inner;
|
|
249
|
-
this.map = map;
|
|
250
|
-
}
|
|
251
|
-
inner;
|
|
252
|
-
map;
|
|
253
|
-
px = [0, 0, 0, 0];
|
|
254
|
-
sample(x, y, out) {
|
|
255
|
-
const [u, v] = this.map(x, y);
|
|
256
|
-
const x0 = Math.floor(u);
|
|
257
|
-
const y0 = Math.floor(v);
|
|
258
|
-
const fx = u - x0;
|
|
259
|
-
const fy = v - y0;
|
|
260
|
-
let r = 0;
|
|
261
|
-
let g = 0;
|
|
262
|
-
let b = 0;
|
|
263
|
-
let a = 0;
|
|
264
|
-
for (let k = 0; k < 4; k++) {
|
|
265
|
-
const w = (k & 1 ? fx : 1 - fx) * (k & 2 ? fy : 1 - fy);
|
|
266
|
-
if (w <= 0) continue;
|
|
267
|
-
if (!this.inner.sample(x0 + (k & 1), y0 + (k >> 1), this.px)) continue;
|
|
268
|
-
const pa = this.px[3] * w;
|
|
269
|
-
r += this.px[0] * pa;
|
|
270
|
-
g += this.px[1] * pa;
|
|
271
|
-
b += this.px[2] * pa;
|
|
272
|
-
a += pa;
|
|
273
|
-
}
|
|
274
|
-
if (!(a > 0)) {
|
|
275
|
-
out[0] = out[1] = out[2] = out[3] = 0;
|
|
276
|
-
return false;
|
|
277
|
-
}
|
|
278
|
-
out[0] = r / a;
|
|
279
|
-
out[1] = g / a;
|
|
280
|
-
out[2] = b / a;
|
|
281
|
-
out[3] = a;
|
|
282
|
-
return true;
|
|
283
|
-
}
|
|
284
|
-
};
|
|
285
|
-
var TilePixelSource = class {
|
|
286
|
-
constructor(readTile, channels, offset = { x: 0, y: 0 }) {
|
|
287
|
-
this.readTile = readTile;
|
|
288
|
-
this.channels = channels;
|
|
289
|
-
this.offset = offset;
|
|
290
|
-
}
|
|
291
|
-
readTile;
|
|
292
|
-
channels;
|
|
293
|
-
offset;
|
|
294
|
-
cache = /* @__PURE__ */ new Map();
|
|
295
|
-
lastKey = NaN;
|
|
296
|
-
last = null;
|
|
297
|
-
sample(x, y, out) {
|
|
298
|
-
const lx = x - this.offset.x;
|
|
299
|
-
const ly = y - this.offset.y;
|
|
300
|
-
const tx = Math.floor(lx / TILE);
|
|
301
|
-
const ty = Math.floor(ly / TILE);
|
|
302
|
-
const key = tileKey(tx, ty);
|
|
303
|
-
if (key !== this.lastKey) {
|
|
304
|
-
let t2 = this.cache.get(key);
|
|
305
|
-
if (t2 === void 0) {
|
|
306
|
-
t2 = this.readTile(tx, ty);
|
|
307
|
-
this.cache.set(key, t2);
|
|
308
|
-
}
|
|
309
|
-
this.last = t2;
|
|
310
|
-
this.lastKey = key;
|
|
311
|
-
}
|
|
312
|
-
const t = this.last;
|
|
313
|
-
if (!t) {
|
|
314
|
-
out[0] = out[1] = out[2] = out[3] = 0;
|
|
315
|
-
return false;
|
|
316
|
-
}
|
|
317
|
-
const p = (ly - ty * TILE) * TILE + (lx - tx * TILE);
|
|
318
|
-
if (this.channels === 1) {
|
|
319
|
-
out[0] = out[1] = out[2] = t[p];
|
|
320
|
-
out[3] = 255;
|
|
321
|
-
return true;
|
|
322
|
-
}
|
|
323
|
-
const i = p * 4;
|
|
324
|
-
out[0] = t[i];
|
|
325
|
-
out[1] = t[i + 1];
|
|
326
|
-
out[2] = t[i + 2];
|
|
327
|
-
out[3] = t[i + 3];
|
|
328
|
-
return out[3] > 0;
|
|
329
|
-
}
|
|
330
|
-
};
|
|
331
|
-
var RegionPixelSource = class {
|
|
332
|
-
constructor(rect, data) {
|
|
333
|
-
this.rect = rect;
|
|
334
|
-
this.data = data;
|
|
335
|
-
}
|
|
336
|
-
rect;
|
|
337
|
-
data;
|
|
338
|
-
sample(x, y, out) {
|
|
339
|
-
const r = this.rect;
|
|
340
|
-
const lx = x - r.x;
|
|
341
|
-
const ly = y - r.y;
|
|
342
|
-
if (lx < 0 || ly < 0 || lx >= r.width || ly >= r.height) {
|
|
343
|
-
out[0] = out[1] = out[2] = out[3] = 0;
|
|
344
|
-
return false;
|
|
345
|
-
}
|
|
346
|
-
const i = (ly * r.width + lx) * 4;
|
|
347
|
-
out[0] = this.data[i];
|
|
348
|
-
out[1] = this.data[i + 1];
|
|
349
|
-
out[2] = this.data[i + 2];
|
|
350
|
-
out[3] = this.data[i + 3];
|
|
351
|
-
return out[3] > 0;
|
|
352
|
-
}
|
|
353
|
-
};
|
|
354
|
-
function readSourceRegion(source, rect, dx = 0, dy = 0) {
|
|
355
|
-
const out = new Float32Array(rect.width * rect.height * 4);
|
|
356
|
-
const px = [0, 0, 0, 0];
|
|
357
|
-
for (let y = 0; y < rect.height; y++) {
|
|
358
|
-
for (let x = 0; x < rect.width; x++) {
|
|
359
|
-
source.sample(rect.x + x + dx, rect.y + y + dy, px);
|
|
360
|
-
const i = (y * rect.width + x) * 4;
|
|
361
|
-
out[i] = px[0];
|
|
362
|
-
out[i + 1] = px[1];
|
|
363
|
-
out[i + 2] = px[2];
|
|
364
|
-
out[i + 3] = px[3];
|
|
365
|
-
}
|
|
366
|
-
}
|
|
367
|
-
return out;
|
|
368
|
-
}
|
|
369
|
-
function applyRetouchToTile(coverage, tileData, channels, tx, ty, paint, s, options = {}) {
|
|
370
|
-
const out = (options.into ?? tileData).slice();
|
|
371
|
-
const ox = tx * TILE + s.offset.x;
|
|
372
|
-
const oy = ty * TILE + s.offset.y;
|
|
373
|
-
let x0 = 0;
|
|
374
|
-
let y0 = 0;
|
|
375
|
-
let x1 = TILE;
|
|
376
|
-
let y1 = TILE;
|
|
377
|
-
if (options.region) {
|
|
378
|
-
const r = options.region;
|
|
379
|
-
x0 = Math.max(0, Math.floor(r.x) - ox);
|
|
380
|
-
y0 = Math.max(0, Math.floor(r.y) - oy);
|
|
381
|
-
x1 = Math.min(TILE, Math.ceil(r.x + r.width) - ox);
|
|
382
|
-
y1 = Math.min(TILE, Math.ceil(r.y + r.height) - oy);
|
|
383
|
-
if (x1 <= x0 || y1 <= y0) return out;
|
|
384
|
-
if (options.into) {
|
|
385
|
-
for (let y = y0; y < y1; y++) out.set(tileData.subarray((y * TILE + x0) * channels, (y * TILE + x1) * channels), (y * TILE + x0) * channels);
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
const sel = s.selection;
|
|
389
|
-
const blend = s.blend ?? "normal";
|
|
390
|
-
const src = [0, 0, 0, 0];
|
|
391
|
-
const rgb = [0, 0, 0];
|
|
392
|
-
const cb = [0, 0, 0, 0];
|
|
393
|
-
const cs = [0, 0, 0, 0];
|
|
394
|
-
let covKey = NaN;
|
|
395
|
-
let covTile;
|
|
396
|
-
for (let y = y0; y < y1; y++) {
|
|
397
|
-
const dy = oy + y;
|
|
398
|
-
const cty = Math.floor(dy / TILE);
|
|
399
|
-
for (let x = x0; x < x1; x++) {
|
|
400
|
-
const dx = ox + x;
|
|
401
|
-
const ctx = Math.floor(dx / TILE);
|
|
402
|
-
const key = tileKey(ctx, cty);
|
|
403
|
-
if (key !== covKey) {
|
|
404
|
-
covKey = key;
|
|
405
|
-
covTile = coverage.tiles.get(key);
|
|
406
|
-
}
|
|
407
|
-
if (!covTile) continue;
|
|
408
|
-
const c = covTile[(dy - cty * TILE) * TILE + (dx - ctx * TILE)];
|
|
409
|
-
if (c <= 0) continue;
|
|
410
|
-
let k = c * s.opacity;
|
|
411
|
-
if (sel) {
|
|
412
|
-
if (dx < 0 || dy < 0 || dx >= sel.width || dy >= sel.height) continue;
|
|
413
|
-
k *= sel.data[dy * sel.width + dx] / 255;
|
|
414
|
-
}
|
|
415
|
-
if (k > 1) k = 1;
|
|
416
|
-
if (k <= 0) continue;
|
|
417
|
-
const p = y * TILE + x;
|
|
418
|
-
if (channels === 1) {
|
|
419
|
-
const g = out[p];
|
|
420
|
-
let t;
|
|
421
|
-
if (paint.kind === "tone") {
|
|
422
|
-
rgb[0] = rgb[1] = rgb[2] = g / 255;
|
|
423
|
-
paint.tone(rgb);
|
|
424
|
-
t = luma(rgb[0], rgb[1], rgb[2]) * 255;
|
|
425
|
-
} else if (paint.kind === "color") t = paint.color[0];
|
|
426
|
-
else {
|
|
427
|
-
if (!paint.source.sample(dx + paint.dx, dy + paint.dy, src)) continue;
|
|
428
|
-
t = src[0];
|
|
429
|
-
k *= src[3] / 255;
|
|
430
|
-
}
|
|
431
|
-
out[p] = Math.round(g + (t - g) * k);
|
|
432
|
-
continue;
|
|
433
|
-
}
|
|
434
|
-
const i = p * 4;
|
|
435
|
-
const a = out[i + 3];
|
|
436
|
-
if (paint.kind === "tone") {
|
|
437
|
-
if (a === 0) continue;
|
|
438
|
-
rgb[0] = out[i] / 255;
|
|
439
|
-
rgb[1] = out[i + 1] / 255;
|
|
440
|
-
rgb[2] = out[i + 2] / 255;
|
|
441
|
-
const r0 = rgb[0];
|
|
442
|
-
const g0 = rgb[1];
|
|
443
|
-
const b0 = rgb[2];
|
|
444
|
-
paint.tone(rgb);
|
|
445
|
-
put255(out, i, r0 + (rgb[0] - r0) * k);
|
|
446
|
-
put255(out, i + 1, g0 + (rgb[1] - g0) * k);
|
|
447
|
-
put255(out, i + 2, b0 + (rgb[2] - b0) * k);
|
|
448
|
-
continue;
|
|
449
|
-
}
|
|
450
|
-
if (s.lockTransparency && a === 0) continue;
|
|
451
|
-
if (paint.kind === "color") {
|
|
452
|
-
src[0] = paint.color[0];
|
|
453
|
-
src[1] = paint.color[1];
|
|
454
|
-
src[2] = paint.color[2];
|
|
455
|
-
src[3] = paint.color[3];
|
|
456
|
-
} else if (!paint.source.sample(dx + paint.dx, dy + paint.dy, src)) continue;
|
|
457
|
-
for (let ch = 0; ch < 4; ch++) {
|
|
458
|
-
cb[ch] = out[i + ch] / 255;
|
|
459
|
-
cs[ch] = src[ch] / 255;
|
|
460
|
-
}
|
|
461
|
-
const o = blendPixel(blend, cb, cs, k);
|
|
462
|
-
put255(out, i, o[0]);
|
|
463
|
-
put255(out, i + 1, o[1]);
|
|
464
|
-
put255(out, i + 2, o[2]);
|
|
465
|
-
if (!s.lockTransparency) put255(out, i + 3, o[3]);
|
|
466
|
-
}
|
|
467
|
-
}
|
|
468
|
-
return out;
|
|
469
|
-
}
|
|
470
|
-
function applyToneToDeepTile(coverage, samples, tx, ty, tone, s, options = {}) {
|
|
471
|
-
const linear = samples instanceof Float32Array;
|
|
472
|
-
const out = (options.into ?? samples).slice();
|
|
473
|
-
const ox = tx * TILE + s.offset.x;
|
|
474
|
-
const oy = ty * TILE + s.offset.y;
|
|
475
|
-
let x0 = 0;
|
|
476
|
-
let y0 = 0;
|
|
477
|
-
let x1 = TILE;
|
|
478
|
-
let y1 = TILE;
|
|
479
|
-
if (options.region) {
|
|
480
|
-
const r = options.region;
|
|
481
|
-
x0 = Math.max(0, Math.floor(r.x) - ox);
|
|
482
|
-
y0 = Math.max(0, Math.floor(r.y) - oy);
|
|
483
|
-
x1 = Math.min(TILE, Math.ceil(r.x + r.width) - ox);
|
|
484
|
-
y1 = Math.min(TILE, Math.ceil(r.y + r.height) - oy);
|
|
485
|
-
if (x1 <= x0 || y1 <= y0) return out;
|
|
486
|
-
if (options.into) for (let y = y0; y < y1; y++) out.set(samples.subarray((y * TILE + x0) * 4, (y * TILE + x1) * 4), (y * TILE + x0) * 4);
|
|
487
|
-
}
|
|
488
|
-
const sel = s.selection;
|
|
489
|
-
const rgb = [0, 0, 0];
|
|
490
|
-
const before = [0, 0, 0];
|
|
491
|
-
const excess = [0, 0, 0];
|
|
492
|
-
let covKey = NaN;
|
|
493
|
-
let covTile;
|
|
494
|
-
for (let y = y0; y < y1; y++) {
|
|
495
|
-
const dy = oy + y;
|
|
496
|
-
const cty = Math.floor(dy / TILE);
|
|
497
|
-
for (let x = x0; x < x1; x++) {
|
|
498
|
-
const dx = ox + x;
|
|
499
|
-
const ctx = Math.floor(dx / TILE);
|
|
500
|
-
const key = tileKey(ctx, cty);
|
|
501
|
-
if (key !== covKey) {
|
|
502
|
-
covKey = key;
|
|
503
|
-
covTile = coverage.tiles.get(key);
|
|
504
|
-
}
|
|
505
|
-
if (!covTile) continue;
|
|
506
|
-
const c = covTile[(dy - cty * TILE) * TILE + (dx - ctx * TILE)];
|
|
507
|
-
if (c <= 0) continue;
|
|
508
|
-
let k = c * s.opacity;
|
|
509
|
-
if (sel) {
|
|
510
|
-
if (dx < 0 || dy < 0 || dx >= sel.width || dy >= sel.height) continue;
|
|
511
|
-
k *= sel.data[dy * sel.width + dx] / 255;
|
|
512
|
-
}
|
|
513
|
-
if (k > 1) k = 1;
|
|
514
|
-
if (k <= 0) continue;
|
|
515
|
-
const i = (y * TILE + x) * 4;
|
|
516
|
-
if (out[i + 3] === 0) continue;
|
|
517
|
-
for (let ch = 0; ch < 3; ch++) {
|
|
518
|
-
const v = out[i + ch];
|
|
519
|
-
if (linear) {
|
|
520
|
-
excess[ch] = v > 1 ? v - 1 : 0;
|
|
521
|
-
rgb[ch] = srgbEncode(v > 1 ? 1 : v < 0 ? 0 : v);
|
|
522
|
-
} else rgb[ch] = v / 65535;
|
|
523
|
-
before[ch] = rgb[ch];
|
|
524
|
-
}
|
|
525
|
-
tone(rgb);
|
|
526
|
-
for (let ch = 0; ch < 3; ch++) {
|
|
527
|
-
const e = before[ch] + (rgb[ch] - before[ch]) * k;
|
|
528
|
-
if (linear) out[i + ch] = srgbDecode(e) + excess[ch];
|
|
529
|
-
else out[i + ch] = e <= 0 ? 0 : e >= 1 ? 65535 : Math.round(e * 65535);
|
|
530
|
-
}
|
|
531
|
-
}
|
|
532
|
-
}
|
|
533
|
-
return out;
|
|
534
|
-
}
|
|
535
|
-
function toneOf(tool, settings) {
|
|
536
|
-
const burn = tool === "burn";
|
|
537
|
-
return (rgb) => {
|
|
538
|
-
dodgeBurn(rgb, settings.exposure, settings.range, burn, settings.protectTones);
|
|
539
|
-
};
|
|
540
|
-
}
|
|
541
|
-
function healPixels(w, h, src, dst, mask) {
|
|
542
|
-
const out = new Float32Array(dst);
|
|
543
|
-
const bb = maskBounds(w, h, mask);
|
|
544
|
-
if (!bb) return out;
|
|
545
|
-
const x0 = Math.max(0, bb[0] - 1);
|
|
546
|
-
const y0 = Math.max(0, bb[1] - 1);
|
|
547
|
-
const x1 = Math.min(w, bb[2] + 1);
|
|
548
|
-
const y1 = Math.min(h, bb[3] + 1);
|
|
549
|
-
const rw = x1 - x0;
|
|
550
|
-
const rh = y1 - y0;
|
|
551
|
-
const s = new Float32Array(rw * rh * 4);
|
|
552
|
-
const d = new Float32Array(rw * rh * 4);
|
|
553
|
-
const m = new Uint8Array(rw * rh);
|
|
554
|
-
for (let y = 0; y < rh; y++) {
|
|
555
|
-
for (let x = 0; x < rw; x++) {
|
|
556
|
-
const gi = (y + y0) * w + x + x0;
|
|
557
|
-
const li = y * rw + x;
|
|
558
|
-
m[li] = mask[gi] ? 1 : 0;
|
|
559
|
-
for (let c = 0; c < 4; c++) {
|
|
560
|
-
s[li * 4 + c] = src[gi * 4 + c];
|
|
561
|
-
d[li * 4 + c] = dst[gi * 4 + c];
|
|
562
|
-
}
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
const healed = seamlessClone(rw, rh, 4, s, d, m);
|
|
566
|
-
for (let y = 0; y < rh; y++) {
|
|
567
|
-
for (let x = 0; x < rw; x++) {
|
|
568
|
-
const gi = ((y + y0) * w + x + x0) * 4;
|
|
569
|
-
const li = (y * rw + x) * 4;
|
|
570
|
-
for (let c = 0; c < 4; c++) out[gi + c] = Math.min(255, Math.max(0, healed[li + c]));
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
return out;
|
|
574
|
-
}
|
|
575
|
-
function spotHealPixels(w, h, img, hole, size, type, onOffset) {
|
|
576
|
-
const domain = dilateMask(w, h, hole, 2);
|
|
577
|
-
const healMask = dilateMask(w, h, hole, 1);
|
|
578
|
-
let filled = null;
|
|
579
|
-
let bestFound = null;
|
|
580
|
-
if (type === "proximity-match") {
|
|
581
|
-
const ring = Math.min(16, Math.max(3, Math.floor(size / 8)));
|
|
582
|
-
const off2 = bestOffset(w, h, 4, img, domain, ring, Math.floor(Math.max(w, h) / 2));
|
|
583
|
-
if (off2) {
|
|
584
|
-
bestFound = off2;
|
|
585
|
-
filled = new Float32Array(img);
|
|
586
|
-
const [ddx, ddy] = off2;
|
|
587
|
-
for (let i = 0; i < w * h; i++) {
|
|
588
|
-
if (!domain[i]) continue;
|
|
589
|
-
const x = i % w + ddx;
|
|
590
|
-
const y = Math.floor(i / w) + ddy;
|
|
591
|
-
const j = (y * w + x) * 4;
|
|
592
|
-
for (let c = 0; c < 4; c++) filled[i * 4 + c] = img[j + c];
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
onOffset?.(filled ? bestFound : null);
|
|
597
|
-
if (!filled && type === "content-aware") filled = contentAwareFill(w, h, 4, img, domain);
|
|
598
|
-
if (!filled) filled = membraneFill(w, h, 4, img, domain);
|
|
599
|
-
return healPixels(w, h, filled, img, healMask);
|
|
600
|
-
}
|
|
601
|
-
function spotHealWindow(bounds, canvas) {
|
|
602
|
-
const g = Math.max(8, Math.ceil(Math.max(bounds.width, bounds.height)));
|
|
603
|
-
const x0 = Math.max(0, bounds.x - g);
|
|
604
|
-
const y0 = Math.max(0, bounds.y - g);
|
|
605
|
-
const x1 = Math.min(canvas.width, bounds.x + bounds.width + g);
|
|
606
|
-
const y1 = Math.min(canvas.height, bounds.y + bounds.height + g);
|
|
607
|
-
return { x: x0, y: y0, width: Math.max(0, x1 - x0), height: Math.max(0, y1 - y0) };
|
|
608
|
-
}
|
|
609
|
-
var RetouchDabStroke = class {
|
|
610
|
-
constructor(brush, target, effect) {
|
|
611
|
-
this.brush = brush;
|
|
612
|
-
this.effect = effect;
|
|
613
|
-
this.walker = new DabWalker(brush);
|
|
614
|
-
this.medium = new TileMedium(target);
|
|
615
|
-
}
|
|
616
|
-
brush;
|
|
617
|
-
effect;
|
|
618
|
-
dabCount = 0;
|
|
619
|
-
bounds = null;
|
|
620
|
-
walker;
|
|
621
|
-
medium;
|
|
622
|
-
smoothPos = null;
|
|
623
|
-
buf = new Float32Array(0);
|
|
624
|
-
push(points) {
|
|
625
|
-
const dabs = [];
|
|
626
|
-
for (const p of points) this.walker.push(this.smooth(p), dabs);
|
|
627
|
-
return this.paint(dabs);
|
|
628
|
-
}
|
|
629
|
-
finish(last) {
|
|
630
|
-
const dabs = [];
|
|
631
|
-
if (last && this.smoothPos && (this.smoothPos.x !== last.x || this.smoothPos.y !== last.y)) this.walker.push(last, dabs);
|
|
632
|
-
this.walker.finish(dabs);
|
|
633
|
-
return this.paint(dabs);
|
|
634
|
-
}
|
|
635
|
-
smooth(p) {
|
|
636
|
-
const a = 1 - Math.min(0.95, Math.max(0, this.brush.smoothing));
|
|
637
|
-
const cur = this.smoothPos;
|
|
638
|
-
const n = cur && a < 1 ? { ...p, x: cur.x + (p.x - cur.x) * a, y: cur.y + (p.y - cur.y) * a } : p;
|
|
639
|
-
this.smoothPos = n;
|
|
640
|
-
return n;
|
|
641
|
-
}
|
|
642
|
-
paint(dabs) {
|
|
643
|
-
const rects = [];
|
|
644
|
-
for (const d of dabs) {
|
|
645
|
-
const rect = dabRect(d, this.brush.hardness);
|
|
646
|
-
const n = rect.width * rect.height;
|
|
647
|
-
if (this.buf.length < n) this.buf = new Float32Array(n);
|
|
648
|
-
const cov = this.buf.subarray(0, n);
|
|
649
|
-
rasterizeDab({ ...d, alpha: 1 }, this.brush.hardness, rect, cov);
|
|
650
|
-
this.medium.reset();
|
|
651
|
-
this.effect(this.medium, d, rect, cov);
|
|
652
|
-
rects.push(rect);
|
|
653
|
-
this.bounds = unionRect(this.bounds, rect);
|
|
654
|
-
this.dabCount++;
|
|
655
|
-
}
|
|
656
|
-
return rects;
|
|
657
|
-
}
|
|
658
|
-
};
|
|
659
|
-
function smudgeEffect(brush, strength, mixing = "rgb") {
|
|
660
|
-
const s = Math.min(1, Math.max(0, strength));
|
|
661
|
-
const tip = new SmudgeTip({ strength: s, length: s, mixing }, brush.size);
|
|
662
|
-
return (medium, d, rect, cov) => tip.dab(medium, { x: d.x, y: d.y, radius: d.radius, opacity: d.opacity * d.alpha }, rect, cov);
|
|
663
|
-
}
|
|
664
|
-
function spongeEffect(brush, saturate, vibrance) {
|
|
665
|
-
const rgb = [0, 0, 0];
|
|
666
|
-
return (medium, d, rect, cov) => {
|
|
667
|
-
const w = rect.width;
|
|
668
|
-
for (let yy = 0; yy < rect.height; yy++) {
|
|
669
|
-
for (let xx = 0; xx < w; xx++) {
|
|
670
|
-
const cv = cov[yy * w + xx];
|
|
671
|
-
if (cv <= 0) continue;
|
|
672
|
-
const dx = rect.x + xx;
|
|
673
|
-
const dy = rect.y + yy;
|
|
674
|
-
const k = perDabStrength(cv * d.alpha * d.opacity * 0.5, brush.spacing) * medium.selectionAt(dx, dy);
|
|
675
|
-
if (k <= 0) continue;
|
|
676
|
-
const ri = medium.locate(dx, dy, false);
|
|
677
|
-
if (ri < 0 || medium.pixels[ri + 3] === 0) continue;
|
|
678
|
-
const i = medium.locate(dx, dy, true);
|
|
679
|
-
const px = medium.pixels;
|
|
680
|
-
rgb[0] = px[i] / 255;
|
|
681
|
-
rgb[1] = px[i + 1] / 255;
|
|
682
|
-
rgb[2] = px[i + 2] / 255;
|
|
683
|
-
sponge(rgb, k, saturate, vibrance);
|
|
684
|
-
put255(px, i, rgb[0]);
|
|
685
|
-
put255(px, i + 1, rgb[1]);
|
|
686
|
-
put255(px, i + 2, rgb[2]);
|
|
687
|
-
}
|
|
688
|
-
}
|
|
689
|
-
};
|
|
690
|
-
}
|
|
691
|
-
function rgbaViewOfGrey(target) {
|
|
692
|
-
const views = /* @__PURE__ */ new Map();
|
|
693
|
-
const dirty = /* @__PURE__ */ new Map();
|
|
694
|
-
const expand = (g) => {
|
|
695
|
-
const out = new Uint8ClampedArray(g.length * 4);
|
|
696
|
-
for (let i = 0; i < g.length; i++) {
|
|
697
|
-
out[i * 4] = out[i * 4 + 1] = out[i * 4 + 2] = g[i];
|
|
698
|
-
out[i * 4 + 3] = 255;
|
|
699
|
-
}
|
|
700
|
-
return out;
|
|
701
|
-
};
|
|
702
|
-
const view = {
|
|
703
|
-
offset: target.offset,
|
|
704
|
-
lockTransparency: true,
|
|
705
|
-
selection: target.selection,
|
|
706
|
-
readTile: (tx, ty) => {
|
|
707
|
-
const key = tileKey(tx, ty);
|
|
708
|
-
let v = views.get(key);
|
|
709
|
-
if (!v) {
|
|
710
|
-
v = expand(target.readTile(tx, ty) ?? new Uint8ClampedArray(TILE * TILE));
|
|
711
|
-
views.set(key, v);
|
|
712
|
-
}
|
|
713
|
-
return v;
|
|
714
|
-
},
|
|
715
|
-
writeTile: (tx, ty) => {
|
|
716
|
-
const key = tileKey(tx, ty);
|
|
717
|
-
let v = views.get(key);
|
|
718
|
-
if (!v) {
|
|
719
|
-
v = expand(target.readTile(tx, ty) ?? new Uint8ClampedArray(TILE * TILE));
|
|
720
|
-
views.set(key, v);
|
|
721
|
-
}
|
|
722
|
-
dirty.set(key, { tx, ty, data: v });
|
|
723
|
-
return v;
|
|
724
|
-
}
|
|
725
|
-
};
|
|
726
|
-
return {
|
|
727
|
-
target: view,
|
|
728
|
-
flush: () => {
|
|
729
|
-
for (const { tx, ty, data } of dirty.values()) {
|
|
730
|
-
const g = target.writeTile(tx, ty);
|
|
731
|
-
for (let i = 0; i < g.length; i++) g[i] = data[i * 4];
|
|
732
|
-
}
|
|
733
|
-
dirty.clear();
|
|
734
|
-
}
|
|
735
|
-
};
|
|
736
|
-
}
|
|
737
|
-
function unionRect(a, b) {
|
|
738
|
-
if (!a) return { ...b };
|
|
739
|
-
const x = Math.min(a.x, b.x);
|
|
740
|
-
const y = Math.min(a.y, b.y);
|
|
741
|
-
return { x, y, width: Math.max(a.x + a.width, b.x + b.width) - x, height: Math.max(a.y + a.height, b.y + b.height) - y };
|
|
742
|
-
}
|
|
743
|
-
|
|
744
|
-
// src/paint/wet/model.ts
|
|
745
|
-
var WET_TILE = 256;
|
|
746
|
-
var SLOT_SIDE = 258;
|
|
747
|
-
var PLANE = SLOT_SIDE * SLOT_SIDE;
|
|
748
|
-
var PLANE_BYTES = PLANE * 4;
|
|
749
|
-
var SET_PLANES = 19;
|
|
750
|
-
var P_RHO = 9;
|
|
751
|
-
var P_UX = 10;
|
|
752
|
-
var P_UY = 11;
|
|
753
|
-
var P_SW = 12;
|
|
754
|
-
var P_P0 = 13;
|
|
755
|
-
var P_L = P_P0 + 4;
|
|
756
|
-
var P_EDGE = 18;
|
|
757
|
-
var P_D0 = 2 * SET_PLANES;
|
|
758
|
-
var P_DL = P_D0 + 4;
|
|
759
|
-
var P_H = P_D0 + 5;
|
|
760
|
-
var P_FX = P_H + 1;
|
|
761
|
-
var P_FY = P_H + 2;
|
|
762
|
-
var SLOT_PLANES = P_FY + 1;
|
|
763
|
-
var SLOT_BYTES = SLOT_PLANES * PLANE_BYTES;
|
|
764
|
-
var PIGMENT_CHANNELS = 4;
|
|
765
|
-
var MASS_CHANNELS = 5;
|
|
766
|
-
var EX = [0, 1, 0, -1, 0, 1, -1, -1, 1];
|
|
767
|
-
var EY = [0, 0, 1, 0, -1, 1, 1, -1, -1];
|
|
768
|
-
var OPP = [0, 3, 4, 1, 2, 7, 8, 5, 6];
|
|
769
|
-
var W9 = [4 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 36, 1 / 36, 1 / 36, 1 / 36];
|
|
770
|
-
var DRY_EPS = 1e-3;
|
|
771
|
-
var U_MAX = 0.25;
|
|
772
|
-
var STRIP = 64;
|
|
773
|
-
var MAX_BATCH = 32;
|
|
774
|
-
var FREE_INTERVAL = 32;
|
|
775
|
-
var FLAG_ALIVE = 1;
|
|
776
|
-
var FLAG_LEFT = 2;
|
|
777
|
-
var FLAG_RIGHT = 4;
|
|
778
|
-
var FLAG_TOP = 8;
|
|
779
|
-
var FLAG_BOTTOM = 16;
|
|
780
|
-
var FLAG_WET = 32;
|
|
781
|
-
var PARAM_FLOATS = 32;
|
|
782
|
-
var PARAM = {
|
|
783
|
-
omega: 0,
|
|
784
|
-
tau: 1,
|
|
785
|
-
evap: 2,
|
|
786
|
-
edgeEvap: 3,
|
|
787
|
-
// times the edge field
|
|
788
|
-
mobility: 4,
|
|
789
|
-
// half the pigment mobility (the face flux uses the sum of two velocities)
|
|
790
|
-
depRate: 5,
|
|
791
|
-
pickup: 6,
|
|
792
|
-
absorption: 7,
|
|
793
|
-
invCap: 8,
|
|
794
|
-
blockScale: 9,
|
|
795
|
-
rough: 10,
|
|
796
|
-
pinT: 11,
|
|
797
|
-
gx: 12,
|
|
798
|
-
gy: 13,
|
|
799
|
-
flowK: 14,
|
|
800
|
-
granulation: 15,
|
|
801
|
-
edgeDep: 16,
|
|
802
|
-
// times the edge field
|
|
803
|
-
bloom: 17,
|
|
804
|
-
paperEvap: 18,
|
|
805
|
-
hasFlow: 19,
|
|
806
|
-
bleed: 20
|
|
807
|
-
};
|
|
808
|
-
var DEFAULT_WET_PARAMS = {
|
|
809
|
-
viscosity: 0.3,
|
|
810
|
-
evaporation: 0.45,
|
|
811
|
-
edgeDarkening: 0.5,
|
|
812
|
-
pigmentWeight: 0.3,
|
|
813
|
-
granulation: 0.4,
|
|
814
|
-
pickup: 0.2,
|
|
815
|
-
fixture: 0.2,
|
|
816
|
-
bloom: 0.4,
|
|
817
|
-
bleed: 0.3
|
|
818
|
-
};
|
|
819
|
-
var WET_PARAM_KEYS = Object.keys(DEFAULT_WET_PARAMS);
|
|
820
|
-
var DEFAULT_WET_PAPER = { absorption: 0.7, permeability: 0.5, roughness: 0.6 };
|
|
821
|
-
var FLAT = { angle: 0, direction: 0 };
|
|
822
|
-
var unit = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
|
|
823
|
-
function normalizeWetParams(raw = {}, base = DEFAULT_WET_PARAMS) {
|
|
824
|
-
const out = {};
|
|
825
|
-
for (const k of WET_PARAM_KEYS) out[k] = unit(raw[k], base[k]);
|
|
826
|
-
return out;
|
|
827
|
-
}
|
|
828
|
-
function normalizeTilt(raw = {}, base = FLAT) {
|
|
829
|
-
const angle = typeof raw.angle === "number" && Number.isFinite(raw.angle) ? Math.min(90, Math.max(0, raw.angle)) : base.angle;
|
|
830
|
-
let direction = typeof raw.direction === "number" && Number.isFinite(raw.direction) ? raw.direction : base.direction;
|
|
831
|
-
direction = (direction % 360 + 360) % 360;
|
|
832
|
-
return { angle, direction };
|
|
833
|
-
}
|
|
834
|
-
function latticeViscosity(v) {
|
|
835
|
-
return 0.02 * Math.pow(75, v);
|
|
836
|
-
}
|
|
837
|
-
var PAPER_CAPACITY = 0.08;
|
|
838
|
-
var MAX_TILT_ACCEL = 0.025;
|
|
839
|
-
function packWetParams(params, paper, tilt, flowStrength, out = new Float32Array(PARAM_FLOATS)) {
|
|
840
|
-
const nu = latticeViscosity(params.viscosity);
|
|
841
|
-
const tau = 3 * nu + 0.5;
|
|
842
|
-
const g = MAX_TILT_ACCEL * Math.sin(tilt.angle * Math.PI / 180);
|
|
843
|
-
const dir = tilt.direction * Math.PI / 180;
|
|
844
|
-
out.fill(0);
|
|
845
|
-
out[PARAM.omega] = 1 / tau;
|
|
846
|
-
out[PARAM.tau] = tau;
|
|
847
|
-
out[PARAM.evap] = 1e-3 * params.evaporation * params.evaporation;
|
|
848
|
-
out[PARAM.edgeEvap] = params.edgeDarkening * 12;
|
|
849
|
-
out[PARAM.mobility] = 0.5 * (1 - 0.5 * params.pigmentWeight);
|
|
850
|
-
out[PARAM.depRate] = 0.019 * params.fixture * (0.5 + params.pigmentWeight);
|
|
851
|
-
out[PARAM.pickup] = 0.01 * params.pickup;
|
|
852
|
-
out[PARAM.absorption] = 15e-4 * paper.absorption;
|
|
853
|
-
out[PARAM.invCap] = 1 / PAPER_CAPACITY;
|
|
854
|
-
out[PARAM.blockScale] = 0.05 * (1 - paper.permeability);
|
|
855
|
-
out[PARAM.rough] = 0.15 * paper.roughness;
|
|
856
|
-
out[PARAM.pinT] = 0.2;
|
|
857
|
-
out[PARAM.gx] = -g * Math.sin(dir);
|
|
858
|
-
out[PARAM.gy] = g * Math.cos(dir);
|
|
859
|
-
out[PARAM.flowK] = flowStrength;
|
|
860
|
-
out[PARAM.granulation] = 1.2 * params.granulation * paper.roughness;
|
|
861
|
-
out[PARAM.edgeDep] = params.edgeDarkening * 3;
|
|
862
|
-
out[PARAM.bloom] = 60 * params.bloom;
|
|
863
|
-
out[PARAM.paperEvap] = 5e-4 * params.evaporation * params.evaporation;
|
|
864
|
-
out[PARAM.hasFlow] = flowStrength !== 0 ? 1 : 0;
|
|
865
|
-
out[PARAM.bleed] = 0.05 * params.bleed;
|
|
866
|
-
return out;
|
|
867
|
-
}
|
|
868
|
-
function edgeBits(lx, ly) {
|
|
869
|
-
let b = 0;
|
|
870
|
-
if (lx < STRIP) b |= FLAG_LEFT;
|
|
871
|
-
if (lx >= WET_TILE - STRIP) b |= FLAG_RIGHT;
|
|
872
|
-
if (ly < STRIP) b |= FLAG_TOP;
|
|
873
|
-
if (ly >= WET_TILE - STRIP) b |= FLAG_BOTTOM;
|
|
874
|
-
return b;
|
|
875
|
-
}
|
|
876
|
-
|
|
877
8
|
// src/paint/wet/film.ts
|
|
878
9
|
var PIGMENT_UNIT = 0.25;
|
|
879
10
|
var HIDE = 1.5;
|
|
@@ -1200,6 +331,139 @@ function shadeLightTile(f, plane, side, d, p, dl, pl, src, out, w, h) {
|
|
|
1200
331
|
return any;
|
|
1201
332
|
}
|
|
1202
333
|
|
|
334
|
+
// src/paint/wet/model.ts
|
|
335
|
+
var WET_TILE = 256;
|
|
336
|
+
var SLOT_SIDE = 258;
|
|
337
|
+
var PLANE = SLOT_SIDE * SLOT_SIDE;
|
|
338
|
+
var PLANE_BYTES = PLANE * 4;
|
|
339
|
+
var SET_PLANES = 19;
|
|
340
|
+
var P_RHO = 9;
|
|
341
|
+
var P_UX = 10;
|
|
342
|
+
var P_UY = 11;
|
|
343
|
+
var P_SW = 12;
|
|
344
|
+
var P_P0 = 13;
|
|
345
|
+
var P_L = P_P0 + 4;
|
|
346
|
+
var P_EDGE = 18;
|
|
347
|
+
var P_D0 = 2 * SET_PLANES;
|
|
348
|
+
var P_DL = P_D0 + 4;
|
|
349
|
+
var P_H = P_D0 + 5;
|
|
350
|
+
var P_FX = P_H + 1;
|
|
351
|
+
var P_FY = P_H + 2;
|
|
352
|
+
var SLOT_PLANES = P_FY + 1;
|
|
353
|
+
var SLOT_BYTES = SLOT_PLANES * PLANE_BYTES;
|
|
354
|
+
var PIGMENT_CHANNELS = 4;
|
|
355
|
+
var MASS_CHANNELS = 5;
|
|
356
|
+
var EX = [0, 1, 0, -1, 0, 1, -1, -1, 1];
|
|
357
|
+
var EY = [0, 0, 1, 0, -1, 1, 1, -1, -1];
|
|
358
|
+
var OPP = [0, 3, 4, 1, 2, 7, 8, 5, 6];
|
|
359
|
+
var W9 = [4 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 9, 1 / 36, 1 / 36, 1 / 36, 1 / 36];
|
|
360
|
+
var DRY_EPS = 1e-3;
|
|
361
|
+
var U_MAX = 0.25;
|
|
362
|
+
var STRIP = 64;
|
|
363
|
+
var MAX_BATCH = 32;
|
|
364
|
+
var FREE_INTERVAL = 32;
|
|
365
|
+
var FLAG_ALIVE = 1;
|
|
366
|
+
var FLAG_LEFT = 2;
|
|
367
|
+
var FLAG_RIGHT = 4;
|
|
368
|
+
var FLAG_TOP = 8;
|
|
369
|
+
var FLAG_BOTTOM = 16;
|
|
370
|
+
var FLAG_WET = 32;
|
|
371
|
+
var PARAM_FLOATS = 32;
|
|
372
|
+
var PARAM = {
|
|
373
|
+
omega: 0,
|
|
374
|
+
tau: 1,
|
|
375
|
+
evap: 2,
|
|
376
|
+
edgeEvap: 3,
|
|
377
|
+
// times the edge field
|
|
378
|
+
mobility: 4,
|
|
379
|
+
// half the pigment mobility (the face flux uses the sum of two velocities)
|
|
380
|
+
depRate: 5,
|
|
381
|
+
pickup: 6,
|
|
382
|
+
absorption: 7,
|
|
383
|
+
invCap: 8,
|
|
384
|
+
blockScale: 9,
|
|
385
|
+
rough: 10,
|
|
386
|
+
pinT: 11,
|
|
387
|
+
gx: 12,
|
|
388
|
+
gy: 13,
|
|
389
|
+
flowK: 14,
|
|
390
|
+
granulation: 15,
|
|
391
|
+
edgeDep: 16,
|
|
392
|
+
// times the edge field
|
|
393
|
+
bloom: 17,
|
|
394
|
+
paperEvap: 18,
|
|
395
|
+
hasFlow: 19,
|
|
396
|
+
bleed: 20
|
|
397
|
+
};
|
|
398
|
+
var DEFAULT_WET_PARAMS = {
|
|
399
|
+
viscosity: 0.3,
|
|
400
|
+
evaporation: 0.45,
|
|
401
|
+
edgeDarkening: 0.5,
|
|
402
|
+
pigmentWeight: 0.3,
|
|
403
|
+
granulation: 0.4,
|
|
404
|
+
pickup: 0.2,
|
|
405
|
+
fixture: 0.2,
|
|
406
|
+
bloom: 0.4,
|
|
407
|
+
bleed: 0.3
|
|
408
|
+
};
|
|
409
|
+
var WET_PARAM_KEYS = Object.keys(DEFAULT_WET_PARAMS);
|
|
410
|
+
var DEFAULT_WET_PAPER = { absorption: 0.7, permeability: 0.5, roughness: 0.6 };
|
|
411
|
+
var FLAT = { angle: 0, direction: 0 };
|
|
412
|
+
var unit = (v, d) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : d;
|
|
413
|
+
function normalizeWetParams(raw = {}, base = DEFAULT_WET_PARAMS) {
|
|
414
|
+
const out = {};
|
|
415
|
+
for (const k of WET_PARAM_KEYS) out[k] = unit(raw[k], base[k]);
|
|
416
|
+
return out;
|
|
417
|
+
}
|
|
418
|
+
function normalizeTilt(raw = {}, base = FLAT) {
|
|
419
|
+
const angle = typeof raw.angle === "number" && Number.isFinite(raw.angle) ? Math.min(90, Math.max(0, raw.angle)) : base.angle;
|
|
420
|
+
let direction = typeof raw.direction === "number" && Number.isFinite(raw.direction) ? raw.direction : base.direction;
|
|
421
|
+
direction = (direction % 360 + 360) % 360;
|
|
422
|
+
return { angle, direction };
|
|
423
|
+
}
|
|
424
|
+
function latticeViscosity(v) {
|
|
425
|
+
return 0.02 * Math.pow(75, v);
|
|
426
|
+
}
|
|
427
|
+
var PAPER_CAPACITY = 0.08;
|
|
428
|
+
var MAX_TILT_ACCEL = 0.025;
|
|
429
|
+
function packWetParams(params, paper, tilt, flowStrength, out = new Float32Array(PARAM_FLOATS)) {
|
|
430
|
+
const nu = latticeViscosity(params.viscosity);
|
|
431
|
+
const tau = 3 * nu + 0.5;
|
|
432
|
+
const g = MAX_TILT_ACCEL * Math.sin(tilt.angle * Math.PI / 180);
|
|
433
|
+
const dir = tilt.direction * Math.PI / 180;
|
|
434
|
+
out.fill(0);
|
|
435
|
+
out[PARAM.omega] = 1 / tau;
|
|
436
|
+
out[PARAM.tau] = tau;
|
|
437
|
+
out[PARAM.evap] = 1e-3 * params.evaporation * params.evaporation;
|
|
438
|
+
out[PARAM.edgeEvap] = params.edgeDarkening * 12;
|
|
439
|
+
out[PARAM.mobility] = 0.5 * (1 - 0.5 * params.pigmentWeight);
|
|
440
|
+
out[PARAM.depRate] = 0.019 * params.fixture * (0.5 + params.pigmentWeight);
|
|
441
|
+
out[PARAM.pickup] = 0.01 * params.pickup;
|
|
442
|
+
out[PARAM.absorption] = 15e-4 * paper.absorption;
|
|
443
|
+
out[PARAM.invCap] = 1 / PAPER_CAPACITY;
|
|
444
|
+
out[PARAM.blockScale] = 0.05 * (1 - paper.permeability);
|
|
445
|
+
out[PARAM.rough] = 0.15 * paper.roughness;
|
|
446
|
+
out[PARAM.pinT] = 0.2;
|
|
447
|
+
out[PARAM.gx] = -g * Math.sin(dir);
|
|
448
|
+
out[PARAM.gy] = g * Math.cos(dir);
|
|
449
|
+
out[PARAM.flowK] = flowStrength;
|
|
450
|
+
out[PARAM.granulation] = 1.2 * params.granulation * paper.roughness;
|
|
451
|
+
out[PARAM.edgeDep] = params.edgeDarkening * 3;
|
|
452
|
+
out[PARAM.bloom] = 60 * params.bloom;
|
|
453
|
+
out[PARAM.paperEvap] = 5e-4 * params.evaporation * params.evaporation;
|
|
454
|
+
out[PARAM.hasFlow] = flowStrength !== 0 ? 1 : 0;
|
|
455
|
+
out[PARAM.bleed] = 0.05 * params.bleed;
|
|
456
|
+
return out;
|
|
457
|
+
}
|
|
458
|
+
function edgeBits(lx, ly) {
|
|
459
|
+
let b = 0;
|
|
460
|
+
if (lx < STRIP) b |= FLAG_LEFT;
|
|
461
|
+
if (lx >= WET_TILE - STRIP) b |= FLAG_RIGHT;
|
|
462
|
+
if (ly < STRIP) b |= FLAG_TOP;
|
|
463
|
+
if (ly >= WET_TILE - STRIP) b |= FLAG_BOTTOM;
|
|
464
|
+
return b;
|
|
465
|
+
}
|
|
466
|
+
|
|
1203
467
|
// src/paint/wet/kernel.ts
|
|
1204
468
|
var F = Math.fround;
|
|
1205
469
|
var S = SLOT_SIDE;
|
|
@@ -2510,7 +1774,7 @@ var WetWorld = class {
|
|
|
2510
1774
|
if (x1 <= x0 || y1 <= y0) continue;
|
|
2511
1775
|
const whole = x0 === tr.x && y0 === tr.y && x1 >= Math.min(tr.x + WET_TILE, this.width) && y1 >= Math.min(tr.y + WET_TILE, this.height);
|
|
2512
1776
|
if (whole) {
|
|
2513
|
-
if (this.bakeKey(key, true)) bounds =
|
|
1777
|
+
if (this.bakeKey(key, true)) bounds = unionRect(bounds, { x: tr.x, y: tr.y, width: Math.min(WET_TILE, this.width - tr.x), height: Math.min(WET_TILE, this.height - tr.y) });
|
|
2514
1778
|
this.free(key);
|
|
2515
1779
|
continue;
|
|
2516
1780
|
}
|
|
@@ -2530,7 +1794,7 @@ var WetWorld = class {
|
|
|
2530
1794
|
f[c + P_SW * PLANE] = 0;
|
|
2531
1795
|
}
|
|
2532
1796
|
}
|
|
2533
|
-
bounds =
|
|
1797
|
+
bounds = unionRect(bounds, { x: x0, y: y0, width: x1 - x0, height: y1 - y0 });
|
|
2534
1798
|
this.markEdited(lane, x0, y0, x1, y1);
|
|
2535
1799
|
}
|
|
2536
1800
|
this.syncList();
|
|
@@ -3100,7 +2364,7 @@ function moveWetSnapshot(snap, from, to, dx, dy, lane = () => ({})) {
|
|
|
3100
2364
|
});
|
|
3101
2365
|
return { clock: snap.clock, tilt: { ...snap.tilt }, lanes, slots, bytes };
|
|
3102
2366
|
}
|
|
3103
|
-
function
|
|
2367
|
+
function unionRect(a, b) {
|
|
3104
2368
|
if (!a) return { ...b };
|
|
3105
2369
|
const x = Math.min(a.x, b.x);
|
|
3106
2370
|
const y = Math.min(a.y, b.y);
|
|
@@ -3960,63 +3224,24 @@ var WetGpuEngine = class _WetGpuEngine {
|
|
|
3960
3224
|
}
|
|
3961
3225
|
};
|
|
3962
3226
|
|
|
3963
|
-
// src/paint/pointer.ts
|
|
3964
|
-
function pointerPressure(e) {
|
|
3965
|
-
if (e.pointerType === "pen" && typeof e.pressure === "number" && e.pressure > 0) return Math.min(1, e.pressure);
|
|
3966
|
-
return 1;
|
|
3967
|
-
}
|
|
3968
|
-
function pointerStrokeSample(e, toPoint) {
|
|
3969
|
-
const p = toPoint(e.clientX, e.clientY);
|
|
3970
|
-
const s = { x: p.x, y: p.y, pressure: pointerPressure(e) };
|
|
3971
|
-
if (typeof e.timeStamp === "number" && Number.isFinite(e.timeStamp)) s.t = e.timeStamp;
|
|
3972
|
-
if (e.pointerType === "pen") {
|
|
3973
|
-
if (typeof e.altitudeAngle === "number" && e.altitudeAngle < Math.PI / 2 - 1e-6) {
|
|
3974
|
-
s.altitude = e.altitudeAngle;
|
|
3975
|
-
s.azimuth = e.azimuthAngle ?? 0;
|
|
3976
|
-
} else if (e.tiltX || e.tiltY) {
|
|
3977
|
-
s.tiltX = e.tiltX ?? 0;
|
|
3978
|
-
s.tiltY = e.tiltY ?? 0;
|
|
3979
|
-
}
|
|
3980
|
-
}
|
|
3981
|
-
return s;
|
|
3982
|
-
}
|
|
3983
|
-
function pointerStrokeSamples(e, toPoint) {
|
|
3984
|
-
const events = e.getCoalescedEvents?.() ?? [];
|
|
3985
|
-
return (events.length ? events : [e]).map((ev) => pointerStrokeSample(ev, toPoint));
|
|
3986
|
-
}
|
|
3987
|
-
|
|
3988
3227
|
export {
|
|
3989
|
-
|
|
3990
|
-
|
|
3991
|
-
|
|
3992
|
-
|
|
3993
|
-
|
|
3994
|
-
|
|
3995
|
-
|
|
3996
|
-
|
|
3997
|
-
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
TransformedPixelSource,
|
|
4007
|
-
TilePixelSource,
|
|
4008
|
-
RegionPixelSource,
|
|
4009
|
-
readSourceRegion,
|
|
4010
|
-
applyRetouchToTile,
|
|
4011
|
-
applyToneToDeepTile,
|
|
4012
|
-
toneOf,
|
|
4013
|
-
healPixels,
|
|
4014
|
-
spotHealPixels,
|
|
4015
|
-
spotHealWindow,
|
|
4016
|
-
RetouchDabStroke,
|
|
4017
|
-
smudgeEffect,
|
|
4018
|
-
spongeEffect,
|
|
4019
|
-
rgbaViewOfGrey,
|
|
3228
|
+
PIGMENT_UNIT,
|
|
3229
|
+
HIDE,
|
|
3230
|
+
BODY_SCATTER,
|
|
3231
|
+
dexp,
|
|
3232
|
+
dlog,
|
|
3233
|
+
dpow,
|
|
3234
|
+
SRGB_TO_LINEAR,
|
|
3235
|
+
srgbByteToLinear,
|
|
3236
|
+
linearToSrgb8,
|
|
3237
|
+
pigmentOf,
|
|
3238
|
+
expNeg,
|
|
3239
|
+
filmReflectance,
|
|
3240
|
+
pigmentColor,
|
|
3241
|
+
filmPixel,
|
|
3242
|
+
pixelPigment,
|
|
3243
|
+
shadeTile,
|
|
3244
|
+
shadeLightTile,
|
|
4020
3245
|
WET_TILE,
|
|
4021
3246
|
SLOT_SIDE,
|
|
4022
3247
|
PLANE,
|
|
@@ -4066,23 +3291,6 @@ export {
|
|
|
4066
3291
|
MAX_TILT_ACCEL,
|
|
4067
3292
|
packWetParams,
|
|
4068
3293
|
edgeBits,
|
|
4069
|
-
PIGMENT_UNIT,
|
|
4070
|
-
HIDE,
|
|
4071
|
-
BODY_SCATTER,
|
|
4072
|
-
dexp,
|
|
4073
|
-
dlog,
|
|
4074
|
-
dpow,
|
|
4075
|
-
SRGB_TO_LINEAR,
|
|
4076
|
-
srgbByteToLinear,
|
|
4077
|
-
linearToSrgb8,
|
|
4078
|
-
pigmentOf,
|
|
4079
|
-
expNeg,
|
|
4080
|
-
filmReflectance,
|
|
4081
|
-
pigmentColor,
|
|
4082
|
-
filmPixel,
|
|
4083
|
-
pixelPigment,
|
|
4084
|
-
shadeTile,
|
|
4085
|
-
shadeLightTile,
|
|
4086
3294
|
stepSlotTs,
|
|
4087
3295
|
loadWetKernel,
|
|
4088
3296
|
canShareMemory,
|
|
@@ -4106,8 +3314,5 @@ export {
|
|
|
4106
3314
|
findWebGpu,
|
|
4107
3315
|
createWetGpuEngine,
|
|
4108
3316
|
wetGpuSupport,
|
|
4109
|
-
WetGpuEngine
|
|
4110
|
-
pointerPressure,
|
|
4111
|
-
pointerStrokeSample,
|
|
4112
|
-
pointerStrokeSamples
|
|
3317
|
+
WetGpuEngine
|
|
4113
3318
|
};
|