pixel-data-js 0.27.0 → 0.29.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/README.md +12 -2
- package/dist/index.prod.cjs +2355 -1124
- package/dist/index.prod.cjs.map +1 -1
- package/dist/index.prod.d.ts +558 -424
- package/dist/index.prod.js +2304 -1115
- package/dist/index.prod.js.map +1 -1
- package/package.json +11 -11
- package/src/Algorithm/floodFillSelection.ts +8 -6
- package/src/Algorithm/forEachLinePoint.ts +6 -6
- package/src/{Internal/resample32.ts → Algorithm/resampleUint32Array.ts} +11 -21
- package/src/BlendModes/blend-modes-fast.ts +169 -0
- package/src/BlendModes/blend-modes-perfect.ts +207 -0
- package/src/BlendModes/blend-modes.ts +9 -0
- package/src/Canvas/CanvasFrameRenderer.ts +20 -28
- package/src/Canvas/CanvasPixelDataRenderer.ts +23 -0
- package/src/Canvas/PixelCanvas.ts +2 -7
- package/src/Canvas/ReusableCanvas.ts +4 -12
- package/src/Canvas/_canvas-types.ts +26 -0
- package/src/History/PixelAccumulator.ts +17 -17
- package/src/History/PixelEngineConfig.ts +3 -3
- package/src/History/PixelMutator/mutatorApplyAlphaMask.ts +4 -3
- package/src/History/PixelMutator/mutatorApplyBinaryMask.ts +4 -3
- package/src/History/PixelMutator/mutatorApplyMask.ts +4 -3
- package/src/History/PixelMutator/mutatorBlendAlphaMask.ts +6 -4
- package/src/History/PixelMutator/mutatorBlendBinaryMask.ts +6 -4
- package/src/History/PixelMutator/mutatorBlendColor.ts +2 -2
- package/src/History/PixelMutator/mutatorBlendColorPaintAlphaMask.ts +2 -1
- package/src/History/PixelMutator/mutatorBlendColorPaintBinaryMask.ts +2 -1
- package/src/History/PixelMutator/mutatorBlendColorPaintMask.ts +3 -1
- package/src/History/PixelMutator/mutatorBlendColorPaintRect.ts +3 -3
- package/src/History/PixelMutator/mutatorBlendMask.ts +6 -4
- package/src/History/PixelMutator/mutatorBlendPixelData.ts +5 -4
- package/src/History/PixelMutator/mutatorClear.ts +4 -3
- package/src/History/PixelMutator/mutatorFill.ts +5 -4
- package/src/History/PixelMutator/mutatorFillBinaryMask.ts +2 -1
- package/src/History/PixelMutator/mutatorInvert.ts +2 -2
- package/src/History/PixelMutator.ts +1 -1
- package/src/History/PixelPatchTiles.ts +7 -7
- package/src/History/PixelWriter.ts +12 -63
- package/src/ImageData/ImageDataLike.ts +1 -1
- package/src/ImageData/_ImageData-types.ts +13 -0
- package/src/ImageData/copyImageData.ts +1 -1
- package/src/ImageData/extractImageDataBuffer.ts +3 -2
- package/src/ImageData/imageDataToUint32Array.ts +18 -0
- package/src/ImageData/resampleImageData.ts +3 -3
- package/src/ImageData/resizeImageData.ts +1 -1
- package/src/ImageData/serialization.ts +1 -1
- package/src/ImageData/uInt32ArrayToImageData.ts +1 -1
- package/src/ImageData/writeImageData.ts +2 -2
- package/src/ImageData/writeImageDataBuffer.ts +2 -2
- package/src/IndexedImage/IndexedImage.ts +56 -98
- package/src/IndexedImage/_indexedImage-types.ts +18 -0
- package/src/IndexedImage/getIndexedImageColorCounts.ts +3 -3
- package/src/IndexedImage/indexedImageToAverageColor.ts +1 -1
- package/src/IndexedImage/indexedImageToImageData.ts +4 -6
- package/src/IndexedImage/resampleIndexedImage.ts +7 -15
- package/src/Input/fileToImageData.ts +1 -1
- package/src/Internal/_constants.ts +3 -0
- package/src/Internal/_errors.ts +2 -0
- package/src/Internal/macros.ts +14 -0
- package/src/Mask/AlphaMask.ts +1 -1
- package/src/Mask/BinaryMask/makeBinaryMaskFromAlphaMask.ts +23 -0
- package/src/Mask/BinaryMask/makeBinaryMaskOutline.ts +88 -0
- package/src/Mask/BinaryMask/makeCircleBinaryMaskOutline.ts +104 -0
- package/src/Mask/BinaryMask/makeRectBinaryMaskOutline.ts +34 -0
- package/src/Mask/BinaryMask.ts +1 -1
- package/src/Mask/_mask-types.ts +73 -0
- package/src/Mask/applyBinaryMaskToAlphaMask.ts +2 -1
- package/src/Mask/copyMask.ts +1 -1
- package/src/Mask/extractMask.ts +2 -1
- package/src/Mask/extractMaskBuffer.ts +1 -1
- package/src/Mask/mergeAlphaMasks.ts +6 -3
- package/src/Mask/mergeBinaryMasks.ts +2 -1
- package/src/Mask/setMaskData.ts +1 -1
- package/src/MaskRect/merge2BinaryMaskRects.ts +2 -2
- package/src/MaskRect/mergeBinaryMaskRects.ts +1 -1
- package/src/MaskRect/subtractBinaryMaskRects.ts +1 -1
- package/src/Paint/AlphaMaskPaintBuffer.ts +283 -0
- package/src/Paint/BinaryMaskPaintBuffer.ts +198 -0
- package/src/Paint/{PaintBuffer.ts → ColorPaintBuffer.ts} +95 -77
- package/src/Paint/Commit/AlphaMaskPaintBufferCommitter.ts +26 -0
- package/src/Paint/Commit/AlphaMaskPaintBufferManager.ts +34 -0
- package/src/Paint/Commit/BinaryMaskPaintBufferCommitter.ts +26 -0
- package/src/Paint/Commit/BinaryMaskPaintBufferManager.ts +31 -0
- package/src/Paint/Commit/ColorPaintBufferCommitter.ts +23 -0
- package/src/Paint/Commit/ColorPaintBufferManager.ts +34 -0
- package/src/Paint/Commit/commitColorPaintBuffer.ts +55 -0
- package/src/Paint/Commit/commitMaskPaintBuffer.ts +78 -0
- package/src/Paint/Render/AlphaMaskPaintBufferCanvasRenderer.ts +78 -0
- package/src/Paint/Render/BinaryMaskPaintBufferCanvasRenderer.ts +67 -0
- package/src/Paint/{PaintBufferCanvasRenderer.ts → Render/ColorPaintBufferCanvasRenderer.ts} +13 -14
- package/src/Paint/Render/PaintCursorRenderer.ts +118 -0
- package/src/Paint/_paint-types.ts +22 -0
- package/src/Paint/eachTileInBounds.ts +45 -0
- package/src/Paint/makeCirclePaintMask.ts +74 -0
- package/src/Paint/makePaintMask.ts +5 -2
- package/src/Paint/makeRectFalloffPaintAlphaMask.ts +4 -2
- package/src/PixelData/PixelData.ts +15 -19
- package/src/PixelData/ReusablePixelData.ts +36 -0
- package/src/PixelData/_pixelData-types.ts +17 -0
- package/src/PixelData/applyAlphaMaskToPixelData.ts +80 -43
- package/src/PixelData/applyBinaryMaskToPixelData.ts +10 -8
- package/src/PixelData/applyMaskToPixelData.ts +4 -9
- package/src/PixelData/blendColorPixelData.ts +9 -8
- package/src/PixelData/blendColorPixelDataAlphaMask.ts +9 -7
- package/src/PixelData/blendColorPixelDataBinaryMask.ts +9 -7
- package/src/PixelData/blendColorPixelDataMask.ts +4 -2
- package/src/PixelData/blendColorPixelDataPaintAlphaMask.ts +4 -2
- package/src/PixelData/blendColorPixelDataPaintBinaryMask.ts +4 -2
- package/src/PixelData/blendColorPixelDataPaintMask.ts +5 -2
- package/src/PixelData/blendPixel.ts +6 -5
- package/src/PixelData/blendPixelData.ts +14 -13
- package/src/PixelData/blendPixelDataAlphaMask.ts +15 -13
- package/src/PixelData/blendPixelDataBinaryMask.ts +15 -13
- package/src/PixelData/blendPixelDataMask.ts +5 -3
- package/src/PixelData/blendPixelDataPaintBuffer.ts +5 -4
- package/src/PixelData/clearPixelDataFast.ts +4 -2
- package/src/PixelData/copyPixelData.ts +14 -0
- package/src/PixelData/extractPixelData.ts +8 -7
- package/src/PixelData/extractPixelDataBuffer.ts +9 -8
- package/src/PixelData/fillPixelData.ts +16 -14
- package/src/PixelData/fillPixelDataBinaryMask.ts +10 -8
- package/src/PixelData/fillPixelDataFast.ts +16 -14
- package/src/PixelData/invertPixelData.ts +9 -8
- package/src/PixelData/pixelDataToAlphaMask.ts +9 -8
- package/src/PixelData/reflectPixelData.ts +9 -9
- package/src/PixelData/resamplePixelData.ts +20 -9
- package/src/PixelData/rotatePixelData.ts +8 -7
- package/src/PixelData/uInt32ArrayToPixelData.ts +15 -0
- package/src/PixelData/writePaintBufferToPixelData.ts +5 -5
- package/src/PixelData/writePixelDataBuffer.ts +10 -9
- package/src/Rect/_rect-types.ts +7 -0
- package/src/Rect/getRectsBounds.ts +1 -1
- package/src/Rect/trimMaskRectBounds.ts +2 -1
- package/src/Rect/trimRectBounds.ts +1 -1
- package/src/Tile/MaskTile.ts +40 -0
- package/src/Tile/PixelTile.ts +23 -0
- package/src/{PixelTile/PixelTilePool.ts → Tile/TilePool.ts} +9 -9
- package/src/Tile/_tile-types.ts +33 -0
- package/src/_errors.ts +1 -0
- package/src/_types.ts +2 -118
- package/src/index.ts +57 -21
- package/src/ImageData/imageDataToUInt32Array.ts +0 -13
- package/src/Internal/helpers.ts +0 -5
- package/src/Paint/makeCirclePaintAlphaMask.ts +0 -41
- package/src/Paint/makeCirclePaintBinaryMask.ts +0 -29
- package/src/PixelTile/PixelTile.ts +0 -21
- /package/src/{Internal → Rect}/resolveClipping.ts +0 -0
|
@@ -1,78 +1,60 @@
|
|
|
1
|
-
import type { Color32
|
|
1
|
+
import type { Color32 } from '../_types'
|
|
2
2
|
import { forEachLinePoint } from '../Algorithm/forEachLinePoint'
|
|
3
3
|
import type { PixelEngineConfig } from '../History/PixelEngineConfig'
|
|
4
|
-
import { _macro_paintRectCenterOffset } from '../Internal/
|
|
5
|
-
import type {
|
|
6
|
-
import type { PixelTilePool } from '../PixelTile/PixelTilePool'
|
|
4
|
+
import { _macro_paintRectCenterOffset } from '../Internal/macros'
|
|
5
|
+
import type { Rect } from '../Rect/_rect-types'
|
|
7
6
|
import { trimRectBounds } from '../Rect/trimRectBounds'
|
|
7
|
+
import type { PixelTile } from '../Tile/_tile-types'
|
|
8
|
+
import type { TilePool } from '../Tile/TilePool'
|
|
9
|
+
import type { PaintAlphaMask, PaintBinaryMask } from './_paint-types'
|
|
10
|
+
import { eachTileInBounds } from './eachTileInBounds'
|
|
8
11
|
|
|
9
|
-
export class
|
|
12
|
+
export class ColorPaintBuffer {
|
|
10
13
|
readonly lookup: (PixelTile | undefined)[]
|
|
11
14
|
private readonly scratchBounds: Rect = { x: 0, y: 0, w: 0, h: 0 }
|
|
12
15
|
|
|
13
16
|
constructor(
|
|
14
17
|
readonly config: PixelEngineConfig,
|
|
15
|
-
readonly tilePool:
|
|
18
|
+
readonly tilePool: TilePool<PixelTile>,
|
|
16
19
|
) {
|
|
17
20
|
this.lookup = []
|
|
18
21
|
}
|
|
19
22
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
for (let ty = y1; ty <= y2; ty++) {
|
|
37
|
-
const rowOffset = ty * targetColumns
|
|
38
|
-
const tileTop = ty << tileShift
|
|
39
|
-
|
|
40
|
-
for (let tx = x1; tx <= x2; tx++) {
|
|
41
|
-
const id = rowOffset + tx
|
|
42
|
-
const tile = lookup[id] ?? (lookup[id] = tilePool.getTile(id, tx, ty))
|
|
43
|
-
const tileLeft = tx << tileShift
|
|
44
|
-
|
|
45
|
-
const startX = bounds.x > tileLeft ? bounds.x : tileLeft
|
|
46
|
-
const startY = bounds.y > tileTop ? bounds.y : tileTop
|
|
47
|
-
|
|
48
|
-
const maskEndX = bounds.x + bounds.w
|
|
49
|
-
const tileEndX = tileLeft + tileSize
|
|
50
|
-
const endX = maskEndX < tileEndX ? maskEndX : tileEndX
|
|
51
|
-
|
|
52
|
-
const maskEndY = bounds.y + bounds.h
|
|
53
|
-
const tileEndY = tileTop + tileSize
|
|
54
|
-
const endY = maskEndY < tileEndY ? maskEndY : tileEndY
|
|
55
|
-
|
|
56
|
-
callback(tile, startX, startY, endX - startX, endY - startY)
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
writePaintAlphaMaskStroke(
|
|
23
|
+
paintAlphaMask(
|
|
24
|
+
color: Color32,
|
|
25
|
+
brush: PaintAlphaMask,
|
|
26
|
+
x: number,
|
|
27
|
+
y: number,
|
|
28
|
+
): boolean
|
|
29
|
+
paintAlphaMask(
|
|
30
|
+
color: Color32,
|
|
31
|
+
brush: PaintAlphaMask,
|
|
32
|
+
startX: number,
|
|
33
|
+
startY: number,
|
|
34
|
+
endX: number,
|
|
35
|
+
endY: number,
|
|
36
|
+
): boolean
|
|
37
|
+
paintAlphaMask(
|
|
62
38
|
color: Color32,
|
|
63
39
|
brush: PaintAlphaMask,
|
|
64
40
|
x0: number,
|
|
65
41
|
y0: number,
|
|
66
|
-
x1: number,
|
|
67
|
-
y1: number,
|
|
42
|
+
x1: number = x0,
|
|
43
|
+
y1: number = y0,
|
|
68
44
|
): boolean {
|
|
69
45
|
const cA = color >>> 24
|
|
70
46
|
if (cA === 0) return false
|
|
71
47
|
|
|
72
|
-
const
|
|
48
|
+
const scratch = this.scratchBounds
|
|
49
|
+
const lookup = this.lookup
|
|
50
|
+
const tilePool = this.tilePool
|
|
51
|
+
const config = this.config
|
|
52
|
+
const tileShift = config.tileShift
|
|
53
|
+
const tileMask = config.tileMask
|
|
54
|
+
const target = config.target
|
|
55
|
+
|
|
73
56
|
const { w: bW, h: bH, data: bD, centerOffsetX, centerOffsetY } = brush
|
|
74
57
|
const cRGB = color & 0x00ffffff
|
|
75
|
-
const scratch = this.scratchBounds
|
|
76
58
|
|
|
77
59
|
let changed = false
|
|
78
60
|
|
|
@@ -85,15 +67,15 @@ export class PaintBuffer {
|
|
|
85
67
|
topLeftY,
|
|
86
68
|
bW,
|
|
87
69
|
bH,
|
|
88
|
-
target.
|
|
89
|
-
target.
|
|
70
|
+
target.w,
|
|
71
|
+
target.h,
|
|
90
72
|
scratch,
|
|
91
73
|
)
|
|
92
74
|
|
|
93
75
|
if (scratch.w <= 0 || scratch.h <= 0) return
|
|
94
76
|
|
|
95
|
-
|
|
96
|
-
const d32 = tile.
|
|
77
|
+
eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
78
|
+
const d32 = tile.data
|
|
97
79
|
let tileChanged = false
|
|
98
80
|
|
|
99
81
|
for (let i = 0; i < bH_t; i++) {
|
|
@@ -127,20 +109,40 @@ export class PaintBuffer {
|
|
|
127
109
|
return changed
|
|
128
110
|
}
|
|
129
111
|
|
|
130
|
-
|
|
112
|
+
paintBinaryMask(
|
|
113
|
+
color: Color32,
|
|
114
|
+
brush: PaintBinaryMask,
|
|
115
|
+
x: number,
|
|
116
|
+
y: number,
|
|
117
|
+
): boolean
|
|
118
|
+
paintBinaryMask(
|
|
119
|
+
color: Color32,
|
|
120
|
+
brush: PaintBinaryMask,
|
|
121
|
+
startX: number,
|
|
122
|
+
startY: number,
|
|
123
|
+
endX: number,
|
|
124
|
+
endY: number,
|
|
125
|
+
): boolean
|
|
126
|
+
paintBinaryMask(
|
|
131
127
|
color: Color32,
|
|
132
128
|
brush: PaintBinaryMask,
|
|
133
129
|
x0: number,
|
|
134
130
|
y0: number,
|
|
135
|
-
x1: number,
|
|
136
|
-
y1: number,
|
|
131
|
+
x1: number = x0,
|
|
132
|
+
y1: number = y0,
|
|
137
133
|
): boolean {
|
|
138
134
|
const alphaIsZero = (color >>> 24) === 0
|
|
139
135
|
if (alphaIsZero) return false
|
|
140
136
|
|
|
141
|
-
const { tileShift, tileMask, target } = this.config
|
|
142
|
-
const { w: bW, h: bH, data: bD, centerOffsetX, centerOffsetY } = brush
|
|
143
137
|
const scratch = this.scratchBounds
|
|
138
|
+
const lookup = this.lookup
|
|
139
|
+
const tilePool = this.tilePool
|
|
140
|
+
const config = this.config
|
|
141
|
+
const tileShift = config.tileShift
|
|
142
|
+
const tileMask = config.tileMask
|
|
143
|
+
const target = config.target
|
|
144
|
+
|
|
145
|
+
const { w: bW, h: bH, data: bD, centerOffsetX, centerOffsetY } = brush
|
|
144
146
|
let changed = false
|
|
145
147
|
|
|
146
148
|
forEachLinePoint(x0, y0, x1, y1, (px, py) => {
|
|
@@ -152,15 +154,15 @@ export class PaintBuffer {
|
|
|
152
154
|
topLeftY,
|
|
153
155
|
bW,
|
|
154
156
|
bH,
|
|
155
|
-
target.
|
|
156
|
-
target.
|
|
157
|
+
target.w,
|
|
158
|
+
target.h,
|
|
157
159
|
scratch,
|
|
158
160
|
)
|
|
159
161
|
|
|
160
162
|
if (scratch.w <= 0 || scratch.h <= 0) return
|
|
161
163
|
|
|
162
|
-
|
|
163
|
-
const d32 = tile.
|
|
164
|
+
eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
165
|
+
const d32 = tile.data
|
|
164
166
|
let tileChanged = false
|
|
165
167
|
|
|
166
168
|
for (let i = 0; i < bH_t; i++) {
|
|
@@ -187,26 +189,44 @@ export class PaintBuffer {
|
|
|
187
189
|
return changed
|
|
188
190
|
}
|
|
189
191
|
|
|
190
|
-
|
|
192
|
+
paintRect(
|
|
193
|
+
color: Color32,
|
|
194
|
+
brushWidth: number,
|
|
195
|
+
brushHeight: number,
|
|
196
|
+
x: number,
|
|
197
|
+
y: number,
|
|
198
|
+
): boolean
|
|
199
|
+
paintRect(
|
|
200
|
+
color: Color32,
|
|
201
|
+
brushWidth: number,
|
|
202
|
+
brushHeight: number,
|
|
203
|
+
startX: number,
|
|
204
|
+
startY: number,
|
|
205
|
+
endX: number,
|
|
206
|
+
endY: number,
|
|
207
|
+
): boolean
|
|
208
|
+
paintRect(
|
|
191
209
|
color: Color32,
|
|
192
210
|
brushWidth: number,
|
|
193
211
|
brushHeight: number,
|
|
194
212
|
x0: number,
|
|
195
213
|
y0: number,
|
|
196
|
-
x1: number,
|
|
197
|
-
y1: number,
|
|
214
|
+
x1: number = x0,
|
|
215
|
+
y1: number = y0,
|
|
198
216
|
): boolean {
|
|
199
217
|
const alphaIsZero = (color >>> 24) === 0
|
|
200
218
|
if (alphaIsZero) return false
|
|
201
219
|
|
|
220
|
+
const scratch = this.scratchBounds
|
|
221
|
+
const lookup = this.lookup
|
|
222
|
+
const tilePool = this.tilePool
|
|
202
223
|
const config = this.config
|
|
203
224
|
const tileShift = config.tileShift
|
|
204
225
|
const tileMask = config.tileMask
|
|
205
226
|
const target = config.target
|
|
206
|
-
const scratch = this.scratchBounds
|
|
207
227
|
|
|
208
|
-
const centerOffsetX =
|
|
209
|
-
const centerOffsetY =
|
|
228
|
+
const centerOffsetX = _macro_paintRectCenterOffset(brushWidth)
|
|
229
|
+
const centerOffsetY = _macro_paintRectCenterOffset(brushHeight)
|
|
210
230
|
|
|
211
231
|
let changed = false
|
|
212
232
|
|
|
@@ -224,17 +244,15 @@ export class PaintBuffer {
|
|
|
224
244
|
topLeftY,
|
|
225
245
|
brushWidth,
|
|
226
246
|
brushHeight,
|
|
227
|
-
target.
|
|
228
|
-
target.
|
|
247
|
+
target.w,
|
|
248
|
+
target.h,
|
|
229
249
|
scratch,
|
|
230
250
|
)
|
|
231
251
|
|
|
232
252
|
if (scratch.w <= 0 || scratch.h <= 0) return
|
|
233
253
|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
(tile, bX, bY, bW_t, bH_t) => {
|
|
237
|
-
const d32 = tile.data32
|
|
254
|
+
eachTileInBounds(config, lookup, tilePool, scratch, (tile, bX, bY, bW_t, bH_t) => {
|
|
255
|
+
const d32 = tile.data
|
|
238
256
|
let tileChanged = false
|
|
239
257
|
|
|
240
258
|
for (let i = 0; i < bH_t; i++) {
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Color32 } from '../../_types'
|
|
2
|
+
import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
|
|
3
|
+
import type { PixelAccumulator } from '../../History/PixelAccumulator'
|
|
4
|
+
import { blendColorPixelDataAlphaMask } from '../../PixelData/blendColorPixelDataAlphaMask'
|
|
5
|
+
import type { AlphaMaskPaintBuffer } from '../AlphaMaskPaintBuffer'
|
|
6
|
+
import { commitMaskPaintBuffer } from './commitMaskPaintBuffer'
|
|
7
|
+
|
|
8
|
+
export function makeAlphaMaskPaintBufferCommitter(
|
|
9
|
+
accumulator: PixelAccumulator,
|
|
10
|
+
paintBuffer: AlphaMaskPaintBuffer,
|
|
11
|
+
) {
|
|
12
|
+
return function commitAlphaMaskPaintBufferToAccumulator(
|
|
13
|
+
color: Color32,
|
|
14
|
+
alpha = 255,
|
|
15
|
+
blendFn = sourceOverPerfect,
|
|
16
|
+
) {
|
|
17
|
+
return commitMaskPaintBuffer(
|
|
18
|
+
accumulator,
|
|
19
|
+
paintBuffer,
|
|
20
|
+
color,
|
|
21
|
+
alpha,
|
|
22
|
+
blendFn,
|
|
23
|
+
blendColorPixelDataAlphaMask,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CanvasObjectFactory } from '../../Canvas/_canvas-types'
|
|
2
|
+
import type { PixelWriter } from '../../History/PixelWriter'
|
|
3
|
+
import { DEFAULT_CANVAS_FACTORY } from '../../Internal/_constants'
|
|
4
|
+
import { makeAlphaMaskTile } from '../../Tile/MaskTile'
|
|
5
|
+
import { TilePool } from '../../Tile/TilePool'
|
|
6
|
+
import { AlphaMaskPaintBuffer } from '../AlphaMaskPaintBuffer'
|
|
7
|
+
import { makeAlphaMaskPaintBufferCanvasRenderer } from '../Render/AlphaMaskPaintBufferCanvasRenderer'
|
|
8
|
+
import { makeAlphaMaskPaintBufferCommitter } from './AlphaMaskPaintBufferCommitter'
|
|
9
|
+
|
|
10
|
+
export type AlphaMaskPaintBufferManager =
|
|
11
|
+
Pick<AlphaMaskPaintBuffer, 'paintAlphaMask' | 'paintBinaryMask' | 'paintRect'>
|
|
12
|
+
& {
|
|
13
|
+
commit: ReturnType<typeof makeAlphaMaskPaintBufferCommitter>
|
|
14
|
+
draw: ReturnType<typeof makeAlphaMaskPaintBufferCanvasRenderer>
|
|
15
|
+
clear: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function makeAlphaMaskPaintBufferManager(
|
|
19
|
+
writer: Pick<PixelWriter<any>, 'accumulator' | 'config'>,
|
|
20
|
+
canvasFactory: CanvasObjectFactory<any> = DEFAULT_CANVAS_FACTORY,
|
|
21
|
+
): AlphaMaskPaintBufferManager {
|
|
22
|
+
const pool = new TilePool(writer.config, makeAlphaMaskTile)
|
|
23
|
+
const buffer = new AlphaMaskPaintBuffer(writer.config, pool)
|
|
24
|
+
const draw = makeAlphaMaskPaintBufferCanvasRenderer(buffer, canvasFactory)
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
clear: buffer.clear.bind(buffer),
|
|
28
|
+
paintRect: buffer.paintRect.bind(buffer),
|
|
29
|
+
paintAlphaMask: buffer.paintAlphaMask.bind(buffer),
|
|
30
|
+
paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
|
|
31
|
+
commit: makeAlphaMaskPaintBufferCommitter(writer.accumulator, buffer),
|
|
32
|
+
draw,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Color32 } from '../../_types'
|
|
2
|
+
import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
|
|
3
|
+
import type { PixelAccumulator } from '../../History/PixelAccumulator'
|
|
4
|
+
import { blendColorPixelDataBinaryMask } from '../../PixelData/blendColorPixelDataBinaryMask'
|
|
5
|
+
import type { BinaryMaskPaintBuffer } from '../BinaryMaskPaintBuffer'
|
|
6
|
+
import { commitMaskPaintBuffer } from './commitMaskPaintBuffer'
|
|
7
|
+
|
|
8
|
+
export function makeBinaryMaskPaintBufferCommitter(
|
|
9
|
+
accumulator: PixelAccumulator,
|
|
10
|
+
paintBuffer: BinaryMaskPaintBuffer,
|
|
11
|
+
) {
|
|
12
|
+
return function commitBinaryMaskPaintBufferToAccumulator(
|
|
13
|
+
color: Color32,
|
|
14
|
+
alpha = 255,
|
|
15
|
+
blendFn = sourceOverPerfect,
|
|
16
|
+
) {
|
|
17
|
+
return commitMaskPaintBuffer(
|
|
18
|
+
accumulator,
|
|
19
|
+
paintBuffer,
|
|
20
|
+
color,
|
|
21
|
+
alpha,
|
|
22
|
+
blendFn,
|
|
23
|
+
blendColorPixelDataBinaryMask,
|
|
24
|
+
)
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { CanvasObjectFactory } from '../../Canvas/_canvas-types'
|
|
2
|
+
import type { PixelWriter } from '../../History/PixelWriter'
|
|
3
|
+
import { DEFAULT_CANVAS_FACTORY } from '../../Internal/_constants'
|
|
4
|
+
import { makeBinaryMaskTile } from '../../Tile/MaskTile'
|
|
5
|
+
import { TilePool } from '../../Tile/TilePool'
|
|
6
|
+
import { BinaryMaskPaintBuffer } from '../BinaryMaskPaintBuffer'
|
|
7
|
+
import { makeBinaryMaskPaintBufferCanvasRenderer } from '../Render/BinaryMaskPaintBufferCanvasRenderer'
|
|
8
|
+
import { makeBinaryMaskPaintBufferCommitter } from './BinaryMaskPaintBufferCommitter'
|
|
9
|
+
|
|
10
|
+
export type BinaryMaskPaintBufferManager = Pick<BinaryMaskPaintBuffer, 'paintBinaryMask' | 'paintRect'> & {
|
|
11
|
+
commit: ReturnType<typeof makeBinaryMaskPaintBufferCommitter>
|
|
12
|
+
draw: ReturnType<typeof makeBinaryMaskPaintBufferCanvasRenderer>
|
|
13
|
+
clear: () => void
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function makeBinaryMaskPaintBufferManager(
|
|
17
|
+
writer: Pick<PixelWriter<any>, 'accumulator' | 'config'>,
|
|
18
|
+
canvasFactory: CanvasObjectFactory<any> = DEFAULT_CANVAS_FACTORY,
|
|
19
|
+
): BinaryMaskPaintBufferManager {
|
|
20
|
+
const pool = new TilePool(writer.config, makeBinaryMaskTile)
|
|
21
|
+
const buffer = new BinaryMaskPaintBuffer(writer.config, pool)
|
|
22
|
+
const draw = makeBinaryMaskPaintBufferCanvasRenderer(buffer, canvasFactory)
|
|
23
|
+
|
|
24
|
+
return {
|
|
25
|
+
clear: buffer.clear.bind(buffer),
|
|
26
|
+
paintRect: buffer.paintRect.bind(buffer),
|
|
27
|
+
paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
|
|
28
|
+
commit: makeBinaryMaskPaintBufferCommitter(writer.accumulator, buffer),
|
|
29
|
+
draw,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
|
|
2
|
+
import type { PixelAccumulator } from '../../History/PixelAccumulator'
|
|
3
|
+
import { blendPixelData } from '../../PixelData/blendPixelData'
|
|
4
|
+
import type { ColorPaintBuffer } from '../ColorPaintBuffer'
|
|
5
|
+
import { commitColorPaintBuffer } from './commitColorPaintBuffer'
|
|
6
|
+
|
|
7
|
+
export function makeColorPaintBufferCommitter(
|
|
8
|
+
accumulator: PixelAccumulator,
|
|
9
|
+
paintBuffer: ColorPaintBuffer,
|
|
10
|
+
) {
|
|
11
|
+
return function commitColorPaintBufferToAccumulator(
|
|
12
|
+
alpha = 255,
|
|
13
|
+
blendFn = sourceOverPerfect,
|
|
14
|
+
) {
|
|
15
|
+
return commitColorPaintBuffer(
|
|
16
|
+
accumulator,
|
|
17
|
+
paintBuffer,
|
|
18
|
+
alpha,
|
|
19
|
+
blendFn,
|
|
20
|
+
blendPixelData,
|
|
21
|
+
)
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { CanvasObjectFactory } from '../../Canvas/_canvas-types'
|
|
2
|
+
import type { PixelWriter } from '../../History/PixelWriter'
|
|
3
|
+
import { DEFAULT_CANVAS_FACTORY } from '../../Internal/_constants'
|
|
4
|
+
import { makePixelTile } from '../../Tile/PixelTile'
|
|
5
|
+
import { TilePool } from '../../Tile/TilePool'
|
|
6
|
+
import { ColorPaintBuffer } from '../ColorPaintBuffer'
|
|
7
|
+
import { makeColorPaintBufferCanvasRenderer } from '../Render/ColorPaintBufferCanvasRenderer'
|
|
8
|
+
import { makeColorPaintBufferCommitter } from './ColorPaintBufferCommitter'
|
|
9
|
+
|
|
10
|
+
export type ColorPaintBufferManager =
|
|
11
|
+
Pick<ColorPaintBuffer, 'paintAlphaMask' | 'paintBinaryMask' | 'paintRect'>
|
|
12
|
+
& {
|
|
13
|
+
commit: ReturnType<typeof makeColorPaintBufferCommitter>
|
|
14
|
+
draw: ReturnType<typeof makeColorPaintBufferCanvasRenderer>
|
|
15
|
+
clear: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function makeColorPaintBufferManager(
|
|
19
|
+
writer: Pick<PixelWriter<any>, 'accumulator' | 'config'>,
|
|
20
|
+
canvasFactory: CanvasObjectFactory<any> = DEFAULT_CANVAS_FACTORY,
|
|
21
|
+
): ColorPaintBufferManager {
|
|
22
|
+
const pool = new TilePool(writer.config, makePixelTile)
|
|
23
|
+
const buffer = new ColorPaintBuffer(writer.config, pool)
|
|
24
|
+
const draw = makeColorPaintBufferCanvasRenderer(buffer, canvasFactory)
|
|
25
|
+
|
|
26
|
+
return {
|
|
27
|
+
clear: buffer.clear.bind(buffer),
|
|
28
|
+
paintRect: buffer.paintRect.bind(buffer),
|
|
29
|
+
paintAlphaMask: buffer.paintAlphaMask.bind(buffer),
|
|
30
|
+
paintBinaryMask: buffer.paintBinaryMask.bind(buffer),
|
|
31
|
+
commit: makeColorPaintBufferCommitter(writer.accumulator, buffer),
|
|
32
|
+
draw,
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
|
|
2
|
+
import type { PixelAccumulator } from '../../History/PixelAccumulator'
|
|
3
|
+
import { blendPixelData } from '../../PixelData/blendPixelData'
|
|
4
|
+
import type { ColorPaintBuffer } from '../ColorPaintBuffer'
|
|
5
|
+
|
|
6
|
+
const SCRATCH_OPTS = {
|
|
7
|
+
alpha: 255,
|
|
8
|
+
blendFn: sourceOverPerfect,
|
|
9
|
+
x: 0,
|
|
10
|
+
y: 0,
|
|
11
|
+
w: 0,
|
|
12
|
+
h: 0,
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function commitColorPaintBuffer(
|
|
16
|
+
accumulator: PixelAccumulator,
|
|
17
|
+
paintBuffer: ColorPaintBuffer,
|
|
18
|
+
alpha = 255,
|
|
19
|
+
blendFn = sourceOverPerfect,
|
|
20
|
+
blendPixelDataFn = blendPixelData,
|
|
21
|
+
) {
|
|
22
|
+
const config = accumulator.config
|
|
23
|
+
const tileShift = config.tileShift
|
|
24
|
+
const lookup = paintBuffer.lookup
|
|
25
|
+
|
|
26
|
+
SCRATCH_OPTS.alpha = alpha
|
|
27
|
+
SCRATCH_OPTS.blendFn = blendFn
|
|
28
|
+
|
|
29
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
30
|
+
const tile = lookup[i]
|
|
31
|
+
|
|
32
|
+
if (tile) {
|
|
33
|
+
const didChange = accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty)
|
|
34
|
+
|
|
35
|
+
const dx = tile.tx << tileShift
|
|
36
|
+
const dy = tile.ty << tileShift
|
|
37
|
+
|
|
38
|
+
SCRATCH_OPTS.x = dx
|
|
39
|
+
SCRATCH_OPTS.y = dy
|
|
40
|
+
SCRATCH_OPTS.w = tile.w
|
|
41
|
+
SCRATCH_OPTS.h = tile.h
|
|
42
|
+
|
|
43
|
+
didChange(
|
|
44
|
+
blendPixelDataFn(
|
|
45
|
+
config.target,
|
|
46
|
+
tile,
|
|
47
|
+
SCRATCH_OPTS,
|
|
48
|
+
),
|
|
49
|
+
)
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
paintBuffer.clear()
|
|
54
|
+
}
|
|
55
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { type Color32 } from '../../_types'
|
|
2
|
+
import { sourceOverPerfect } from '../../BlendModes/blend-modes-perfect'
|
|
3
|
+
import type { PixelAccumulator } from '../../History/PixelAccumulator'
|
|
4
|
+
import { blendColorPixelDataAlphaMask } from '../../PixelData/blendColorPixelDataAlphaMask'
|
|
5
|
+
import { blendColorPixelDataBinaryMask } from '../../PixelData/blendColorPixelDataBinaryMask'
|
|
6
|
+
import type { AlphaMaskPaintBuffer } from '../AlphaMaskPaintBuffer'
|
|
7
|
+
import type { BinaryMaskPaintBuffer } from '../BinaryMaskPaintBuffer'
|
|
8
|
+
|
|
9
|
+
const SCRATCH_OPTS = {
|
|
10
|
+
alpha: 255,
|
|
11
|
+
blendFn: sourceOverPerfect,
|
|
12
|
+
x: 0,
|
|
13
|
+
y: 0,
|
|
14
|
+
w: 0,
|
|
15
|
+
h: 0,
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export function commitMaskPaintBuffer(
|
|
19
|
+
accumulator: PixelAccumulator,
|
|
20
|
+
paintBuffer: BinaryMaskPaintBuffer,
|
|
21
|
+
color: Color32,
|
|
22
|
+
alpha: number | undefined,
|
|
23
|
+
blendFn: typeof sourceOverPerfect | undefined,
|
|
24
|
+
blendColorPixelDataMaskFn: typeof blendColorPixelDataBinaryMask,
|
|
25
|
+
): void
|
|
26
|
+
|
|
27
|
+
export function commitMaskPaintBuffer(
|
|
28
|
+
accumulator: PixelAccumulator,
|
|
29
|
+
paintBuffer: AlphaMaskPaintBuffer,
|
|
30
|
+
color: Color32,
|
|
31
|
+
alpha: number | undefined,
|
|
32
|
+
blendFn: typeof sourceOverPerfect | undefined,
|
|
33
|
+
blendColorPixelDataMaskFn: typeof blendColorPixelDataAlphaMask,
|
|
34
|
+
): void
|
|
35
|
+
|
|
36
|
+
export function commitMaskPaintBuffer(
|
|
37
|
+
accumulator: PixelAccumulator,
|
|
38
|
+
paintBuffer: any,
|
|
39
|
+
color: Color32,
|
|
40
|
+
alpha = 255,
|
|
41
|
+
blendFn = sourceOverPerfect,
|
|
42
|
+
blendColorPixelDataMaskFn: any,
|
|
43
|
+
) {
|
|
44
|
+
const config = accumulator.config
|
|
45
|
+
const tileShift = config.tileShift
|
|
46
|
+
const lookup = paintBuffer.lookup
|
|
47
|
+
|
|
48
|
+
SCRATCH_OPTS.alpha = alpha
|
|
49
|
+
SCRATCH_OPTS.blendFn = blendFn
|
|
50
|
+
|
|
51
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
52
|
+
const tile = lookup[i]
|
|
53
|
+
|
|
54
|
+
if (tile) {
|
|
55
|
+
const didChange = accumulator.storeTileBeforeState(tile.id, tile.tx, tile.ty)
|
|
56
|
+
|
|
57
|
+
const dx = tile.tx << tileShift
|
|
58
|
+
const dy = tile.ty << tileShift
|
|
59
|
+
|
|
60
|
+
SCRATCH_OPTS.x = dx
|
|
61
|
+
SCRATCH_OPTS.y = dy
|
|
62
|
+
SCRATCH_OPTS.w = tile.w
|
|
63
|
+
SCRATCH_OPTS.h = tile.h
|
|
64
|
+
|
|
65
|
+
didChange(
|
|
66
|
+
blendColorPixelDataMaskFn(
|
|
67
|
+
config.target,
|
|
68
|
+
color,
|
|
69
|
+
tile,
|
|
70
|
+
SCRATCH_OPTS,
|
|
71
|
+
),
|
|
72
|
+
)
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
paintBuffer.clear()
|
|
77
|
+
}
|
|
78
|
+
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import type { Color32 } from '../../_types'
|
|
2
|
+
import type { CanvasObjectFactory } from '../../Canvas/_canvas-types'
|
|
3
|
+
import { DEFAULT_CANVAS_FACTORY } from '../../Internal/_constants'
|
|
4
|
+
import { CANVAS_CTX_FAILED } from '../../Internal/_errors'
|
|
5
|
+
import { makePixelData } from '../../PixelData/PixelData'
|
|
6
|
+
import type { AlphaMaskPaintBuffer } from '../AlphaMaskPaintBuffer'
|
|
7
|
+
|
|
8
|
+
export type AlphaMaskPaintBufferCanvasRenderer = ReturnType<typeof makeAlphaMaskPaintBufferCanvasRenderer>
|
|
9
|
+
|
|
10
|
+
export function makeAlphaMaskPaintBufferCanvasRenderer(
|
|
11
|
+
paintBuffer: AlphaMaskPaintBuffer,
|
|
12
|
+
canvasFactory: CanvasObjectFactory<any> = DEFAULT_CANVAS_FACTORY,
|
|
13
|
+
) {
|
|
14
|
+
const config = paintBuffer.config
|
|
15
|
+
const tileSize = config.tileSize
|
|
16
|
+
const tileShift = config.tileShift
|
|
17
|
+
const tileArea = config.tileArea
|
|
18
|
+
const lookup = paintBuffer.lookup
|
|
19
|
+
|
|
20
|
+
const canvas = canvasFactory(tileSize, tileSize)
|
|
21
|
+
const ctx = canvas.getContext('2d')
|
|
22
|
+
if (!ctx) throw new Error(CANVAS_CTX_FAILED)
|
|
23
|
+
ctx.imageSmoothingEnabled = false
|
|
24
|
+
|
|
25
|
+
const bridge = makePixelData(new ImageData(tileSize, tileSize))
|
|
26
|
+
const view32 = bridge.data
|
|
27
|
+
|
|
28
|
+
return function drawPaintBuffer(
|
|
29
|
+
targetCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D,
|
|
30
|
+
color: Color32,
|
|
31
|
+
alpha = 255,
|
|
32
|
+
compOperation: GlobalCompositeOperation = 'source-over',
|
|
33
|
+
): void {
|
|
34
|
+
if (alpha === 0) return
|
|
35
|
+
|
|
36
|
+
const baseSrcAlpha = (color >>> 24)
|
|
37
|
+
const colorRGB = color & 0x00ffffff
|
|
38
|
+
|
|
39
|
+
if (baseSrcAlpha === 0) return
|
|
40
|
+
|
|
41
|
+
targetCtx.globalAlpha = alpha / 255
|
|
42
|
+
targetCtx.globalCompositeOperation = compOperation
|
|
43
|
+
|
|
44
|
+
for (let i = 0; i < lookup.length; i++) {
|
|
45
|
+
const tile = lookup[i]
|
|
46
|
+
|
|
47
|
+
if (tile) {
|
|
48
|
+
const data8 = tile.data
|
|
49
|
+
view32.fill(0)
|
|
50
|
+
|
|
51
|
+
for (let p = 0; p < tileArea; p++) {
|
|
52
|
+
const maskA = data8[p]
|
|
53
|
+
if (maskA === 0) continue
|
|
54
|
+
|
|
55
|
+
// If mask is solid, the final pixel is just the unmodified color
|
|
56
|
+
if (maskA === 255) {
|
|
57
|
+
view32[p] = color
|
|
58
|
+
} else {
|
|
59
|
+
// Otherwise, blend the color's inherent alpha with the mask's alpha
|
|
60
|
+
const t = baseSrcAlpha * maskA + 128
|
|
61
|
+
const finalA = (t + (t >> 8)) >> 8
|
|
62
|
+
|
|
63
|
+
view32[p] = ((colorRGB | (finalA << 24)) >>> 0) as Color32
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const dx = tile.tx << tileShift
|
|
68
|
+
const dy = tile.ty << tileShift
|
|
69
|
+
|
|
70
|
+
ctx.putImageData(bridge.imageData, 0, 0)
|
|
71
|
+
targetCtx.drawImage(canvas, dx, dy)
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
targetCtx.globalAlpha = 1
|
|
76
|
+
targetCtx.globalCompositeOperation = 'source-over'
|
|
77
|
+
}
|
|
78
|
+
}
|