/
Renderer.js
474 lines (422 loc) · 15.7 KB
/
Renderer.js
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
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
import { AbstractRenderer } from './AbstractRenderer';
import { sayHello, isWebGLSupported } from '@pixi/utils';
import { MaskSystem } from './mask/MaskSystem';
import { StencilSystem } from './mask/StencilSystem';
import { ScissorSystem } from './mask/ScissorSystem';
import { FilterSystem } from './filters/FilterSystem';
import { FramebufferSystem } from './framebuffer/FramebufferSystem';
import { RenderTextureSystem } from './renderTexture/RenderTextureSystem';
import { TextureSystem } from './textures/TextureSystem';
import { ProjectionSystem } from './projection/ProjectionSystem';
import { StateSystem } from './state/StateSystem';
import { GeometrySystem } from './geometry/GeometrySystem';
import { ShaderSystem } from './shader/ShaderSystem';
import { ContextSystem } from './context/ContextSystem';
import { BatchSystem } from './batch/BatchSystem';
import { TextureGCSystem } from './textures/TextureGCSystem';
import { RENDERER_TYPE } from '@pixi/constants';
import { UniformGroup } from './shader/UniformGroup';
import { Matrix } from '@pixi/math';
import { Runner } from '@pixi/runner';
/**
* The Renderer draws the scene and all its content onto a WebGL enabled canvas.
*
* This renderer should be used for browsers that support WebGL.
*
* This renderer works by automatically managing WebGLBatchesm, so no need for Sprite Batches or Sprite Clouds.
* Don't forget to add the view to your DOM or you will not see anything!
*
* @class
* @memberof PIXI
* @extends PIXI.AbstractRenderer
*/
export class Renderer extends AbstractRenderer
{
/**
* Create renderer if WebGL is available. Overrideable
* by the **@pixi/canvas-renderer** package to allow fallback.
* throws error if WebGL is not available.
* @static
* @private
*/
static create(options)
{
if (isWebGLSupported())
{
return new Renderer(options);
}
throw new Error('WebGL unsupported in this browser, use "pixi.js-legacy" for fallback canvas2d support.');
}
/**
* @param {object} [options] - The optional renderer parameters.
* @param {number} [options.width=800] - The width of the screen.
* @param {number} [options.height=600] - The height of the screen.
* @param {HTMLCanvasElement} [options.view] - The canvas to use as a view, optional.
* @param {boolean} [options.transparent=false] - If the render view is transparent.
* @param {boolean} [options.autoDensity=false] - Resizes renderer view in CSS pixels to allow for
* resolutions other than 1.
* @param {boolean} [options.antialias=false] - Sets antialias. If not available natively then FXAA
* antialiasing is used.
* @param {boolean} [options.forceFXAA=false] - Forces FXAA antialiasing to be used over native.
* FXAA is faster, but may not always look as great.
* @param {number} [options.resolution=1] - The resolution / device pixel ratio of the renderer.
* The resolution of the renderer retina would be 2.
* @param {boolean} [options.clearBeforeRender=true] - This sets if the renderer will clear
* the canvas or not before the new render pass. If you wish to set this to false, you *must* set
* preserveDrawingBuffer to `true`.
* @param {boolean} [options.preserveDrawingBuffer=false] - Enables drawing buffer preservation,
* enable this if you need to call toDataUrl on the WebGL context.
* @param {number} [options.backgroundColor=0x000000] - The background color of the rendered area
* (shown if not transparent).
* @param {string} [options.powerPreference] - Parameter passed to WebGL context, set to "high-performance"
* for devices with dual graphics card.
* @param {object} [options.context] If WebGL context already exists, all parameters must be taken from it.
*/
constructor(options = {})
{
super('WebGL', options);
// the options will have been modified here in the super constructor with pixi's default settings..
options = this.options;
/**
* The type of this renderer as a standardized const
*
* @member {number}
* @see PIXI.RENDERER_TYPE
*/
this.type = RENDERER_TYPE.WEBGL;
/**
* WebGL context, set by the contextSystem (this.context)
*
* @readonly
* @member {WebGLRenderingContext}
*/
this.gl = null;
this.CONTEXT_UID = 0;
// TODO legacy!
/**
* Internal signal instances of **runner**, these
* are assigned to each system created.
* @see PIXI.Runner
* @name PIXI.Renderer#runners
* @private
* @type {object}
* @readonly
* @property {PIXI.Runner} destroy - Destroy runner
* @property {PIXI.Runner} contextChange - Context change runner
* @property {PIXI.Runner} reset - Reset runner
* @property {PIXI.Runner} update - Update runner
* @property {PIXI.Runner} postrender - Post-render runner
* @property {PIXI.Runner} prerender - Pre-render runner
* @property {PIXI.Runner} resize - Resize runner
*/
this.runners = {
destroy: new Runner('destroy'),
contextChange: new Runner('contextChange', 1),
reset: new Runner('reset'),
update: new Runner('update'),
postrender: new Runner('postrender'),
prerender: new Runner('prerender'),
resize: new Runner('resize', 2),
};
/**
* Global uniforms
* @member {PIXI.UniformGroup}
*/
this.globalUniforms = new UniformGroup({
projectionMatrix: new Matrix(),
}, true);
/**
* Mask system instance
* @member {PIXI.systems.MaskSystem} mask
* @memberof PIXI.Renderer#
* @readonly
*/
this.addSystem(MaskSystem, 'mask')
/**
* Context system instance
* @member {PIXI.systems.ContextSystem} context
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(ContextSystem, 'context')
/**
* State system instance
* @member {PIXI.systems.StateSystem} state
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(StateSystem, 'state')
/**
* Shader system instance
* @member {PIXI.systems.ShaderSystem} shader
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(ShaderSystem, 'shader')
/**
* Texture system instance
* @member {PIXI.systems.TextureSystem} texture
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(TextureSystem, 'texture')
/**
* Geometry system instance
* @member {PIXI.systems.GeometrySystem} geometry
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(GeometrySystem, 'geometry')
/**
* Framebuffer system instance
* @member {PIXI.systems.FramebufferSystem} framebuffer
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(FramebufferSystem, 'framebuffer')
/**
* Scissor system instance
* @member {PIXI.systems.ScissorSystem} scissor
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(ScissorSystem, 'scissor')
/**
* Stencil system instance
* @member {PIXI.systems.StencilSystem} stencil
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(StencilSystem, 'stencil')
/**
* Projection system instance
* @member {PIXI.systems.ProjectionSystem} projection
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(ProjectionSystem, 'projection')
/**
* Texture garbage collector system instance
* @member {PIXI.systems.TextureGCSystem} textureGC
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(TextureGCSystem, 'textureGC')
/**
* Filter system instance
* @member {PIXI.systems.FilterSystem} filter
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(FilterSystem, 'filter')
/**
* RenderTexture system instance
* @member {PIXI.systems.RenderTextureSystem} renderTexture
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(RenderTextureSystem, 'renderTexture')
/**
* Batch system instance
* @member {PIXI.systems.BatchSystem} batch
* @memberof PIXI.Renderer#
* @readonly
*/
.addSystem(BatchSystem, 'batch');
this.initPlugins(Renderer.__plugins);
/**
* The options passed in to create a new WebGL context.
*/
if (options.context)
{
this.context.initFromContext(options.context);
}
else
{
this.context.initFromOptions({
alpha: this.transparent,
antialias: options.antialias,
premultipliedAlpha: this.transparent && this.transparent !== 'notMultiplied',
stencil: true,
preserveDrawingBuffer: options.preserveDrawingBuffer,
powerPreference: this.options.powerPreference,
});
}
/**
* Flag if we are rendering to the screen vs renderTexture
* @member {boolean}
* @readonly
* @default true
*/
this.renderingToScreen = true;
sayHello(this.context.webGLVersion === 2 ? 'WebGL 2' : 'WebGL 1');
this.resize(this.options.width, this.options.height);
}
/**
* Add a new system to the renderer.
* @param {Function} ClassRef - Class reference
* @param {string} [name] - Property name for system, if not specified
* will use a static `name` property on the class itself. This
* name will be assigned as s property on the Renderer so make
* sure it doesn't collide with properties on Renderer.
* @return {PIXI.Renderer} Return instance of renderer
*/
addSystem(ClassRef, name)
{
if (!name)
{
name = ClassRef.name;
}
const system = new ClassRef(this);
if (this[name])
{
throw new Error(`Whoops! The name "${name}" is already in use`);
}
this[name] = system;
for (const i in this.runners)
{
this.runners[i].add(system);
}
/**
* Fired after rendering finishes.
*
* @event PIXI.Renderer#postrender
*/
/**
* Fired before rendering starts.
*
* @event PIXI.Renderer#prerender
*/
/**
* Fired when the WebGL context is set.
*
* @event PIXI.Renderer#context
* @param {WebGLRenderingContext} gl - WebGL context.
*/
return this;
}
/**
* Renders the object to its WebGL view
*
* @param {PIXI.DisplayObject} displayObject - The object to be rendered.
* @param {PIXI.RenderTexture} [renderTexture] - The render texture to render to.
* @param {boolean} [clear=true] - Should the canvas be cleared before the new render.
* @param {PIXI.Matrix} [transform] - A transform to apply to the render texture before rendering.
* @param {boolean} [skipUpdateTransform=false] - Should we skip the update transform pass?
*/
render(displayObject, renderTexture, clear, transform, skipUpdateTransform)
{
// can be handy to know!
this.renderingToScreen = !renderTexture;
this.runners.prerender.run();
this.emit('prerender');
// apply a transform at a GPU level
this.projection.transform = transform;
// no point rendering if our context has been blown up!
if (this.context.isLost)
{
return;
}
if (!renderTexture)
{
this._lastObjectRendered = displayObject;
}
if (!skipUpdateTransform)
{
// update the scene graph
const cacheParent = displayObject.parent;
displayObject.parent = this._tempDisplayObjectParent;
displayObject.updateTransform();
displayObject.parent = cacheParent;
// displayObject.hitArea = //TODO add a temp hit area
}
this.renderTexture.bind(renderTexture);
this.batch.currentRenderer.start();
if (clear !== undefined ? clear : this.clearBeforeRender)
{
this.renderTexture.clear();
}
displayObject.render(this);
// apply transform..
this.batch.currentRenderer.flush();
if (renderTexture)
{
renderTexture.baseTexture.update();
}
this.runners.postrender.run();
// reset transform after render
this.projection.transform = null;
this.emit('postrender');
}
/**
* Resizes the WebGL view to the specified width and height.
*
* @param {number} screenWidth - The new width of the screen.
* @param {number} screenHeight - The new height of the screen.
*/
resize(screenWidth, screenHeight)
{
super.resize(screenWidth, screenHeight);
this.runners.resize.run(screenWidth, screenHeight);
}
/**
* Resets the WebGL state so you can render things however you fancy!
*
* @return {PIXI.Renderer} Returns itself.
*/
reset()
{
this.runners.reset.run();
return this;
}
/**
* Clear the frame buffer
*/
clear()
{
this.framebuffer.bind();
this.framebuffer.clear();
}
/**
* Removes everything from the renderer (event listeners, spritebatch, etc...)
*
* @param {boolean} [removeView=false] - Removes the Canvas element from the DOM.
* See: https://github.com/pixijs/pixi.js/issues/2233
*/
destroy(removeView)
{
this.runners.destroy.run();
for (const r in this.runners)
{
this.runners[r].destroy();
}
// call base destroy
super.destroy(removeView);
// TODO nullify all the managers..
this.gl = null;
}
/**
* Collection of installed plugins. These are included by default in PIXI, but can be excluded
* by creating a custom build. Consult the README for more information about creating custom
* builds and excluding plugins.
* @name PIXI.Renderer#plugins
* @type {object}
* @readonly
* @property {PIXI.accessibility.AccessibilityManager} accessibility Support tabbing interactive elements.
* @property {PIXI.extract.Extract} extract Extract image data from renderer.
* @property {PIXI.interaction.InteractionManager} interaction Handles mouse, touch and pointer events.
* @property {PIXI.prepare.Prepare} prepare Pre-render display objects.
*/
/**
* Adds a plugin to the renderer.
*
* @method
* @param {string} pluginName - The name of the plugin.
* @param {Function} ctor - The constructor function or class for the plugin.
*/
static registerPlugin(pluginName, ctor)
{
Renderer.__plugins = Renderer.__plugins || {};
Renderer.__plugins[pluginName] = ctor;
}
}