@vpmedia/phaser 1.0.1 → 1.0.2
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/phaser.cjs.LICENSE.txt +1 -1
- package/dist/phaser.js.LICENSE.txt +1 -1
- package/package.json +2 -3
- package/src/index.js +99 -0
- package/src/phaser/core/animation.js +355 -0
- package/src/phaser/core/animation_manager.js +238 -0
- package/src/phaser/core/animation_parser.js +130 -0
- package/src/phaser/core/array_set.js +108 -0
- package/src/phaser/core/cache.js +558 -0
- package/src/phaser/core/const.js +106 -0
- package/src/phaser/core/device.js +67 -0
- package/src/phaser/core/device_util.js +386 -0
- package/src/phaser/core/dom.js +207 -0
- package/src/phaser/core/event_manager.js +243 -0
- package/src/phaser/core/factory.js +74 -0
- package/src/phaser/core/frame.js +75 -0
- package/src/phaser/core/frame_data.js +84 -0
- package/src/phaser/core/frame_util.js +31 -0
- package/src/phaser/core/game.js +412 -0
- package/src/phaser/core/input.js +401 -0
- package/src/phaser/core/input_button.js +102 -0
- package/src/phaser/core/input_handler.js +687 -0
- package/src/phaser/core/input_mouse.js +289 -0
- package/src/phaser/core/input_mspointer.js +197 -0
- package/src/phaser/core/input_pointer.js +427 -0
- package/src/phaser/core/input_touch.js +157 -0
- package/src/phaser/core/loader.js +946 -0
- package/src/phaser/core/loader_parser.js +105 -0
- package/src/phaser/core/raf.js +46 -0
- package/src/phaser/core/raf_fb.js +75 -0
- package/src/phaser/core/raf_to.js +34 -0
- package/src/phaser/core/scale_manager.js +806 -0
- package/src/phaser/core/scene.js +66 -0
- package/src/phaser/core/scene_manager.js +310 -0
- package/src/phaser/core/signal.js +175 -0
- package/src/phaser/core/signal_binding.js +69 -0
- package/src/phaser/core/sound.js +538 -0
- package/src/phaser/core/sound_manager.js +365 -0
- package/src/phaser/core/stage.js +108 -0
- package/src/phaser/core/time.js +203 -0
- package/src/phaser/core/timer.js +276 -0
- package/src/phaser/core/timer_event.js +21 -0
- package/src/phaser/core/tween.js +329 -0
- package/src/phaser/core/tween_data.js +258 -0
- package/src/phaser/core/tween_easing.js +316 -0
- package/src/phaser/core/tween_manager.js +185 -0
- package/src/phaser/core/world.js +18 -0
- package/src/phaser/display/bitmap_text.js +322 -0
- package/src/phaser/display/button.js +194 -0
- package/src/phaser/display/canvas/buffer.js +36 -0
- package/src/phaser/display/canvas/graphics.js +227 -0
- package/src/phaser/display/canvas/masker.js +39 -0
- package/src/phaser/display/canvas/pool.js +121 -0
- package/src/phaser/display/canvas/renderer.js +123 -0
- package/src/phaser/display/canvas/tinter.js +141 -0
- package/src/phaser/display/canvas/util.js +151 -0
- package/src/phaser/display/display_object.js +597 -0
- package/src/phaser/display/graphics.js +723 -0
- package/src/phaser/display/graphics_data.js +27 -0
- package/src/phaser/display/graphics_data_util.js +14 -0
- package/src/phaser/display/group.js +227 -0
- package/src/phaser/display/image.js +288 -0
- package/src/phaser/display/sprite_batch.js +15 -0
- package/src/phaser/display/sprite_util.js +248 -0
- package/src/phaser/display/text.js +1089 -0
- package/src/phaser/display/webgl/abstract_filter.js +25 -0
- package/src/phaser/display/webgl/base_texture.js +68 -0
- package/src/phaser/display/webgl/blend_manager.js +35 -0
- package/src/phaser/display/webgl/earcut.js +647 -0
- package/src/phaser/display/webgl/earcut_node.js +28 -0
- package/src/phaser/display/webgl/fast_sprite_batch.js +242 -0
- package/src/phaser/display/webgl/filter_manager.js +46 -0
- package/src/phaser/display/webgl/filter_texture.js +61 -0
- package/src/phaser/display/webgl/graphics.js +618 -0
- package/src/phaser/display/webgl/graphics_data.js +42 -0
- package/src/phaser/display/webgl/mask_manager.js +36 -0
- package/src/phaser/display/webgl/render_texture.js +81 -0
- package/src/phaser/display/webgl/renderer.js +234 -0
- package/src/phaser/display/webgl/shader/complex.js +74 -0
- package/src/phaser/display/webgl/shader/fast.js +97 -0
- package/src/phaser/display/webgl/shader/normal.js +225 -0
- package/src/phaser/display/webgl/shader/primitive.js +72 -0
- package/src/phaser/display/webgl/shader/strip.js +77 -0
- package/src/phaser/display/webgl/shader_manager.js +89 -0
- package/src/phaser/display/webgl/sprite_batch.js +320 -0
- package/src/phaser/display/webgl/stencil_manager.js +170 -0
- package/src/phaser/display/webgl/texture.js +117 -0
- package/src/phaser/display/webgl/texture_util.js +32 -0
- package/src/phaser/display/webgl/util.js +74 -0
- package/src/phaser/geom/circle.js +186 -0
- package/src/phaser/geom/ellipse.js +65 -0
- package/src/phaser/geom/line.js +190 -0
- package/src/phaser/geom/matrix.js +147 -0
- package/src/phaser/geom/point.js +164 -0
- package/src/phaser/geom/polygon.js +141 -0
- package/src/phaser/geom/rectangle.js +306 -0
- package/src/phaser/geom/rounded_rectangle.js +36 -0
- package/src/phaser/geom/util/circle.js +115 -0
- package/src/phaser/geom/util/ellipse.js +30 -0
- package/src/phaser/geom/util/line.js +130 -0
- package/src/phaser/geom/util/matrix.js +48 -0
- package/src/phaser/geom/util/point.js +276 -0
- package/src/phaser/geom/util/polygon.js +24 -0
- package/src/phaser/geom/util/rectangle.js +212 -0
- package/src/phaser/geom/util/rounded_rectangle.js +28 -0
- package/src/phaser/util/math.js +279 -0
- package/src/phaser/util/string.js +26 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Andras Csizmadia <andras@vpmedia.hu>
|
|
3
|
+
* @author Richard Davey <rich@photonstorm.com>
|
|
4
|
+
* @author Mat Groves http://matgroves.com/ @Doormat23
|
|
5
|
+
* @copyright Copyright (c) 2018-present Richard Davey, Photon Storm Ltd., Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)
|
|
6
|
+
*/
|
|
7
|
+
import { create, removeByCanvas } from './pool';
|
|
8
|
+
|
|
9
|
+
export default class {
|
|
10
|
+
|
|
11
|
+
constructor(width, height) {
|
|
12
|
+
this.width = width;
|
|
13
|
+
this.height = height;
|
|
14
|
+
this.canvas = create(this, this.width, this.height);
|
|
15
|
+
this.context = this.canvas.getContext('2d');
|
|
16
|
+
this.canvas.width = width;
|
|
17
|
+
this.canvas.height = height;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
clear() {
|
|
21
|
+
this.context.setTransform(1, 0, 0, 1, 0, 0);
|
|
22
|
+
this.context.clearRect(0, 0, this.width, this.height);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
resize(width, height) {
|
|
26
|
+
this.width = width;
|
|
27
|
+
this.height = height;
|
|
28
|
+
this.canvas.width = width;
|
|
29
|
+
this.canvas.height = height;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
destroy() {
|
|
33
|
+
removeByCanvas(this.canvas);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
}
|
|
@@ -0,0 +1,227 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Andras Csizmadia <andras@vpmedia.hu>
|
|
3
|
+
* @author Richard Davey <rich@photonstorm.com>
|
|
4
|
+
* @author Mat Groves http://matgroves.com/ @Doormat23
|
|
5
|
+
* @copyright Copyright (c) 2018-present Richard Davey, Photon Storm Ltd., Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)
|
|
6
|
+
*/
|
|
7
|
+
import { GEOM_POLYGON, GEOM_RECTANGLE, GEOM_CIRCLE, GEOM_ELLIPSE, GEOM_ROUNDED_RECTANGLE } from '../../core/const';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param graphics
|
|
12
|
+
*/
|
|
13
|
+
export function updateGraphicsTint(graphics) {
|
|
14
|
+
if (graphics.tint === 0xFFFFFF) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const tintR = (graphics.tint >> 16 & 0xFF) / 255;
|
|
18
|
+
const tintG = (graphics.tint >> 8 & 0xFF) / 255;
|
|
19
|
+
const tintB = (graphics.tint & 0xFF) / 255;
|
|
20
|
+
for (let i = 0; i < graphics.graphicsData.length; i += 1) {
|
|
21
|
+
const data = graphics.graphicsData[i];
|
|
22
|
+
const fillColor = data.fillColor | 0;
|
|
23
|
+
const lineColor = data.lineColor | 0;
|
|
24
|
+
data._fillTint = (((fillColor >> 16 & 0xFF) / 255 * tintR * 255 << 16) + ((fillColor >> 8 & 0xFF) / 255 * tintG * 255 << 8) + (fillColor & 0xFF) / 255 * tintB * 255);
|
|
25
|
+
data._lineTint = (((lineColor >> 16 & 0xFF) / 255 * tintR * 255 << 16) + ((lineColor >> 8 & 0xFF) / 255 * tintG * 255 << 8) + (lineColor & 0xFF) / 255 * tintB * 255);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
*
|
|
31
|
+
* @param graphics
|
|
32
|
+
* @param context
|
|
33
|
+
*/
|
|
34
|
+
export function renderGraphics(graphics, context) {
|
|
35
|
+
const worldAlpha = graphics.worldAlpha;
|
|
36
|
+
if (graphics.dirty) {
|
|
37
|
+
updateGraphicsTint(graphics);
|
|
38
|
+
graphics.dirty = false;
|
|
39
|
+
}
|
|
40
|
+
for (let i = 0; i < graphics.graphicsData.length; i += 1) {
|
|
41
|
+
const data = graphics.graphicsData[i];
|
|
42
|
+
const shape = data.shape;
|
|
43
|
+
const fillColor = data._fillTint;
|
|
44
|
+
const lineColor = data._lineTint;
|
|
45
|
+
context.lineWidth = data.lineWidth;
|
|
46
|
+
if (data.type === GEOM_POLYGON) {
|
|
47
|
+
context.beginPath();
|
|
48
|
+
const points = shape.points;
|
|
49
|
+
context.moveTo(points[0], points[1]);
|
|
50
|
+
for (let j = 1; j < points.length / 2; j += 1) {
|
|
51
|
+
context.lineTo(points[j * 2], points[j * 2 + 1]);
|
|
52
|
+
}
|
|
53
|
+
if (shape.closed) {
|
|
54
|
+
context.lineTo(points[0], points[1]);
|
|
55
|
+
}
|
|
56
|
+
// if the first and last point are the same close the path - much neater :)
|
|
57
|
+
if (points[0] === points[points.length - 2] && points[1] === points[points.length - 1]) {
|
|
58
|
+
context.closePath();
|
|
59
|
+
}
|
|
60
|
+
if (data.fill) {
|
|
61
|
+
context.globalAlpha = data.fillAlpha * worldAlpha;
|
|
62
|
+
context.fillStyle = '#' + ('00000' + (fillColor | 0).toString(16)).substr(-6);
|
|
63
|
+
context.fill();
|
|
64
|
+
}
|
|
65
|
+
if (data.lineWidth) {
|
|
66
|
+
context.globalAlpha = data.lineAlpha * worldAlpha;
|
|
67
|
+
context.strokeStyle = '#' + ('00000' + (lineColor | 0).toString(16)).substr(-6);
|
|
68
|
+
context.stroke();
|
|
69
|
+
}
|
|
70
|
+
} else if (data.type === GEOM_RECTANGLE) {
|
|
71
|
+
if (data.fillColor || data.fillColor === 0) {
|
|
72
|
+
context.globalAlpha = data.fillAlpha * worldAlpha;
|
|
73
|
+
context.fillStyle = '#' + ('00000' + (fillColor | 0).toString(16)).substr(-6);
|
|
74
|
+
context.fillRect(shape.x, shape.y, shape.width, shape.height);
|
|
75
|
+
}
|
|
76
|
+
if (data.lineWidth) {
|
|
77
|
+
context.globalAlpha = data.lineAlpha * worldAlpha;
|
|
78
|
+
context.strokeStyle = '#' + ('00000' + (lineColor | 0).toString(16)).substr(-6);
|
|
79
|
+
context.strokeRect(shape.x, shape.y, shape.width, shape.height);
|
|
80
|
+
}
|
|
81
|
+
} else if (data.type === GEOM_CIRCLE) {
|
|
82
|
+
context.beginPath();
|
|
83
|
+
context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI);
|
|
84
|
+
context.closePath();
|
|
85
|
+
if (data.fill) {
|
|
86
|
+
context.globalAlpha = data.fillAlpha * worldAlpha;
|
|
87
|
+
context.fillStyle = '#' + ('00000' + (fillColor | 0).toString(16)).substr(-6);
|
|
88
|
+
context.fill();
|
|
89
|
+
}
|
|
90
|
+
if (data.lineWidth) {
|
|
91
|
+
context.globalAlpha = data.lineAlpha * worldAlpha;
|
|
92
|
+
context.strokeStyle = '#' + ('00000' + (lineColor | 0).toString(16)).substr(-6);
|
|
93
|
+
context.stroke();
|
|
94
|
+
}
|
|
95
|
+
} else if (data.type === GEOM_ELLIPSE) {
|
|
96
|
+
// ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
|
|
97
|
+
const w = shape.width * 2;
|
|
98
|
+
const h = shape.height * 2;
|
|
99
|
+
const x = shape.x - w / 2;
|
|
100
|
+
const y = shape.y - h / 2;
|
|
101
|
+
context.beginPath();
|
|
102
|
+
const kappa = 0.5522848;
|
|
103
|
+
const ox = (w / 2) * kappa; // control point offset horizontal
|
|
104
|
+
const oy = (h / 2) * kappa; // control point offset vertical
|
|
105
|
+
const xe = x + w; // x-end
|
|
106
|
+
const ye = y + h; // y-end
|
|
107
|
+
const xm = x + w / 2; // x-middle
|
|
108
|
+
const ym = y + h / 2; // y-middle
|
|
109
|
+
context.moveTo(x, ym);
|
|
110
|
+
context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
|
|
111
|
+
context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
|
|
112
|
+
context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
|
|
113
|
+
context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
|
|
114
|
+
context.closePath();
|
|
115
|
+
if (data.fill) {
|
|
116
|
+
context.globalAlpha = data.fillAlpha * worldAlpha;
|
|
117
|
+
context.fillStyle = '#' + ('00000' + (fillColor | 0).toString(16)).substr(-6);
|
|
118
|
+
context.fill();
|
|
119
|
+
}
|
|
120
|
+
if (data.lineWidth) {
|
|
121
|
+
context.globalAlpha = data.lineAlpha * worldAlpha;
|
|
122
|
+
context.strokeStyle = '#' + ('00000' + (lineColor | 0).toString(16)).substr(-6);
|
|
123
|
+
context.stroke();
|
|
124
|
+
}
|
|
125
|
+
} else if (data.type === GEOM_ROUNDED_RECTANGLE) {
|
|
126
|
+
const rx = shape.x;
|
|
127
|
+
const ry = shape.y;
|
|
128
|
+
const width = shape.width;
|
|
129
|
+
const height = shape.height;
|
|
130
|
+
let radius = shape.radius;
|
|
131
|
+
const maxRadius = Math.min(width, height) / 2 | 0;
|
|
132
|
+
radius = radius > maxRadius ? maxRadius : radius;
|
|
133
|
+
context.beginPath();
|
|
134
|
+
context.moveTo(rx, ry + radius);
|
|
135
|
+
context.lineTo(rx, ry + height - radius);
|
|
136
|
+
context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height);
|
|
137
|
+
context.lineTo(rx + width - radius, ry + height);
|
|
138
|
+
context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius);
|
|
139
|
+
context.lineTo(rx + width, ry + radius);
|
|
140
|
+
context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry);
|
|
141
|
+
context.lineTo(rx + radius, ry);
|
|
142
|
+
context.quadraticCurveTo(rx, ry, rx, ry + radius);
|
|
143
|
+
context.closePath();
|
|
144
|
+
if (data.fillColor || data.fillColor === 0) {
|
|
145
|
+
context.globalAlpha = data.fillAlpha * worldAlpha;
|
|
146
|
+
context.fillStyle = '#' + ('00000' + (fillColor | 0).toString(16)).substr(-6);
|
|
147
|
+
context.fill();
|
|
148
|
+
}
|
|
149
|
+
if (data.lineWidth) {
|
|
150
|
+
context.globalAlpha = data.lineAlpha * worldAlpha;
|
|
151
|
+
context.strokeStyle = '#' + ('00000' + (lineColor | 0).toString(16)).substr(-6);
|
|
152
|
+
context.stroke();
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
*
|
|
160
|
+
* @param graphics
|
|
161
|
+
* @param context
|
|
162
|
+
*/
|
|
163
|
+
export function renderGraphicsMask(graphics, context) {
|
|
164
|
+
const len = graphics.graphicsData.length;
|
|
165
|
+
if (len === 0) {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
context.beginPath();
|
|
169
|
+
for (let i = 0; i < len; i += 1) {
|
|
170
|
+
const data = graphics.graphicsData[i];
|
|
171
|
+
const shape = data.shape;
|
|
172
|
+
if (data.type === GEOM_POLYGON) {
|
|
173
|
+
const points = shape.points;
|
|
174
|
+
context.moveTo(points[0], points[1]);
|
|
175
|
+
for (let j = 1; j < points.length / 2; j += 1) {
|
|
176
|
+
context.lineTo(points[j * 2], points[j * 2 + 1]);
|
|
177
|
+
}
|
|
178
|
+
// if the first and last point are the same close the path - much neater :)
|
|
179
|
+
if (points[0] === points[points.length - 2] && points[1] === points[points.length - 1]) {
|
|
180
|
+
context.closePath();
|
|
181
|
+
}
|
|
182
|
+
} else if (data.type === GEOM_RECTANGLE) {
|
|
183
|
+
context.rect(shape.x, shape.y, shape.width, shape.height);
|
|
184
|
+
context.closePath();
|
|
185
|
+
} else if (data.type === GEOM_CIRCLE) {
|
|
186
|
+
context.arc(shape.x, shape.y, shape.radius, 0, 2 * Math.PI);
|
|
187
|
+
context.closePath();
|
|
188
|
+
} else if (data.type === GEOM_ELLIPSE) {
|
|
189
|
+
// ellipse code taken from: http://stackoverflow.com/questions/2172798/how-to-draw-an-oval-in-html5-canvas
|
|
190
|
+
const w = shape.width * 2;
|
|
191
|
+
const h = shape.height * 2;
|
|
192
|
+
const x = shape.x - w / 2;
|
|
193
|
+
const y = shape.y - h / 2;
|
|
194
|
+
const kappa = 0.5522848;
|
|
195
|
+
const ox = (w / 2) * kappa; // control point offset horizontal
|
|
196
|
+
const oy = (h / 2) * kappa; // control point offset vertical
|
|
197
|
+
const xe = x + w; // x-end
|
|
198
|
+
const ye = y + h; // y-end
|
|
199
|
+
const xm = x + w / 2; // x-middle
|
|
200
|
+
const ym = y + h / 2; // y-middle
|
|
201
|
+
context.moveTo(x, ym);
|
|
202
|
+
context.bezierCurveTo(x, ym - oy, xm - ox, y, xm, y);
|
|
203
|
+
context.bezierCurveTo(xm + ox, y, xe, ym - oy, xe, ym);
|
|
204
|
+
context.bezierCurveTo(xe, ym + oy, xm + ox, ye, xm, ye);
|
|
205
|
+
context.bezierCurveTo(xm - ox, ye, x, ym + oy, x, ym);
|
|
206
|
+
context.closePath();
|
|
207
|
+
} else if (data.type === GEOM_ROUNDED_RECTANGLE) {
|
|
208
|
+
const rx = shape.x;
|
|
209
|
+
const ry = shape.y;
|
|
210
|
+
const width = shape.width;
|
|
211
|
+
const height = shape.height;
|
|
212
|
+
let radius = shape.radius;
|
|
213
|
+
const maxRadius = Math.min(width, height) / 2 | 0;
|
|
214
|
+
radius = radius > maxRadius ? maxRadius : radius;
|
|
215
|
+
context.moveTo(rx, ry + radius);
|
|
216
|
+
context.lineTo(rx, ry + height - radius);
|
|
217
|
+
context.quadraticCurveTo(rx, ry + height, rx + radius, ry + height);
|
|
218
|
+
context.lineTo(rx + width - radius, ry + height);
|
|
219
|
+
context.quadraticCurveTo(rx + width, ry + height, rx + width, ry + height - radius);
|
|
220
|
+
context.lineTo(rx + width, ry + radius);
|
|
221
|
+
context.quadraticCurveTo(rx + width, ry, rx + width - radius, ry);
|
|
222
|
+
context.lineTo(rx + radius, ry);
|
|
223
|
+
context.quadraticCurveTo(rx, ry, rx, ry + radius);
|
|
224
|
+
context.closePath();
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Andras Csizmadia <andras@vpmedia.hu>
|
|
3
|
+
* @author Richard Davey <rich@photonstorm.com>
|
|
4
|
+
* @author Mat Groves http://matgroves.com/ @Doormat23
|
|
5
|
+
* @copyright Copyright (c) 2018-present Richard Davey, Photon Storm Ltd., Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)
|
|
6
|
+
*/
|
|
7
|
+
import { renderGraphicsMask } from './graphics';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
*
|
|
11
|
+
* @param maskData
|
|
12
|
+
* @param renderSession
|
|
13
|
+
*/
|
|
14
|
+
export function pushMask(maskData, renderSession) {
|
|
15
|
+
const context = renderSession.context;
|
|
16
|
+
context.save();
|
|
17
|
+
const cacheAlpha = maskData.alpha;
|
|
18
|
+
const transform = maskData.worldTransform;
|
|
19
|
+
const resolution = renderSession.resolution;
|
|
20
|
+
context.setTransform(
|
|
21
|
+
transform.a * resolution,
|
|
22
|
+
transform.b * resolution,
|
|
23
|
+
transform.c * resolution,
|
|
24
|
+
transform.d * resolution,
|
|
25
|
+
transform.tx * resolution,
|
|
26
|
+
transform.ty * resolution,
|
|
27
|
+
);
|
|
28
|
+
renderGraphicsMask(maskData, context);
|
|
29
|
+
context.clip();
|
|
30
|
+
maskData.worldAlpha = cacheAlpha;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
*
|
|
35
|
+
* @param renderSession
|
|
36
|
+
*/
|
|
37
|
+
export function popMask(renderSession) {
|
|
38
|
+
renderSession.context.restore();
|
|
39
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Andras Csizmadia <andras@vpmedia.hu>
|
|
3
|
+
* @author Richard Davey <rich@photonstorm.com>
|
|
4
|
+
* @author Mat Groves http://matgroves.com/ @Doormat23
|
|
5
|
+
* @copyright Copyright (c) 2018-present Richard Davey, Photon Storm Ltd., Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
*
|
|
10
|
+
*/
|
|
11
|
+
export function getPool() {
|
|
12
|
+
if (!window.PhaserRegistry) {
|
|
13
|
+
window.PhaserRegistry = {};
|
|
14
|
+
}
|
|
15
|
+
if (!window.PhaserRegistry.CANVAS_POOL) {
|
|
16
|
+
window.PhaserRegistry.CANVAS_POOL = [];
|
|
17
|
+
}
|
|
18
|
+
return window.PhaserRegistry.CANVAS_POOL;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
*
|
|
23
|
+
*/
|
|
24
|
+
export function getFirst() {
|
|
25
|
+
const pool = getPool();
|
|
26
|
+
for (let i = 0; i < pool.length; i += 1) {
|
|
27
|
+
if (!pool[i].parent) {
|
|
28
|
+
return i;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return -1;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
*
|
|
36
|
+
* @param parent
|
|
37
|
+
*/
|
|
38
|
+
export function remove(parent) {
|
|
39
|
+
const pool = getPool();
|
|
40
|
+
for (let i = 0; i < pool.length; i += 1) {
|
|
41
|
+
if (pool[i].parent === parent) {
|
|
42
|
+
pool[i].parent = null;
|
|
43
|
+
pool[i].canvas.width = 1;
|
|
44
|
+
pool[i].canvas.height = 1;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
*
|
|
51
|
+
* @param canvas
|
|
52
|
+
*/
|
|
53
|
+
export function removeByCanvas(canvas) {
|
|
54
|
+
const pool = getPool();
|
|
55
|
+
for (let i = 0; i < pool.length; i += 1) {
|
|
56
|
+
if (pool[i].canvas === canvas) {
|
|
57
|
+
pool[i].parent = null;
|
|
58
|
+
pool[i].canvas.width = 1;
|
|
59
|
+
pool[i].canvas.height = 1;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
*
|
|
66
|
+
*/
|
|
67
|
+
export function getTotal() {
|
|
68
|
+
const pool = getPool();
|
|
69
|
+
let c = 0;
|
|
70
|
+
for (let i = 0; i < pool.length; i += 1) {
|
|
71
|
+
if (pool[i].parent) {
|
|
72
|
+
c += 1;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return c;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
*
|
|
80
|
+
*/
|
|
81
|
+
export function getFree() {
|
|
82
|
+
const pool = getPool();
|
|
83
|
+
let c = 0;
|
|
84
|
+
for (let i = 0; i < pool.length; i += 1) {
|
|
85
|
+
if (!pool[i].parent) {
|
|
86
|
+
c += 1;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
return c;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
*
|
|
94
|
+
* @param parent
|
|
95
|
+
* @param width
|
|
96
|
+
* @param height
|
|
97
|
+
*/
|
|
98
|
+
export function create(parent, width, height) {
|
|
99
|
+
if (parent === undefined) {
|
|
100
|
+
console.warn('Created CanvasPool element with undefined parent.');
|
|
101
|
+
}
|
|
102
|
+
const idx = getFirst();
|
|
103
|
+
const pool = getPool();
|
|
104
|
+
let canvas;
|
|
105
|
+
if (idx === -1) {
|
|
106
|
+
const container = {
|
|
107
|
+
parent,
|
|
108
|
+
canvas: document.createElement('canvas'),
|
|
109
|
+
};
|
|
110
|
+
pool.push(container);
|
|
111
|
+
canvas = container.canvas;
|
|
112
|
+
} else {
|
|
113
|
+
pool[idx].parent = parent;
|
|
114
|
+
canvas = pool[idx].canvas;
|
|
115
|
+
}
|
|
116
|
+
if (width !== undefined) {
|
|
117
|
+
canvas.width = width;
|
|
118
|
+
canvas.height = height;
|
|
119
|
+
}
|
|
120
|
+
return canvas;
|
|
121
|
+
}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Andras Csizmadia <andras@vpmedia.hu>
|
|
3
|
+
* @author Richard Davey <rich@photonstorm.com>
|
|
4
|
+
* @author Mat Groves http://matgroves.com/ @Doormat23
|
|
5
|
+
* @copyright Copyright (c) 2018-present Richard Davey, Photon Storm Ltd., Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)
|
|
6
|
+
*/
|
|
7
|
+
import { RENDER_CANVAS, SCALE_LINEAR, BLEND_NORMAL, BLEND_ADD, BLEND_MULTIPLY, BLEND_SCREEN, BLEND_OVERLAY, BLEND_DARKEN, BLEND_LIGHTEN, BLEND_COLOR_DODGE, BLEND_COLOR_BURN, BLEND_HARD_LIGHT, BLEND_SOFT_LIGHT, BLEND_DIFFERENCE, BLEND_EXCLUSION, BLEND_HUE, BLEND_SATURATION, BLEND_COLOR, BLEND_LUMINOSITY } from '../../core/const';
|
|
8
|
+
import { getSmoothingPrefix } from './util';
|
|
9
|
+
import { detectCapabilities } from './tinter';
|
|
10
|
+
import * as CanvasMaskManager from './masker';
|
|
11
|
+
|
|
12
|
+
export default class {
|
|
13
|
+
|
|
14
|
+
constructor(game) {
|
|
15
|
+
detectCapabilities();
|
|
16
|
+
this.type = RENDER_CANVAS;
|
|
17
|
+
this.resolution = game.config.resolution;
|
|
18
|
+
this.clearBeforeRender = game.config.clearBeforeRender;
|
|
19
|
+
this.transparent = game.config.transparent;
|
|
20
|
+
this.autoResize = false;
|
|
21
|
+
this.width = game.width * this.resolution;
|
|
22
|
+
this.height = game.height * this.resolution;
|
|
23
|
+
this.view = game.canvas;
|
|
24
|
+
this.context = this.view.getContext('2d', { alpha: this.transparent });
|
|
25
|
+
if (!this.context) {
|
|
26
|
+
throw new Error('Error creating Canvas 2D context.');
|
|
27
|
+
}
|
|
28
|
+
this.refresh = true;
|
|
29
|
+
this.count = 0;
|
|
30
|
+
this.renderSession = {
|
|
31
|
+
context: this.context,
|
|
32
|
+
maskManager: CanvasMaskManager,
|
|
33
|
+
scaleMode: null,
|
|
34
|
+
smoothProperty: getSmoothingPrefix(this.context),
|
|
35
|
+
roundPixels: false,
|
|
36
|
+
};
|
|
37
|
+
this.mapBlendModes();
|
|
38
|
+
this.resize(this.width, this.height);
|
|
39
|
+
window.PhaserRegistry.DEFAULT_RENDERER = this;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
render(root) {
|
|
43
|
+
if (!this.context) {
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
this.context.setTransform(1, 0, 0, 1, 0, 0);
|
|
47
|
+
this.context.globalAlpha = 1;
|
|
48
|
+
this.renderSession.currentBlendMode = 0;
|
|
49
|
+
this.renderSession.shakeX = 0;
|
|
50
|
+
this.renderSession.shakeY = 0;
|
|
51
|
+
this.context.globalCompositeOperation = 'source-over';
|
|
52
|
+
if (navigator.isCocoonJS && this.view.screencanvas) {
|
|
53
|
+
this.context.fillStyle = 'black';
|
|
54
|
+
this.context.clear();
|
|
55
|
+
}
|
|
56
|
+
if (this.clearBeforeRender) {
|
|
57
|
+
if (this.transparent) {
|
|
58
|
+
this.context.clearRect(0, 0, this.width, this.height);
|
|
59
|
+
} else if (root._bgColor) {
|
|
60
|
+
this.context.fillStyle = root._bgColor.rgba;
|
|
61
|
+
this.context.fillRect(0, 0, this.width, this.height);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
this.renderDisplayObject(root);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
destroy(removeView = true) {
|
|
68
|
+
if (removeView && this.view.parent) {
|
|
69
|
+
this.view.parent.removeChild(this.view);
|
|
70
|
+
}
|
|
71
|
+
this.view = null;
|
|
72
|
+
this.context = null;
|
|
73
|
+
this.renderSession = null;
|
|
74
|
+
window.PhaserRegistry.DEFAULT_RENDERER = null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
resize(width, height) {
|
|
78
|
+
this.width = width * this.resolution;
|
|
79
|
+
this.height = height * this.resolution;
|
|
80
|
+
this.view.width = this.width;
|
|
81
|
+
this.view.height = this.height;
|
|
82
|
+
if (this.autoResize) {
|
|
83
|
+
this.view.style.width = this.width / this.resolution + 'px';
|
|
84
|
+
this.view.style.height = this.height / this.resolution + 'px';
|
|
85
|
+
}
|
|
86
|
+
if (this.renderSession.smoothProperty) {
|
|
87
|
+
this.context[this.renderSession.smoothProperty] = (this.renderSession.scaleMode === SCALE_LINEAR);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
renderDisplayObject(displayObject, context, matrix) {
|
|
92
|
+
this.renderSession.context = context || this.context;
|
|
93
|
+
this.renderSession.resolution = this.resolution;
|
|
94
|
+
displayObject.renderCanvas(this.renderSession, matrix);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
mapBlendModes() {
|
|
98
|
+
if (window.PhaserRegistry.blendModesCanvas) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const b = [];
|
|
102
|
+
const useNew = window.PhaserRegistry.CAN_CANVAS_USE_MULTIPLY;
|
|
103
|
+
b[BLEND_NORMAL] = 'source-over';
|
|
104
|
+
b[BLEND_ADD] = 'lighter';
|
|
105
|
+
b[BLEND_MULTIPLY] = (useNew) ? 'multiply' : 'source-over';
|
|
106
|
+
b[BLEND_SCREEN] = (useNew) ? 'screen' : 'source-over';
|
|
107
|
+
b[BLEND_OVERLAY] = (useNew) ? 'overlay' : 'source-over';
|
|
108
|
+
b[BLEND_DARKEN] = (useNew) ? 'darken' : 'source-over';
|
|
109
|
+
b[BLEND_LIGHTEN] = (useNew) ? 'lighten' : 'source-over';
|
|
110
|
+
b[BLEND_COLOR_DODGE] = (useNew) ? 'color-dodge' : 'source-over';
|
|
111
|
+
b[BLEND_COLOR_BURN] = (useNew) ? 'color-burn' : 'source-over';
|
|
112
|
+
b[BLEND_HARD_LIGHT] = (useNew) ? 'hard-light' : 'source-over';
|
|
113
|
+
b[BLEND_SOFT_LIGHT] = (useNew) ? 'soft-light' : 'source-over';
|
|
114
|
+
b[BLEND_DIFFERENCE] = (useNew) ? 'difference' : 'source-over';
|
|
115
|
+
b[BLEND_EXCLUSION] = (useNew) ? 'exclusion' : 'source-over';
|
|
116
|
+
b[BLEND_HUE] = (useNew) ? 'hue' : 'source-over';
|
|
117
|
+
b[BLEND_SATURATION] = (useNew) ? 'saturation' : 'source-over';
|
|
118
|
+
b[BLEND_COLOR] = (useNew) ? 'color' : 'source-over';
|
|
119
|
+
b[BLEND_LUMINOSITY] = (useNew) ? 'luminosity' : 'source-over';
|
|
120
|
+
window.PhaserRegistry.blendModesCanvas = b;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @author Andras Csizmadia <andras@vpmedia.hu>
|
|
3
|
+
* @author Richard Davey <rich@photonstorm.com>
|
|
4
|
+
* @author Mat Groves http://matgroves.com/ @Doormat23
|
|
5
|
+
* @copyright Copyright (c) 2018-present Richard Davey, Photon Storm Ltd., Andras Csizmadia <andras@vpmedia.hu> (www.vpmedia.hu)
|
|
6
|
+
*/
|
|
7
|
+
import CanvasBuffer from './buffer';
|
|
8
|
+
import { create, removeByCanvas } from './pool';
|
|
9
|
+
import { hex2rgb } from '../../util/math';
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
*
|
|
13
|
+
* @param sprite
|
|
14
|
+
* @param color
|
|
15
|
+
*/
|
|
16
|
+
export function getTintedTexture(sprite, color) {
|
|
17
|
+
const canvas = sprite.tintedTexture || create('CanvasTinter');
|
|
18
|
+
window.PhaserRegistry.CANVAS_TINT_METHOD(sprite.texture, color, canvas);
|
|
19
|
+
return canvas;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
*
|
|
24
|
+
* @param texture
|
|
25
|
+
* @param color
|
|
26
|
+
* @param canvas
|
|
27
|
+
*/
|
|
28
|
+
export function tintWithMultiply(texture, color, canvas) {
|
|
29
|
+
const context = canvas.getContext('2d');
|
|
30
|
+
const crop = texture.crop;
|
|
31
|
+
if (canvas.width !== crop.width || canvas.height !== crop.height) {
|
|
32
|
+
canvas.width = crop.width;
|
|
33
|
+
canvas.height = crop.height;
|
|
34
|
+
}
|
|
35
|
+
context.clearRect(0, 0, crop.width, crop.height);
|
|
36
|
+
context.fillStyle = '#' + ('00000' + (color | 0).toString(16)).substr(-6);
|
|
37
|
+
context.fillRect(0, 0, crop.width, crop.height);
|
|
38
|
+
context.globalCompositeOperation = 'multiply';
|
|
39
|
+
context.drawImage(texture.baseTexture.source, crop.x, crop.y, crop.width, crop.height, 0, 0, crop.width, crop.height);
|
|
40
|
+
context.globalCompositeOperation = 'destination-atop';
|
|
41
|
+
context.drawImage(texture.baseTexture.source, crop.x, crop.y, crop.width, crop.height, 0, 0, crop.width, crop.height);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
*
|
|
46
|
+
* @param texture
|
|
47
|
+
* @param color
|
|
48
|
+
* @param canvas
|
|
49
|
+
*/
|
|
50
|
+
export function tintWithPerPixel(texture, color, canvas) {
|
|
51
|
+
const context = canvas.getContext('2d');
|
|
52
|
+
const crop = texture.crop;
|
|
53
|
+
canvas.width = crop.width;
|
|
54
|
+
canvas.height = crop.height;
|
|
55
|
+
context.globalCompositeOperation = 'copy';
|
|
56
|
+
context.drawImage(texture.baseTexture.source, crop.x, crop.y, crop.width, crop.height, 0, 0, crop.width, crop.height);
|
|
57
|
+
const rgbValues = hex2rgb(color);
|
|
58
|
+
const r = rgbValues[0];
|
|
59
|
+
const g = rgbValues[1];
|
|
60
|
+
const b = rgbValues[2];
|
|
61
|
+
const pixelData = context.getImageData(0, 0, crop.width, crop.height);
|
|
62
|
+
const pixels = pixelData.data;
|
|
63
|
+
for (let i = 0; i < pixels.length; i += 4) {
|
|
64
|
+
pixels[i + 0] *= r;
|
|
65
|
+
pixels[i + 1] *= g;
|
|
66
|
+
pixels[i + 2] *= b;
|
|
67
|
+
const canHandleAlpha = window.PhaserRegistry.CAN_CANVAS_HANDLE_ALPHA;
|
|
68
|
+
if (!canHandleAlpha) {
|
|
69
|
+
const alpha = pixels[i + 3];
|
|
70
|
+
pixels[i + 0] /= 255 / alpha;
|
|
71
|
+
pixels[i + 1] /= 255 / alpha;
|
|
72
|
+
pixels[i + 2] /= 255 / alpha;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
context.putImageData(pixelData, 0, 0);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
*
|
|
80
|
+
*/
|
|
81
|
+
export function checkInverseAlpha() {
|
|
82
|
+
const canvas = new CanvasBuffer(2, 1);
|
|
83
|
+
canvas.context.fillStyle = 'rgba(10, 20, 30, 0.5)';
|
|
84
|
+
// Draw a single pixel
|
|
85
|
+
canvas.context.fillRect(0, 0, 1, 1);
|
|
86
|
+
// Get the color values
|
|
87
|
+
const s1 = canvas.context.getImageData(0, 0, 1, 1);
|
|
88
|
+
if (s1 === null) {
|
|
89
|
+
return false;
|
|
90
|
+
}
|
|
91
|
+
// Plot them to x2
|
|
92
|
+
canvas.context.putImageData(s1, 1, 0);
|
|
93
|
+
// Get those values
|
|
94
|
+
const s2 = canvas.context.getImageData(1, 0, 1, 1);
|
|
95
|
+
// Compare and return
|
|
96
|
+
return (s2.data[0] === s1.data[0] && s2.data[1] === s1.data[1] && s2.data[2] === s1.data[2] && s2.data[3] === s1.data[3]);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
*
|
|
101
|
+
*/
|
|
102
|
+
export function canUseNewCanvasBlendModes() {
|
|
103
|
+
if (document === undefined) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const pngHead = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAABAQMAAADD8p2OAAAAA1BMVEX/';
|
|
107
|
+
const pngEnd = 'AAAACklEQVQI12NgAAAAAgAB4iG8MwAAAABJRU5ErkJggg==';
|
|
108
|
+
const magenta = new Image();
|
|
109
|
+
magenta.src = pngHead + 'AP804Oa6' + pngEnd;
|
|
110
|
+
const yellow = new Image();
|
|
111
|
+
yellow.src = pngHead + '/wCKxvRF' + pngEnd;
|
|
112
|
+
const canvas = create('CanvasTinter', 6, 1);
|
|
113
|
+
const context = canvas.getContext('2d');
|
|
114
|
+
context.globalCompositeOperation = 'multiply';
|
|
115
|
+
context.drawImage(magenta, 0, 0);
|
|
116
|
+
context.drawImage(yellow, 2, 0);
|
|
117
|
+
if (!context.getImageData(2, 0, 1, 1)) {
|
|
118
|
+
return false;
|
|
119
|
+
}
|
|
120
|
+
const data = context.getImageData(2, 0, 1, 1).data;
|
|
121
|
+
removeByCanvas(canvas);
|
|
122
|
+
return (data[0] === 255 && data[1] === 0 && data[2] === 0);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
*
|
|
127
|
+
*/
|
|
128
|
+
export function detectCapabilities() {
|
|
129
|
+
if (!window.PhaserRegistry) {
|
|
130
|
+
window.PhaserRegistry = {};
|
|
131
|
+
}
|
|
132
|
+
if (!window.PhaserRegistry.CAN_CANVAS_HANDLE_ALPHA) {
|
|
133
|
+
window.PhaserRegistry.CAN_CANVAS_HANDLE_ALPHA = checkInverseAlpha();
|
|
134
|
+
}
|
|
135
|
+
if (!window.PhaserRegistry.CAN_CANVAS_USE_MULTIPLY) {
|
|
136
|
+
window.PhaserRegistry.CAN_CANVAS_USE_MULTIPLY = canUseNewCanvasBlendModes();
|
|
137
|
+
}
|
|
138
|
+
if (!window.PhaserRegistry.CANVAS_TINT_METHOD) {
|
|
139
|
+
window.PhaserRegistry.CANVAS_TINT_METHOD = window.PhaserRegistry.CAN_CANVAS_USE_MULTIPLY ? tintWithMultiply : tintWithPerPixel;
|
|
140
|
+
}
|
|
141
|
+
}
|