UNPKG

7.18 kBJavaScriptView Raw
1import { __awaiter, __decorate, __generator, __metadata } from "tslib";
2import { inject, singleton, contrib, Syringe, Contribution } from 'mana-syringe'; // import { SyncHook, SyncWaterfallHook, AsyncParallelHook, AsyncSeriesWaterfallHook } from '../utils';
3
4import { SyncHook, SyncWaterfallHook, AsyncParallelHook, AsyncSeriesWaterfallHook } from 'tapable';
5import { StyleValueRegistry } from '../css/interfaces';
6import { ElementEvent } from '../dom';
7import { RenderingContext, RenderReason } from './RenderingContext';
8import { SceneGraphService, sortByZIndex } from './SceneGraphService';
9export var RenderingPluginContribution = Syringe.defineToken('RenderingPluginContribution');
10/**
11 * Use frame renderer implemented by `g-canvas/svg/webgl`, in every frame we do followings:
12 * * update & merge dirty rectangles
13 * * begin frame
14 * * filter by visible
15 * * sort by z-index in scene graph
16 * * culling with strategies registered in `g-canvas/webgl`
17 * * end frame
18 */
19
20var RenderingService =
21/** @class */
22function () {
23 function RenderingService() {
24 this.inited = false;
25 this.stats = {
26 /**
27 * total display objects in scenegraph
28 */
29 total: 0,
30
31 /**
32 * number of display objects need to render in current frame
33 */
34 rendered: 0,
35
36 /**
37 * number of display objects displayed on screen
38 */
39 renderedOnscreen: 0
40 };
41 this.zIndexCounter = 0;
42 this.hooks = {
43 /**
44 * called before any frame rendered
45 */
46 init: new AsyncParallelHook(),
47
48 /**
49 * only dirty object which has sth changed will be rendered
50 */
51 dirtycheck: new SyncWaterfallHook(['object']),
52
53 /**
54 * do culling
55 */
56 cull: new SyncWaterfallHook(['object']),
57
58 /**
59 * called at beginning of each frame, won't get called if nothing to re-render
60 */
61 beginFrame: new SyncHook([]),
62
63 /**
64 * called before every dirty object get rendered
65 */
66 beforeRender: new SyncHook(['objectToRender']),
67
68 /**
69 * called when every dirty object rendering even it's culled
70 */
71 render: new SyncHook(['objectToRender']),
72
73 /**
74 * called after every dirty object get rendered
75 */
76 afterRender: new SyncHook(['objectToRender']),
77 endFrame: new SyncHook([]),
78 destroy: new SyncHook([]),
79
80 /**
81 * use async but faster method such as GPU-based picking in `g-plugin-device-renderer`
82 */
83 pick: new AsyncSeriesWaterfallHook(['result']),
84
85 /**
86 * used in event system
87 */
88 pointerDown: new SyncHook(['event']),
89 pointerUp: new SyncHook(['event']),
90 pointerMove: new SyncHook(['event']),
91 pointerOut: new SyncHook(['event']),
92 pointerOver: new SyncHook(['event']),
93 pointerWheel: new SyncHook(['event']),
94 pointerCancel: new SyncHook(['event'])
95 };
96 }
97
98 RenderingService.prototype.init = function () {
99 return __awaiter(this, void 0, void 0, function () {
100 var _this = this;
101
102 return __generator(this, function (_a) {
103 switch (_a.label) {
104 case 0:
105 // register rendering plugins
106 this.renderingPluginProvider.getContributions({
107 cache: false
108 }).forEach(function (plugin) {
109 plugin.apply(_this);
110 }); // await this.hooks.init.callPromise();
111
112 return [4
113 /*yield*/
114 , this.hooks.init.promise()];
115
116 case 1:
117 // await this.hooks.init.callPromise();
118 _a.sent();
119
120 this.inited = true;
121 return [2
122 /*return*/
123 ];
124 }
125 });
126 });
127 };
128
129 RenderingService.prototype.getStats = function () {
130 return this.stats;
131 };
132
133 RenderingService.prototype.render = function (canvasConfig) {
134 this.stats.total = 0;
135 this.stats.rendered = 0;
136 this.zIndexCounter = 0;
137 this.sceneGraphService.syncHierarchy(this.renderingContext.root);
138
139 if (this.renderingContext.renderReasons.size && this.inited) {
140 this.renderDisplayObject(this.renderingContext.root);
141
142 if (this.renderingContext.dirty || canvasConfig.renderer.getConfig().enableDirtyRectangleRendering && this.stats.total === 1) {
143 if (!this.renderingContext.dirty) {
144 this.hooks.beginFrame.call();
145 }
146
147 this.stats.renderedOnscreen = this.stats.rendered;
148 this.hooks.endFrame.call();
149 this.renderingContext.dirty = false;
150 }
151
152 this.renderingContext.renderReasons.clear();
153 } // console.log('stats', this.stats);
154
155 };
156
157 RenderingService.prototype.renderDisplayObject = function (displayObject) {
158 var _this = this; // recalc style values
159
160
161 this.styleValueRegistry.recalc(displayObject); // TODO: relayout
162 // dirtycheck first
163
164 var objectChanged = this.hooks.dirtycheck.call(displayObject);
165
166 if (objectChanged) {
167 // const objectToRender = this.hooks.cull.call(objectChanged);
168 this.hooks.cull.call(objectChanged); // if (objectToRender) {
169
170 this.stats.rendered++;
171
172 if (!this.renderingContext.dirty) {
173 this.renderingContext.dirty = true;
174 this.hooks.beginFrame.call();
175 }
176
177 this.hooks.beforeRender.call(objectChanged);
178 this.hooks.render.call(objectChanged);
179 this.hooks.afterRender.call(objectChanged);
180 displayObject.renderable.dirty = false; // }
181 }
182
183 displayObject.sortable.renderOrder = this.zIndexCounter++;
184 this.stats.total++; // sort is very expensive, use cached result if posible
185
186 var sortable = displayObject.sortable;
187 var renderOrderChanged = false;
188
189 if (sortable.dirty) {
190 sortable.sorted = displayObject.childNodes.slice().sort(sortByZIndex);
191 renderOrderChanged = true;
192 sortable.dirty = false;
193 } // recursive rendering its children
194
195
196 (sortable.sorted || displayObject.childNodes).forEach(function (child) {
197 _this.renderDisplayObject(child);
198 });
199
200 if (renderOrderChanged) {
201 displayObject.forEach(function (child) {
202 child.emit(ElementEvent.RENDER_ORDER_CHANGED, {
203 renderOrder: child.sortable.renderOrder
204 });
205 });
206 }
207 };
208
209 RenderingService.prototype.destroy = function () {
210 this.inited = false;
211 this.hooks.destroy.call();
212 };
213
214 RenderingService.prototype.dirtify = function () {
215 // need re-render
216 this.renderingContext.renderReasons.add(RenderReason.DISPLAY_OBJECT_CHANGED);
217 };
218
219 __decorate([contrib(RenderingPluginContribution), __metadata("design:type", Object)], RenderingService.prototype, "renderingPluginProvider", void 0);
220
221 __decorate([inject(RenderingContext), __metadata("design:type", Object)], RenderingService.prototype, "renderingContext", void 0);
222
223 __decorate([inject(SceneGraphService), __metadata("design:type", Object)], RenderingService.prototype, "sceneGraphService", void 0);
224
225 __decorate([inject(StyleValueRegistry), __metadata("design:type", Object)], RenderingService.prototype, "styleValueRegistry", void 0);
226
227 RenderingService = __decorate([singleton()], RenderingService);
228 return RenderingService;
229}();
230
231export { RenderingService };
\No newline at end of file