Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pixi V8 Upgrade #1495

Draft
wants to merge 65 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
65 commits
Select commit Hold shift + click to select a range
ef87bf0
initial commit. Renderer and Texures still a WIP
tannerwuster Jul 18, 2024
4f91923
renamed mesh class, and updated name to label
tannerwuster Jul 29, 2024
dcc9e50
updated renderer for async init and new name schemes
tannerwuster Jul 29, 2024
c12c6a9
updated textures to use new pixi v8 types
tannerwuster Jul 29, 2024
489229b
package updated to pixi V8
tannerwuster Jul 29, 2024
a255e94
name is depricated so changed to label
tannerwuster Jul 30, 2024
d189fb7
pixi/core, pixi/display and pixi/events updated
tannerwuster Jul 30, 2024
5dc3600
initial commit. Renderer and Texures still a WIP
tannerwuster Jul 18, 2024
3912c96
updated renderer for async init and new name schemes
tannerwuster Jul 29, 2024
71e6321
package updated to pixi V8
tannerwuster Jul 29, 2024
c84c17f
fix async issue (thanks Ben!)
tannerwuster Jul 30, 2024
70fdd7d
new name schemes updated for v8
tannerwuster Aug 1, 2024
d40ffe3
name changed to label
tannerwuster Aug 2, 2024
46e9ef9
WIP: problems with supersurface being initialized
tannerwuster Aug 2, 2024
454c62e
checking is stage, ticker, scenes and events are initialized
tannerwuster Aug 2, 2024
588f5fe
naming schemes updated to V8
tannerwuster Aug 2, 2024
7f3db22
updated to be async
tannerwuster Aug 2, 2024
3c493ff
view changed to canvas
tannerwuster Aug 7, 2024
975e40f
remove console.logs
tannerwuster Aug 7, 2024
a1a1fa1
pixi v8.3.1
tannerwuster Aug 7, 2024
ee73c70
Working on pixi async init startup
bhousel Aug 8, 2024
b499b8c
setParent changed to just parent
tannerwuster Aug 20, 2024
02d4310
view changed to canvas
tannerwuster Aug 20, 2024
4c264e9
name changed to label
tannerwuster Aug 20, 2024
de61c72
WIP on Pixi v8 upgrade
bhousel Aug 21, 2024
e82fb85
uninstalling @pixi/display, utils, graphics because its built into pi…
tannerwuster Aug 23, 2024
e2db882
drawShape changed poly
tannerwuster Aug 23, 2024
52afe07
Remove enum helpers for pixi line cap/joints, as v8 now just uses the…
Aug 28, 2024
6ef1f17
Fix a few issues- beginHole/endHole are replaced by the cut method, a…
Aug 28, 2024
39e932b
fix the svgIconToTexture method to just do the symbol allocation with…
Aug 28, 2024
62fa838
Begin tackling the text-to-texture-allocator problem.
Aug 28, 2024
863d749
Comment out getLabelSprite as it relies on text objects having image …
Sep 3, 2024
7733f73
Fix a parent-setting bug that was preventing any AbstractFeatures fro…
Sep 4, 2024
99dbcaa
Fix updateHitArea to use a rectangle, which is now one member of the …
Sep 4, 2024
c75f101
Fix all PixiDashedLine draw invocations from 'drawSomething' to just …
Sep 4, 2024
e1b7f2c
Change order of draw calls and swap setStrokeStyle() for just stroke(…
Sep 5, 2024
2193f2b
setStrokeStyle changes to stroke, beginFill changed to fill, drawCirc…
tannerwuster Sep 5, 2024
d875ec2
Get polygons working, but without the fills, which are causing stack …
Sep 5, 2024
9bfd404
Fix the lasso drawing code by using poly() instead of polygon() and c…
Sep 5, 2024
26d75d9
Update texture creation code so that fill() and stroke() methods are …
Sep 5, 2024
0d66f29
use graphicsContext to supply a hit target for lines
Sep 6, 2024
98830c1
Fix background imagery allocator to include the width and height of e…
Sep 9, 2024
8325c2e
Fix stroke styles and get the atlas allocator quasi-working for just …
Sep 12, 2024
9f36993
Fix typo
bhousel Sep 17, 2024
82352d4
Fix call to photoSystem.render() that was causing a stack trace
Sep 17, 2024
391c12b
Update dependencies, pin to pixi 8.4.0
bhousel Sep 18, 2024
806de77
Update more of the graphic drawing methods to v8
bhousel Sep 18, 2024
b2e43dc
Revert the experimental code that was added to the tile layer
bhousel Sep 18, 2024
6304197
Skip the build worflow for this branch for now
bhousel Sep 18, 2024
1ce0237
More Pixi v8 work, atlas textures seem to work now
bhousel Sep 19, 2024
e353b8a
pixi 8.4.1
bhousel Sep 19, 2024
39eba45
Replace default ticker listener as before
bhousel Sep 20, 2024
8307eee
Update the svgIconToTexture method for v8.
Sep 20, 2024
665391e
WIP on textures and bitmap font issues
bhousel Sep 23, 2024
3feb687
Replaced the AtlasAllocator code
bhousel Sep 23, 2024
8ca2a12
Disable half pixel texture correction, as it now causes seams
bhousel Sep 24, 2024
1de84a0
Rasterize the SVG icons by setting them onto an Image
bhousel Sep 24, 2024
b6aa505
Get graphicToTexture working again
bhousel Sep 24, 2024
6c8992e
If no options are supplied to graphicToTexture, make an empty object.
Sep 24, 2024
299b6a3
Restore the preinstalled bitmap font in Background Imagery debug
bhousel Sep 25, 2024
d24aa79
Restore text labels!
bhousel Sep 25, 2024
18355f8
Fix `PIXI.buildLine()` for v8 and restore perimeter area labels
bhousel Sep 25, 2024
ad3710d
Get dashed lines back to working for polygons/lines.
Sep 26, 2024
8afe728
Changes to support webGPU- move the UiDefs svg code to load after pix…
Sep 27, 2024
cb0809c
Got polygon partial fills working again
bhousel Sep 28, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
branches: [ 'main', '!pixi_v8' ]

env:
FORCE_COLOR: 2
Expand Down
2 changes: 1 addition & 1 deletion modules/Context.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EventEmitter } from '@pixi/utils';
import { EventEmitter } from 'pixi.js';
import { select as d3_select } from 'd3-selection';
import { Viewport } from '@rapid-sdk/math';
import { utilUnicodeCharsTruncated } from '@rapid-sdk/util';
Expand Down
79 changes: 37 additions & 42 deletions modules/behaviors/AbstractBehavior.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EventEmitter } from '@pixi/utils';
import { EventEmitter } from 'pixi.js';
import { vecRotate } from '@rapid-sdk/math';


Expand Down Expand Up @@ -125,54 +125,49 @@ export class AbstractBehavior extends EventEmitter {
target: null
};

if (!e.target) { // `e.target` is the Pixi DisplayObject that triggered this event.
//console.log(`hit: ${e.target?.label}`);

if (!e.target) { // `e.target` is the PIXI.DisplayObject that triggered this event.
return result;
}

let dObj = e.target;
let feature = dObj?.__feature__;

// __feature__ is here, use this target
if (feature) {
result.target = {
displayObject: dObj,
feature: feature,
featureID: feature.id,
layer: feature.layer,
layerID: feature.layer.id,
data: feature.data,
dataID: feature.dataID
};
return result;
}

// No __feature__ in target, look in parent
dObj = e.target.parent;
feature = dObj?.__feature__;
if (feature) {
result.target = {
displayObject: dObj,
feature: feature,
featureID: feature.id,
layer: feature.layer,
layerID: feature.layer.id,
data: feature.data,
dataID: feature.dataID
};
return result;
// Try to find a target feature - it will have a `__feature__` property.
// Look up through the parent hierarchy until we find one or end up at the root stage.
while (dObj) {
let feature = dObj.__feature__;
if (feature) {
result.target = {
displayObject: dObj,
feature: feature,
featureID: feature.id,
layer: feature.layer,
layerID: feature.layer.id,
data: feature.data,
dataID: feature.dataID
};
return result;

} else {
if (dObj.parent) {
dObj = dObj.parent;

} else { // can't look up any further, just return the original target.
result.target = {
displayObject: e.target,
feature: null,
featureID: null,
layer: null,
layerID: null,
data: null,
dataID: null
};
return result;
}
}
}

// No __feature__ there either, just use the original target
result.target = {
displayObject: e.target,
feature: null,
featureID: null,
layer: null,
layerID: null,
data: null,
dataID: null
};
return result;
}

}
2 changes: 1 addition & 1 deletion modules/core/AbstractSystem.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { EventEmitter } from '@pixi/utils';
import { EventEmitter } from 'pixi.js';


/**
Expand Down
184 changes: 99 additions & 85 deletions modules/core/MapSystem.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,8 @@ export class MapSystem extends AbstractSystem {

this._renderer = null;
this._initPromise = null;
this._startPromise = null;
this._pixiReadyPromise = null;

// Ensure methods used as callbacks always have `this` bound correctly.
// (This is also necessary when using `d3-selection.call`)
Expand Down Expand Up @@ -144,8 +146,16 @@ export class MapSystem extends AbstractSystem {
* @return {Promise} Promise resolved when this component has completed startup
*/
startAsync() {
this._started = true;
return Promise.resolve();
if (this._startPromise) return this._startPromise;

const ui = this.context.systems.ui;
const prerequisites = ui.startAsync(); // UI must be started before we resolve

return this._startPromise = prerequisites
.then(() => {
this._started = true;
return this._pixiReadyPromise || Promise.reject();
});
}


Expand Down Expand Up @@ -225,96 +235,100 @@ export class MapSystem extends AbstractSystem {
.append('div')
.attr('class', 'overlay');

if (!this._renderer) {
this._renderer = new PixiRenderer(context, this.supersurface, this.surface, this.overlay);
if (this._renderer) return; // we created it already

// Forward the 'move' and 'draw' events from PixiRenderer
this._renderer
.on('move', () => this.emit('move'))
.on('draw', () => {
this._updateHash();
this.emit('draw', { full: true }); // pass {full: true} for legacy receivers
});
}

this._renderer = new PixiRenderer(context, this.supersurface, this.surface, this.overlay);

// Setup events that cause the map to redraw...
const editor = context.systems.editor;
const filters = context.systems.filters;
const imagery = context.systems.imagery;
const photos = context.systems.photos;
const styles = context.systems.styles;
const scene = this._renderer.scene;

editor
.on('merge', entityIDs => {
if (entityIDs) {
scene.dirtyData('osm', entityIDs);
}
this.deferredRedraw();
})
.on('stagingchange', difference => {
// todo - maybe only do this if difference.didChange.geometry?
const complete = difference.complete();
for (const entity of complete.values()) {
if (entity) { // may be undefined if entity was deleted
entity.touch(); // bump .v in place, rendering code will pick it up as dirty
filters.clearEntity(entity); // clear feature filter cache
}
}
this.immediateRedraw();
})
.on('historyjump', (prevIndex, currIndex) => {
// This code occurs when jumping to a different edit because of a undo/redo/restore, etc.
const prevEdit = editor.history[prevIndex];
const currEdit = editor.history[currIndex];

// Counterintuitively, when undoing, we might want the metadata from the _next_ edit (located at prevIndex).
// If that edit exists (it might not if we are restoring) use that one, otherwise just use the current edit
const didUndo = (currIndex === prevIndex - 1);
const edit = (didUndo && prevEdit) ?? currEdit;

// Reposition the map if we've jumped to a different place.
const t0 = context.viewport.transform.props;
const t1 = edit.transform;
if (t1 && (t0.x !== t1.x || t0.y !== t1.y || t0.k !== t1.k || t0.r !== t1.r)) {
this.transformEase(t1);
}
this._pixiReadyPromise = (this._renderer._pixiReadyPromise || Promise.reject())
.then(() => {
// Forward the 'move' and 'draw' events from PixiRenderer
this._renderer
.on('move', () => this.emit('move'))
.on('draw', () => {
this._updateHash();
this.emit('draw', { full: true }); // pass {full: true} for legacy receivers
});

// Switch to select mode if the edit contains selected ids.
// Note: draw modes need to do a little extra work to survive this,
// so they have their own `historyjump` listeners.
const modeID = context.mode?.id;
if (/^draw/.test(modeID)) return;

// For now these IDs are assumed to be OSM ids.
// Check that they are actually in the stable graph.
const graph = edit.graph;
const checkIDs = edit.selectedIDs ?? [];
const selectedIDs = checkIDs.filter(entityID => graph.hasEntity(entityID));
if (selectedIDs.length) {
context.enter('select-osm', { selection: { osm: selectedIDs }} );
} else {
context.enter('browse');
}
});
// Setup events that cause the map to redraw...
const editor = context.systems.editor;
const filters = context.systems.filters;
const imagery = context.systems.imagery;
const photos = context.systems.photos;
const styles = context.systems.styles;
const scene = this._renderer.scene;

editor
.on('merge', entityIDs => {
if (entityIDs) {
scene.dirtyData('osm', entityIDs);
}
this.deferredRedraw();
})
.on('stagingchange', difference => {
// todo - maybe only do this if difference.didChange.geometry?
const complete = difference.complete();
for (const entity of complete.values()) {
if (entity) { // may be undefined if entity was deleted
entity.touch(); // bump .v in place, rendering code will pick it up as dirty
filters.clearEntity(entity); // clear feature filter cache
}
}
this.immediateRedraw();
})
.on('historyjump', (prevIndex, currIndex) => {
// This code occurs when jumping to a different edit because of a undo/redo/restore, etc.
const prevEdit = editor.history[prevIndex];
const currEdit = editor.history[currIndex];

// Counterintuitively, when undoing, we might want the metadata from the _next_ edit (located at prevIndex).
// If that edit exists (it might not if we are restoring) use that one, otherwise just use the current edit
const didUndo = (currIndex === prevIndex - 1);
const edit = (didUndo && prevEdit) ?? currEdit;

// Reposition the map if we've jumped to a different place.
const t0 = context.viewport.transform.props;
const t1 = edit.transform;
if (t1 && (t0.x !== t1.x || t0.y !== t1.y || t0.k !== t1.k || t0.r !== t1.r)) {
this.transformEase(t1);
}

// Switch to select mode if the edit contains selected ids.
// Note: draw modes need to do a little extra work to survive this,
// so they have their own `historyjump` listeners.
const modeID = context.mode?.id;
if (/^draw/.test(modeID)) return;

// For now these IDs are assumed to be OSM ids.
// Check that they are actually in the stable graph.
const graph = edit.graph;
const checkIDs = edit.selectedIDs ?? [];
const selectedIDs = checkIDs.filter(entityID => graph.hasEntity(entityID));
if (selectedIDs.length) {
context.enter('select-osm', { selection: { osm: selectedIDs }} );
} else {
context.enter('browse');
}
});

filters
.on('filterchange', () => {
scene.dirtyLayers('osm');
this.immediateRedraw();
});
filters
.on('filterchange', () => {
scene.dirtyLayers('osm');
this.immediateRedraw();
});

context.on('modechange', this.immediateRedraw);
imagery.on('imagerychange', this.immediateRedraw);
photos.on('photochange', this.immediateRedraw);
scene.on('layerchange', this.immediateRedraw);
styles.on('stylechange', this.immediateRedraw);
context.on('modechange', this.immediateRedraw);
imagery.on('imagerychange', this.immediateRedraw);
photos.on('photochange', this.immediateRedraw);
scene.on('layerchange', this.immediateRedraw);
styles.on('stylechange', this.immediateRedraw);

const osm = context.services.osm;
if (osm) {
osm.on('authchange', this.immediateRedraw);
}
const osm = context.services.osm;
if (osm) {
osm.on('authchange', this.immediateRedraw);
}

});
}


Expand Down
Loading
Loading