Fix memory some memory leaks in the scene editor (#5853)

This commit is contained in:
D8H
2023-11-10 16:14:54 +01:00
committed by GitHub
parent 7229406cfb
commit 4f98ffa9ab
13 changed files with 787 additions and 746 deletions

View File

@@ -2099,6 +2099,12 @@ module.exports = {
this.updateTexture();
}
onRemovedFromScene() {
super.onRemovedFromScene();
// Keep textures because they are shared by all sprites.
this._pixiObject.destroy({ children: true });
}
static _getResourceNameToDisplay(objectConfiguration) {
return getFirstVisibleFaceResourceName(objectConfiguration);
}
@@ -2683,6 +2689,11 @@ module.exports = {
});
}
onRemovedFromScene() {
super.onRemovedFromScene();
this._pixiObject.destroy({ children: true });
}
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'JsPlatform/Extensions/3d_box.svg';
}

View File

@@ -497,89 +497,84 @@ module.exports = {
/**
* Renderer for instances of DummyObject inside the IDE.
*
* @extends RenderedInstance
* @class RenderedDummyObjectInstance
* @constructor
*/
function RenderedDummyObjectInstance(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
RenderedInstance.call(
this,
class RenderedDummyObjectInstance extends RenderedInstance {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
//Setup the PIXI object:
this._pixiObject = new PIXI.Text('This is a dummy object', {
align: 'left',
});
this._pixiObject.anchor.x = 0.5;
this._pixiObject.anchor.y = 0.5;
this._pixiContainer.addChild(this._pixiObject);
this.update();
//Setup the PIXI object:
this._pixiObject = new PIXI.Text('This is a dummy object', {
align: 'left',
});
this._pixiObject.anchor.x = 0.5;
this._pixiObject.anchor.y = 0.5;
this._pixiContainer.addChild(this._pixiObject);
this.update();
}
onRemovedFromScene() {
super.onRemovedFromScene();
this._pixiObject.destroy(true);
}
/**
* Return the path to the thumbnail of the specified object.
*/
getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'CppPlatform/Extensions/texticon24.png';
}
/**
* This is called to update the PIXI object on the scene editor
*/
update() {
// Read a property from the object
const property1Value = this._associatedObjectConfiguration
.getProperties()
.get('My first property')
.getValue();
this._pixiObject.text = property1Value;
// Read position and angle from the instance
this._pixiObject.position.x =
this._instance.getX() + this._pixiObject.width / 2;
this._pixiObject.position.y =
this._instance.getY() + this._pixiObject.height / 2;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
// Custom size can be read in this.getCustomWidth() and
// this.getCustomHeight()
}
/**
* Return the width of the instance, when it's not resized.
*/
getDefaultWidth() {
return this._pixiObject.width;
}
/**
* Return the height of the instance, when it's not resized.
*/
getDefaultHeight() {
return this._pixiObject.height;
}
}
RenderedDummyObjectInstance.prototype = Object.create(
RenderedInstance.prototype
);
/**
* Return the path to the thumbnail of the specified object.
*/
RenderedDummyObjectInstance.getThumbnail = function (
project,
resourcesLoader,
objectConfiguration
) {
return 'CppPlatform/Extensions/texticon24.png';
};
/**
* This is called to update the PIXI object on the scene editor
*/
RenderedDummyObjectInstance.prototype.update = function () {
// Read a property from the object
const property1Value = this._associatedObjectConfiguration
.getProperties()
.get('My first property')
.getValue();
this._pixiObject.text = property1Value;
// Read position and angle from the instance
this._pixiObject.position.x =
this._instance.getX() + this._pixiObject.width / 2;
this._pixiObject.position.y =
this._instance.getY() + this._pixiObject.height / 2;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
// Custom size can be read in this.getCustomWidth() and
// this.getCustomHeight()
};
/**
* Return the width of the instance, when it's not resized.
*/
RenderedDummyObjectInstance.prototype.getDefaultWidth = function () {
return this._pixiObject.width;
};
/**
* Return the height of the instance, when it's not resized.
*/
RenderedDummyObjectInstance.prototype.getDefaultHeight = function () {
return this._pixiObject.height;
};
objectsRenderingService.registerInstanceRenderer(
'MyDummyExtension::DummyObject',

View File

@@ -263,107 +263,107 @@ module.exports = {
/**
* Renderer for instances of LightObject inside the IDE.
*
* @extends RenderedInstance
* @class RenderedLightObjectInstance
* @constructor
*/
function RenderedLightObjectInstance(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
RenderedInstance.call(
this,
class RenderedLightObjectInstance extends RenderedInstance {
constructor(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
this._radius = parseFloat(
this._associatedObjectConfiguration
.getProperties(this.project)
.get('radius')
.getValue()
);
if (this._radius <= 0) this._radius = 1;
const color = objectsRenderingService.rgbOrHexToHexNumber(
this._associatedObjectConfiguration
.getProperties(this.project)
.get('color')
.getValue()
);
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
this._radius = parseFloat(
this._associatedObjectConfiguration
.getProperties(this.project)
.get('radius')
.getValue()
);
if (this._radius <= 0) this._radius = 1;
const color = objectsRenderingService.rgbOrHexToHexNumber(
this._associatedObjectConfiguration
.getProperties(this.project)
.get('color')
.getValue()
);
// The icon in the middle.
const lightIconSprite = new PIXI.Sprite(PIXI.Texture.from('CppPlatform/Extensions/lightIcon32.png'));
lightIconSprite.anchor.x = 0.5;
lightIconSprite.anchor.y = 0.5;
// The icon in the middle.
const lightIconSprite = new PIXI.Sprite(PIXI.Texture.from('CppPlatform/Extensions/lightIcon32.png'));
lightIconSprite.anchor.x = 0.5;
lightIconSprite.anchor.y = 0.5;
// The circle to show the radius of the light.
const radiusBorderWidth = 2;
const radiusGraphics = new PIXI.Graphics();
radiusGraphics.lineStyle(
radiusBorderWidth,
color,
0.8
);
radiusGraphics.drawCircle(0, 0, Math.max(1, this._radius - radiusBorderWidth));
// The circle to show the radius of the light.
const radiusBorderWidth = 2;
const radiusGraphics = new PIXI.Graphics();
radiusGraphics.lineStyle(
radiusBorderWidth,
color,
0.8
);
radiusGraphics.drawCircle(0, 0, Math.max(1, this._radius - radiusBorderWidth));
this._pixiObject = new PIXI.Container();
this._pixiObject.addChild(lightIconSprite);
this._pixiObject.addChild(radiusGraphics);
this._pixiContainer.addChild(this._pixiObject);
this.update();
this._pixiObject = new PIXI.Container();
this._pixiObject.addChild(lightIconSprite);
this._pixiObject.addChild(radiusGraphics);
this._pixiContainer.addChild(this._pixiObject);
this.update();
}
onRemovedFromScene() {
super.onRemovedFromScene();
// Keep textures because they are shared by all sprites.
this._pixiObject.destroy({ children: true });
}
/**
* Return the path to the thumbnail of the specified object.
*/
getThumbnail(
project,
resourcesLoader,
objectConfiguration
) {
return 'CppPlatform/Extensions/lightIcon32.png';
}
/**
* This is called to update the PIXI object on the scene editor
*/
update() {
this._pixiObject.position.x = this._instance.getX();
this._pixiObject.position.y = this._instance.getY();
}
/**
* Return the width of the instance, when it's not resized.
*/
getDefaultWidth() {
return this._radius * 2;
}
/**
* Return the height of the instance, when it's not resized.
*/
getDefaultHeight() {
return this._radius * 2;
}
getOriginX() {
return this._radius;
}
getOriginY() {
return this._radius;
}
}
RenderedLightObjectInstance.prototype = Object.create(
RenderedInstance.prototype
);
/**
* Return the path to the thumbnail of the specified object.
*/
RenderedLightObjectInstance.getThumbnail = function (
project,
resourcesLoader,
objectConfiguration
) {
return 'CppPlatform/Extensions/lightIcon32.png';
};
/**
* This is called to update the PIXI object on the scene editor
*/
RenderedLightObjectInstance.prototype.update = function () {
this._pixiObject.position.x = this._instance.getX();
this._pixiObject.position.y = this._instance.getY();
};
/**
* Return the width of the instance, when it's not resized.
*/
RenderedLightObjectInstance.prototype.getDefaultWidth = function () {
return this._radius * 2;
};
/**
* Return the height of the instance, when it's not resized.
*/
RenderedLightObjectInstance.prototype.getDefaultHeight = function () {
return this._radius * 2;
};
RenderedLightObjectInstance.prototype.getOriginX = function () {
return this._radius;
};
RenderedLightObjectInstance.prototype.getOriginY = function () {
return this._radius;
};
objectsRenderingService.registerInstanceRenderer(
'Lighting::LightObject',

View File

@@ -678,6 +678,12 @@ module.exports = {
this.update();
}
onRemovedFromScene() {
super.onRemovedFromScene();
this._pixiText.destroy(true);
this._pixiObject.destroy({ children: true });
}
static getThumbnail(project, resourcesLoader, objectConfiguration) {
return 'JsPlatform/Extensions/text_input.svg';
}

File diff suppressed because it is too large Load Diff

View File

@@ -568,127 +568,127 @@ module.exports = {
/**
* Renderer for instances of VideoObject inside the IDE.
*
* @extends RenderedInstance
* @class RenderedVideoObjectInstance
* @constructor
*/
function RenderedVideoObjectInstance(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
) {
RenderedInstance.call(
this,
class RenderedVideoObjectInstance extends RenderedInstance {
constructor (
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
) {
super(
project,
layout,
instance,
associatedObjectConfiguration,
pixiContainer,
pixiResourcesLoader
);
this._videoResource = undefined;
this._videoResource = undefined;
//Setup the PIXI object:
this._pixiObject = new PIXI.Sprite(this._getVideoTexture());
this._pixiObject.anchor.x = 0.5;
this._pixiObject.anchor.y = 0.5;
this._pixiContainer.addChild(this._pixiObject);
this.update();
}
RenderedVideoObjectInstance.prototype = Object.create(
RenderedInstance.prototype
);
//Setup the PIXI object:
this._pixiObject = new PIXI.Sprite(this._getVideoTexture());
this._pixiObject.anchor.x = 0.5;
this._pixiObject.anchor.y = 0.5;
this._pixiContainer.addChild(this._pixiObject);
this.update();
}
/**
* Return the path to the thumbnail of the specified object.
*/
RenderedVideoObjectInstance.getThumbnail = function (
project,
resourcesLoader,
objectConfiguration
) {
return 'JsPlatform/Extensions/videoicon24.png';
};
onRemovedFromScene() {
super.onRemovedFromScene();
// Keep textures because they are shared by all sprites.
this._pixiObject.destroy(false);
}
RenderedVideoObjectInstance.prototype._getVideoTexture = function () {
// Get the video resource to use
const videoResource = this._associatedObjectConfiguration
.getProperties()
.get('videoResource')
.getValue();
/**
* Return the path to the thumbnail of the specified object.
*/
getThumbnail(
project,
resourcesLoader,
objectConfiguration
) {
return 'JsPlatform/Extensions/videoicon24.png';
}
// This returns a VideoTexture with autoPlay set to false
return this._pixiResourcesLoader.getPIXIVideoTexture(
this._project,
videoResource
);
};
_getVideoTexture() {
// Get the video resource to use
const videoResource = this._associatedObjectConfiguration
.getProperties()
.get('videoResource')
.getValue();
/**
* This is called to update the PIXI object on the scene editor
*/
RenderedVideoObjectInstance.prototype.update = function () {
// Check if the video resource has changed
const videoResource = this._associatedObjectConfiguration
.getProperties()
.get('videoResource')
.getValue();
if (videoResource !== this._videoResource) {
this._videoResource = videoResource;
this._pixiObject.texture = this._getVideoTexture();
// This returns a VideoTexture with autoPlay set to false
return this._pixiResourcesLoader.getPIXIVideoTexture(
this._project,
videoResource
);
}
if (!this._pixiObject.texture.baseTexture.valid) {
var that = this;
/**
* This is called to update the PIXI object on the scene editor
*/
update() {
// Check if the video resource has changed
const videoResource = this._associatedObjectConfiguration
.getProperties()
.get('videoResource')
.getValue();
if (videoResource !== this._videoResource) {
this._videoResource = videoResource;
this._pixiObject.texture = this._getVideoTexture();
that._pixiObject.texture.on('error', function () {
that._pixiObject.texture.off('error', this);
if (!this._pixiObject.texture.baseTexture.valid) {
var that = this;
that._pixiObject.texture =
that._pixiResourcesLoader.getInvalidPIXITexture();
});
that._pixiObject.texture.on('error', function () {
that._pixiObject.texture.off('error', this);
that._pixiObject.texture =
that._pixiResourcesLoader.getInvalidPIXITexture();
});
}
}
// Update opacity
const opacity = this._associatedObjectConfiguration
.getProperties()
.get('Opacity')
.getValue();
this._pixiObject.alpha = opacity / 255;
// Read position and angle from the instance
this._pixiObject.position.x =
this._instance.getX() + this._pixiObject.width / 2;
this._pixiObject.position.y =
this._instance.getY() + this._pixiObject.height / 2;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
if (this._instance.hasCustomSize()) {
this._pixiObject.width = this.getCustomWidth();
this._pixiObject.height = this.getCustomHeight();
}
}
// Update opacity
const opacity = this._associatedObjectConfiguration
.getProperties()
.get('Opacity')
.getValue();
this._pixiObject.alpha = opacity / 255;
// Read position and angle from the instance
this._pixiObject.position.x =
this._instance.getX() + this._pixiObject.width / 2;
this._pixiObject.position.y =
this._instance.getY() + this._pixiObject.height / 2;
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()
);
if (this._instance.hasCustomSize()) {
this._pixiObject.width = this.getCustomWidth();
this._pixiObject.height = this.getCustomHeight();
/**
* Return the width of the instance, when it's not resized.
*/
getDefaultWidth() {
return this._pixiObject.width;
}
};
/**
* Return the width of the instance, when it's not resized.
*/
RenderedVideoObjectInstance.prototype.getDefaultWidth = function () {
return this._pixiObject.width;
};
/**
* Return the height of the instance, when it's not resized.
*/
RenderedVideoObjectInstance.prototype.getDefaultHeight = function () {
return this._pixiObject.height;
};
/**
* Return the height of the instance, when it's not resized.
*/
getDefaultHeight() {
return this._pixiObject.height;
}
}
// We don't do anything special when instance is removed from the scene,
// because the video is never really played.

View File

@@ -159,6 +159,14 @@ export default class RenderedCustomObjectInstance extends Rendered3DInstance
}
}
onRemovedFromScene(): void {
super.onRemovedFromScene();
for (const childrenInstance of this.childrenRenderedInstances) {
childrenInstance.onRemovedFromScene();
}
this._pixiObject.destroy(false);
}
/**
* Return a URL for thumbnail of the specified object.
*/

View File

@@ -30,6 +30,11 @@ export default function makeRenderer(iconPath: string) {
this._pixiContainer.addChild(this._pixiObject);
}
onRemovedFromScene(): void {
super.onRemovedFromScene();
this._pixiObject.destroy(false);
}
update() {
this._pixiObject.position.x = this._instance.getX();
this._pixiObject.position.y = this._instance.getY();

View File

@@ -117,6 +117,18 @@ export default class RenderedPanelSpriteInstance extends RenderedInstance {
}
}
onRemovedFromScene(): void {
super.onRemovedFromScene();
// Destroy textures because they are instantiated by this class.
for (const borderSprite of this._borderSprites) {
borderSprite.destroy({ texture: true });
}
// Destroy the containers without handling children because they are
// already handled above.
this._centerSprite.destroy({ texture: true });
this._pixiObject.destroy(false);
}
updateAngle() {
this._pixiObject.rotation = RenderedInstance.toRad(
this._instance.getAngle()

View File

@@ -50,6 +50,12 @@ export default class RenderedSpriteInstance extends RenderedInstance {
this.updatePIXITextureAndSprite();
}
onRemovedFromScene(): void {
super.onRemovedFromScene();
// Keep textures because they are shared by all sprites.
this._pixiObject.destroy(false);
}
/**
* Return a URL for thumbnail of the specified object.
*/

View File

@@ -55,6 +55,11 @@ export default class RenderedTextInstance extends RenderedInstance {
this.update();
}
onRemovedFromScene(): void {
super.onRemovedFromScene();
this._pixiObject.destroy(true);
}
/**
* Return a URL for thumbnail of the specified object.
*/

View File

@@ -43,6 +43,12 @@ export default class RenderedTiledSpriteInstance extends RenderedInstance {
this._pixiContainer.addChild(this._pixiObject);
}
onRemovedFromScene(): void {
super.onRemovedFromScene();
// Keep textures because they are shared by all sprites.
this._pixiObject.destroy(false);
}
/**
* Return a URL for thumbnail of the specified object.
*/

View File

@@ -30,6 +30,11 @@ export default class RenderedUnknownInstance extends RenderedInstance {
this._pixiContainer.addChild(this._pixiObject);
}
onRemovedFromScene(): void {
super.onRemovedFromScene();
this._pixiObject.destroy();
}
static getThumbnail(
project: gdProject,
resourcesLoader: Class<ResourcesLoader>,