/
CanvasContextSystem.ts
228 lines (196 loc) · 7.36 KB
/
CanvasContextSystem.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
import { BaseTexture, BLEND_MODES, Color, extensions, ExtensionType, Matrix, SCALE_MODES } from '@pixi/core';
import { mapCanvasBlendModesToPixi } from './utils/mapCanvasBlendModesToPixi';
import type { ColorSource, ExtensionMetadata, ICanvasRenderingContext2D, ISystem } from '@pixi/core';
import type { CanvasRenderer } from './CanvasRenderer';
const tempMatrix = new Matrix();
/**
* Rendering context for all browsers. This includes platform-specific
* properties that are not included in the spec for CanvasRenderingContext2D
*/
export interface CrossPlatformCanvasRenderingContext2D extends ICanvasRenderingContext2D
{
webkitImageSmoothingEnabled: boolean;
mozImageSmoothingEnabled: boolean;
oImageSmoothingEnabled: boolean;
msImageSmoothingEnabled: boolean;
}
/*
* Different browsers support different smoothing property names
* this is the list of all platform props.
*/
export type SmoothingEnabledProperties =
'imageSmoothingEnabled' |
'webkitImageSmoothingEnabled' |
'mozImageSmoothingEnabled' |
'oImageSmoothingEnabled' |
'msImageSmoothingEnabled';
/**
* System that manages the canvas `2d` contexts
* @memberof PIXI
*/
export class CanvasContextSystem implements ISystem
{
/** @ignore */
static extension: ExtensionMetadata = {
type: ExtensionType.CanvasRendererSystem,
name: 'canvasContext',
};
/** A reference to the current renderer */
private renderer: CanvasRenderer;
/** The root canvas 2d context that everything is drawn with. */
public rootContext: CrossPlatformCanvasRenderingContext2D;
/** The currently active canvas 2d context (could change with renderTextures) */
public activeContext: CrossPlatformCanvasRenderingContext2D;
public activeResolution = 1;
/** The canvas property used to set the canvas smoothing property. */
public smoothProperty: SmoothingEnabledProperties = 'imageSmoothingEnabled';
/** Tracks the blend modes useful for this renderer. */
public readonly blendModes: string[] = mapCanvasBlendModesToPixi();
_activeBlendMode: BLEND_MODES = null;
/** Projection transform, passed in render() stored here */
_projTransform: Matrix = null;
/** @private */
_outerBlend = false;
/** @param renderer - A reference to the current renderer */
constructor(renderer: CanvasRenderer)
{
this.renderer = renderer;
}
/** initiates the system */
init(): void
{
const alpha = this.renderer.background.alpha < 1;
this.rootContext = this.renderer.view.getContext('2d', { alpha }) as
CrossPlatformCanvasRenderingContext2D;
this.activeContext = this.rootContext;
if (!this.rootContext.imageSmoothingEnabled)
{
const rc = this.rootContext;
if (rc.webkitImageSmoothingEnabled)
{
this.smoothProperty = 'webkitImageSmoothingEnabled';
}
else if (rc.mozImageSmoothingEnabled)
{
this.smoothProperty = 'mozImageSmoothingEnabled';
}
else if (rc.oImageSmoothingEnabled)
{
this.smoothProperty = 'oImageSmoothingEnabled';
}
else if (rc.msImageSmoothingEnabled)
{
this.smoothProperty = 'msImageSmoothingEnabled';
}
}
}
/**
* Sets matrix of context.
* called only from render() methods
* takes care about resolution
* @param transform - world matrix of current element
* @param roundPixels - whether to round (tx,ty) coords
* @param localResolution - If specified, used instead of `renderer.resolution` for local scaling
*/
setContextTransform(transform: Matrix, roundPixels?: boolean, localResolution?: number): void
{
let mat = transform;
const proj = this._projTransform;
const contextResolution = this.activeResolution;
localResolution = localResolution || contextResolution;
if (proj)
{
mat = tempMatrix;
mat.copyFrom(transform);
mat.prepend(proj);
}
if (roundPixels)
{
this.activeContext.setTransform(
mat.a * localResolution,
mat.b * localResolution,
mat.c * localResolution,
mat.d * localResolution,
(mat.tx * contextResolution) | 0,
(mat.ty * contextResolution) | 0
);
}
else
{
this.activeContext.setTransform(
mat.a * localResolution,
mat.b * localResolution,
mat.c * localResolution,
mat.d * localResolution,
mat.tx * contextResolution,
mat.ty * contextResolution
);
}
}
/**
* Clear the canvas of renderer.
* @param {string} [clearColor] - Clear the canvas with this color, except the canvas is transparent.
* @param {number} [alpha] - Alpha to apply to the background fill color.
*/
public clear(clearColor?: ColorSource, alpha?: number): void
{
const { activeContext: context, renderer } = this;
const fillColor = clearColor
? Color.shared.setValue(clearColor)
: this.renderer.background.backgroundColor;
context.clearRect(0, 0, renderer.width, renderer.height);
if (clearColor)
{
context.globalAlpha = alpha ?? this.renderer.background.alpha;
context.fillStyle = fillColor.toHex();
context.fillRect(0, 0, renderer.width, renderer.height);
context.globalAlpha = 1;
}
}
/**
* Sets the blend mode of the renderer.
* @param {number} blendMode - See {@link PIXI.BLEND_MODES} for valid values.
* @param {boolean} [readyForOuterBlend=false] - Some blendModes are dangerous, they affect outer space of sprite.
* Pass `true` only if you are ready to use them.
*/
setBlendMode(blendMode: BLEND_MODES, readyForOuterBlend?: boolean): void
{
const outerBlend = blendMode === BLEND_MODES.SRC_IN
|| blendMode === BLEND_MODES.SRC_OUT
|| blendMode === BLEND_MODES.DST_IN
|| blendMode === BLEND_MODES.DST_ATOP;
if (!readyForOuterBlend && outerBlend)
{
blendMode = BLEND_MODES.NORMAL;
}
if (this._activeBlendMode === blendMode)
{
return;
}
this._activeBlendMode = blendMode;
this._outerBlend = outerBlend;
this.activeContext.globalCompositeOperation = this.blendModes[blendMode] as GlobalCompositeOperation;
}
resize(): void
{
// reset the scale mode.. oddly this seems to be reset when the canvas is resized.
// surely a browser bug?? Let PixiJS fix that for you..
if (this.smoothProperty)
{
this.rootContext[this.smoothProperty] = (BaseTexture.defaultOptions.scaleMode === SCALE_MODES.LINEAR);
}
}
/** Checks if blend mode has changed. */
invalidateBlendMode(): void
{
this._activeBlendMode = this.blendModes.indexOf(this.activeContext.globalCompositeOperation);
}
public destroy(): void
{
this.renderer = null;
this.rootContext = null;
this.activeContext = null;
this.smoothProperty = null;
}
}
extensions.add(CanvasContextSystem);