Skip to content

Commit 0f403ee

Browse files
RefCountedObject base class, used on Mesh and Morph (playcanvas#2650)
* RefCount base class, used on Mesh and Morph * Remove newline * == to === * fix to tests - fixes setting mesh to the same (would destroy mesh first, then assign destroyed copy)� - fixed mesh destroy by sprite * loop * renamed RefCount -> RefCountedObject Co-authored-by: Will Eastcott <will@playcanvas.com>
1 parent 430b44a commit 0f403ee

File tree

7 files changed

+62
-45
lines changed

7 files changed

+62
-45
lines changed

src/core/ref-counted-object.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
// base class for reference counted objects
2+
class RefCountedObject {
3+
constructor() {
4+
// counter
5+
this._refCount = 0;
6+
}
7+
8+
// inrements the counter
9+
incRefCount() {
10+
this._refCount++;
11+
}
12+
13+
// decrements the counter. When the value reaches zero, destroy is called
14+
decRefCount() {
15+
if (--this._refCount === 0) {
16+
this.destroy();
17+
}
18+
}
19+
20+
// returns current count
21+
getRefCount() {
22+
return this._refCount;
23+
}
24+
25+
// default version of destroy functionality
26+
destroy() {
27+
// #ifdef DEBUG
28+
console.error("Class extended from the RefCountedObject class needs to have a destroy function implemented.");
29+
// #endif
30+
}
31+
}
32+
33+
export { RefCountedObject };

src/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export { IndexedList } from './core/indexed-list.js';
2222
export { Tags } from './core/tags.js';
2323
export { Timer, now } from './core/time.js';
2424
export { URI, createURI } from './core/uri.js';
25+
export { RefCountedObject } from './core/ref-counted-object.js';
2526

2627
// NET
2728
export { http, Http } from './net/http.js';

src/scene/mesh-instance.js

Lines changed: 16 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,8 @@ class MeshInstance {
9797
this._staticSource = null;
9898

9999
this.node = node; // The node that defines the transform of the mesh instance
100-
this._mesh = mesh; // The mesh that this instance renders
101-
mesh.incReference();
100+
this._mesh = mesh; // The mesh that this instance renders
101+
mesh.incRefCount();
102102
this.material = material; // The material with which to render this instance
103103

104104
this._shaderDefs = MASK_DYNAMIC << 16; // 2 byte toggles, 2 bytes light mask; Default value is no toggles and mask = pc.MASK_DYNAMIC
@@ -156,14 +156,19 @@ class MeshInstance {
156156
}
157157

158158
set mesh(mesh) {
159+
160+
if (mesh === this._mesh)
161+
return;
162+
159163
if (this._mesh) {
160-
this._mesh.decReference();
164+
// this destroys the mesh if refcount gets to 0
165+
this._mesh.decRefCount();
161166
}
162167

163168
this._mesh = mesh;
164169

165170
if (mesh) {
166-
mesh.incReference();
171+
mesh.incRefCount();
167172
}
168173
}
169174

@@ -392,15 +397,15 @@ class MeshInstance {
392397

393398
destroy() {
394399

395-
var mesh = this.mesh;
396-
if (mesh) {
397-
this.mesh = null; // this calls decReference on mesh
398-
if (mesh.refCount < 1) {
399-
mesh.destroy();
400-
}
400+
if (this.mesh) {
401+
// release previous mesh
402+
this.mesh = null;
401403
}
402404

403-
this.destroySkinInstance();
405+
if (this._skinInstance) {
406+
this._skinInstance.destroy();
407+
this._skinInstance = null;
408+
}
404409

405410
if (this.morphInstance) {
406411
this.morphInstance.destroy();
@@ -411,13 +416,6 @@ class MeshInstance {
411416
this.material = null;
412417
}
413418

414-
destroySkinInstance() {
415-
if (this._skinInstance) {
416-
this._skinInstance.destroy();
417-
this._skinInstance = null;
418-
}
419-
}
420-
421419
syncAabb() {
422420
// Deprecated
423421
}

src/scene/mesh.js

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { RefCountedObject } from '../core/ref-counted-object.js';
12
import { Vec3 } from '../math/vec3.js';
23

34
import { BoundingBox } from '../shape/bounding-box.js';
@@ -175,9 +176,9 @@ class GeometryVertexStream {
175176
* @property {pc.Skin} [skin] The skin data (if any) that drives skinned mesh animations for this mesh.
176177
* @property {pc.Morph} [morph] The morph data (if any) that drives morph target animations for this mesh.
177178
*/
178-
class Mesh {
179+
class Mesh extends RefCountedObject {
179180
constructor(graphicsDevice) {
180-
this._refCount = 0;
181+
super();
181182
this.id = id++;
182183
this.device = graphicsDevice || Application.getApplication().graphicsDevice;
183184
this.vertexBuffer = null;
@@ -206,18 +207,6 @@ class Mesh {
206207
this._aabb = aabb;
207208
}
208209

209-
get refCount() {
210-
return this._refCount;
211-
}
212-
213-
incReference() {
214-
this._refCount++;
215-
}
216-
217-
decReference() {
218-
this._refCount--;
219-
}
220-
221210
/**
222211
* @function
223212
* @name pc.Mesh#destroy

src/scene/morph-instance.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ var textureMorphVertexShader =
2323
class MorphInstance {
2424
constructor(morph) {
2525
this.morph = morph;
26+
morph.incRefCount();
2627
this.device = morph.device;
2728
this.meshInstance = null;
2829

@@ -108,7 +109,8 @@ class MorphInstance {
108109
this.shader = null;
109110

110111
if (this.morph) {
111-
this.morph.destroy();
112+
// this destroys morph if refcount gets to 0
113+
this.morph.decRefCount();
112114
this.morph = null;
113115
}
114116

src/scene/morph.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { RefCountedObject } from '../core/ref-counted-object.js';
12
import { Vec3 } from '../math/vec3.js';
23
import { math } from '../math/math.js';
34
import { BoundingBox } from '../shape/bounding-box.js';
@@ -16,8 +17,9 @@ import { BUFFER_STATIC, TYPE_FLOAT32, SEMANTIC_ATTR15, ADDRESS_CLAMP_TO_EDGE, FI
1617
* @param {pc.GraphicsDevice} graphicsDevice - The graphics device used to manage this morph target. If it is not provided, a device is obtained
1718
* from the {@link pc.Application}.
1819
*/
19-
class Morph {
20+
class Morph extends RefCountedObject {
2021
constructor(targets, graphicsDevice) {
22+
super();
2123

2224
this.device = graphicsDevice || Application.getApplication().graphicsDevice;
2325
this._targets = targets;

src/scene/sprite.js

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -252,18 +252,10 @@ Sprite.prototype.endUpdate = function () {
252252
* @description Free up the meshes created by the sprite.
253253
*/
254254
Sprite.prototype.destroy = function () {
255-
var i;
256-
var len;
257255

258-
// destroy old meshes
259-
for (i = 0, len = this._meshes.length; i < len; i++) {
260-
var mesh = this._meshes[i];
261-
if (!mesh) continue;
262-
263-
mesh.vertexBuffer.destroy();
264-
for (var j = 0, len2 = mesh.indexBuffer.length; j < len2; j++) {
265-
mesh.indexBuffer[j].destroy();
266-
}
256+
for (const mesh of this._meshes) {
257+
if (mesh)
258+
mesh.destroy();
267259
}
268260
this._meshes.length = 0;
269261
};

0 commit comments

Comments
 (0)