Skip to content

Commit 0e3022c

Browse files
Support for a more compressed scene file format (playcanvas#2294)
* initial decompress * do nothing without the compressed field * move decompress data * decompress in template * decompress in hierarchy * use underscores with private vars * rm else return * refactor parser for speed * rm expanding entities in templates * decompress entities only * move decompress to scene parser * initial decompress * handle triple vectors * reorder array and map check * change map check * rename fields * use field map array * edits for lint * comments in decompress * move decompress call to parser * add utils comments Co-authored-by: zachppaul <zachppaul@gmail.com>
1 parent 199cc41 commit 0e3022c

File tree

4 files changed

+186
-43
lines changed

4 files changed

+186
-43
lines changed

src/compress/compress-utils.js

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
var CompressUtils = {
2+
/**
3+
* @private
4+
* @function
5+
* @name pc.CompressUtils#setCompressedPRS
6+
* @description Set position, rotation and scale of an entity
7+
* using compressed scene format
8+
* @param {pc.Entity} entity - The entity
9+
* @param {object} data - Json entity data from a compressed scene
10+
* @param {object} compressed - Compression metadata
11+
*/
12+
setCompressedPRS: function (entity, data, compressed) {
13+
var a = compressed.singleVecs;
14+
15+
var b, i;
16+
17+
var v = data.___1;
18+
19+
if (!v) {
20+
b = compressed.tripleVecs;
21+
22+
i = data.___2;
23+
}
24+
25+
var n = v ? v[0] : b[i];
26+
27+
entity.setLocalPosition(a[n], a[n + 1], a[n + 2]);
28+
29+
n = v ? v[1] : b[i + 1];
30+
31+
entity.setLocalEulerAngles(a[n], a[n + 1], a[n + 2]);
32+
33+
n = v ? v[2] : b[i + 2];
34+
35+
entity.setLocalScale(a[n], a[n + 1], a[n + 2]);
36+
},
37+
38+
/**
39+
* @private
40+
* @function
41+
* @name pc.CompressUtils#oneCharToKey
42+
* @description Retrieve the original field name (key) for a
43+
* single character key from a compressed entity
44+
* @param {string} s - The compressed key string
45+
* @param {object} data - Compression metadata
46+
* @returns {string} The original key
47+
*/
48+
oneCharToKey: function (s, data) {
49+
var i = s.charCodeAt(0) - data.fieldFirstCode;
50+
51+
return data.fieldArray[i];
52+
},
53+
54+
/**
55+
* @private
56+
* @function
57+
* @name pc.CompressUtils#multCharToKey
58+
* @description Retrieve the original field name (key) for a
59+
* multi-character key from a compressed entity
60+
* @param {string} s - The compressed key string
61+
* @param {object} data - Compression metadata
62+
* @returns {string} The original key
63+
*/
64+
multCharToKey: function (s, data) {
65+
var ind = 0;
66+
67+
for (var i = 0; i < s.length; i++) {
68+
ind = ind * data.fieldCodeBase + s.charCodeAt(i) - data.fieldFirstCode;
69+
}
70+
71+
return data.fieldArray[ind];
72+
}
73+
};
74+
75+
export { CompressUtils };

src/compress/decompress.js

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
import { CompressUtils } from './compress-utils';
2+
3+
/**
4+
* @private
5+
* @class
6+
* @name pc.Decompress
7+
* @classdesc Reconstruct original object field names in a
8+
* compressed scene
9+
* @param {object} node - The current node of the object being
10+
* decompressed, initially the 'entities' field of a scene
11+
* @param {object} data - Compression metadata
12+
*/
13+
function Decompress(node, data) {
14+
this._node = node;
15+
16+
this._data = data;
17+
}
18+
19+
Object.assign(Decompress.prototype, {
20+
run: function () {
21+
var type = Object.prototype.toString.call(this._node);
22+
23+
if (type === '[object Object]') {
24+
this._handleMap();
25+
26+
} else if (type === '[object Array]') {
27+
this._handleArray();
28+
29+
} else {
30+
this._result = this._node;
31+
}
32+
33+
return this._result;
34+
},
35+
36+
_handleMap: function () {
37+
this._result = {};
38+
39+
var a = Object.keys(this._node);
40+
41+
a.forEach(this._handleKey, this);
42+
},
43+
44+
_handleKey: function (origKey) {
45+
var newKey = origKey;
46+
47+
var len = origKey.length;
48+
49+
if (len === 1) {
50+
newKey = CompressUtils.oneCharToKey(origKey, this._data);
51+
} else if (len === 2) {
52+
newKey = CompressUtils.multCharToKey(origKey, this._data);
53+
}
54+
55+
this._result[newKey] = new Decompress(this._node[origKey], this._data).run();
56+
},
57+
58+
_handleArray: function () {
59+
this._result = [];
60+
61+
this._node.forEach(this._handleArElt, this);
62+
},
63+
64+
_handleArElt: function (elt) {
65+
var v = new Decompress(elt, this._data).run();
66+
67+
this._result.push(v);
68+
}
69+
});
70+
71+
export { Decompress };

src/resources/parser/scene.js

Lines changed: 39 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import { Entity } from '../../framework/entity.js';
22

33
import { TemplateUtils } from '../../templates/template-utils.js';
4+
import { CompressUtils } from '../../compress/compress-utils';
5+
import { Decompress } from '../../compress/decompress';
46

57
function SceneParser(app, isTemplate) {
68
this._app = app;
@@ -11,51 +13,54 @@ function SceneParser(app, isTemplate) {
1113
Object.assign(SceneParser.prototype, {
1214
parse: function (data) {
1315
var entities = {};
14-
var id, i;
16+
var id, i, curEnt;
1517
var parent = null;
1618

19+
var compressed = data.compressedFormat;
20+
if (compressed) {
21+
data.entities = new Decompress(data.entities, compressed).run();
22+
}
23+
1724
if (data.collapsedInstances) {
1825
this._addCollapsedToEntities(this._app, data);
1926
}
2027

2128
// instantiate entities
2229
for (id in data.entities) {
23-
entities[id] = this._createEntity(data.entities[id]);
24-
if (data.entities[id].parent === null) {
25-
parent = entities[id];
30+
var curData = data.entities[id];
31+
curEnt = this._createEntity(curData, compressed);
32+
entities[id] = curEnt;
33+
if (curData.parent === null) {
34+
parent = curEnt;
2635
}
2736
}
2837

2938
// put entities into hierarchy
3039
for (id in data.entities) {
31-
var l = data.entities[id].children.length;
32-
for (i = 0; i < l; i++) {
33-
// pop resource id off the end of the array
34-
var resource_id = data.entities[id].children[i];
35-
if (entities[resource_id]) {
36-
// push entity on the front of the array
37-
entities[id].addChild(entities[resource_id]);
40+
curEnt = entities[id];
41+
var children = data.entities[id].children;
42+
var len = children.length;
43+
for (i = 0; i < len; i++) {
44+
var childEnt = entities[children[i]];
45+
if (childEnt) {
46+
curEnt.addChild(childEnt);
3847
}
3948
}
4049
}
4150

4251
this._openComponentData(parent, data.entities);
4352

53+
delete data.compressedFormat;
54+
4455
return parent;
4556
},
4657

47-
_createEntity: function (data) {
58+
_createEntity: function (data, compressed) {
4859
var entity = new Entity();
4960

50-
var p = data.position;
51-
var r = data.rotation;
52-
var s = data.scale;
53-
5461
entity.name = data.name;
5562
entity.setGuid(data.resource_id);
56-
entity.setLocalPosition(p[0], p[1], p[2]);
57-
entity.setLocalEulerAngles(r[0], r[1], r[2]);
58-
entity.setLocalScale(s[0], s[1], s[2]);
63+
this._setPosRotScale(entity, data, compressed);
5964
entity._enabled = data.enabled !== undefined ? data.enabled : true;
6065

6166
if (this._isTemplate) {
@@ -81,6 +86,21 @@ Object.assign(SceneParser.prototype, {
8186
return entity;
8287
},
8388

89+
_setPosRotScale: function (entity, data, compressed) {
90+
if (compressed) {
91+
CompressUtils.setCompressedPRS(entity, data, compressed);
92+
93+
} else {
94+
var p = data.position;
95+
var r = data.rotation;
96+
var s = data.scale;
97+
98+
entity.setLocalPosition(p[0], p[1], p[2]);
99+
entity.setLocalEulerAngles(r[0], r[1], r[2]);
100+
entity.setLocalScale(s[0], s[1], s[2]);
101+
}
102+
},
103+
84104
_openComponentData: function (entity, entities) {
85105
// Create components in order
86106
var systemsList = this._app.systems.list;

src/templates/template.js

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
import { SceneParser } from '../resources/parser/scene.js';
22

3-
import { TemplateUtils } from './template-utils.js';
4-
53
/**
64
* @private
75
* @class
@@ -15,8 +13,6 @@ function Template(app, data) {
1513

1614
this._data = data;
1715

18-
this._expandedData = {};
19-
2016
this._templateRoot = null;
2117
}
2218

@@ -35,29 +31,10 @@ Template.prototype.instantiate = function () {
3531
return this._templateRoot.clone();
3632
};
3733

38-
39-
/**
40-
* @private
41-
* @function
42-
* @name pc.Template#getExpandedData
43-
* @description Creates, if needed, and returns an object whose entities field contains
44-
* expanded entity data. This output format matches the format of raw scene data.
45-
* @returns {object} An object whose entities field contains
46-
* expanded entity data.
47-
*/
48-
Template.prototype.getExpandedData = function () {
49-
if (!this._expandedData.entities) {
50-
this._expandedData.entities = TemplateUtils.expandTemplateEntities(
51-
this._app, this._data.entities);
52-
}
53-
54-
return this._expandedData;
55-
};
56-
5734
Template.prototype._parseTemplate = function () {
5835
var parser = new SceneParser(this._app, true);
5936

60-
this._templateRoot = parser.parse(this.getExpandedData());
37+
this._templateRoot = parser.parse(this._data);
6138
};
6239

6340
export { Template };

0 commit comments

Comments
 (0)