forked from FamousArchives/core
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Scene.js
174 lines (158 loc) · 5.39 KB
/
Scene.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Owner: [email protected]
* @license MPL 2.0
* @copyright Famous Industries, Inc. 2014
*/
define(function(require, exports, module) {
var Transform = require('./Transform');
var Modifier = require('./Modifier');
var RenderNode = require('./RenderNode');
/**
* Builds and renders a scene graph based on a declarative structure definition.
* See the Scene examples in the examples distribution (http://github.com/Famous/examples.git).
*
* @class Scene
* @constructor
* @param {Object} definition in the format of a render spec.
*/
function Scene(definition) {
this.id = null;
this._objects = null;
this.node = new RenderNode();
this._definition = null;
if (definition) this.load(definition);
}
var _MATRIX_GENERATORS = {
'translate': Transform.translate,
'rotate': Transform.rotate,
'rotateX': Transform.rotateX,
'rotateY': Transform.rotateY,
'rotateZ': Transform.rotateZ,
'rotateAxis': Transform.rotateAxis,
'scale': Transform.scale,
'skew': Transform.skew,
'matrix3d': function() {
return arguments;
}
};
/**
* Clone this scene
*
* @method create
* @return {Scene} deep copy of this scene
*/
Scene.prototype.create = function create() {
return new Scene(this._definition);
};
function _resolveTransformMatrix(matrixDefinition) {
for (var type in _MATRIX_GENERATORS) {
if (type in matrixDefinition) {
var args = matrixDefinition[type];
if (!(args instanceof Array)) args = [args];
return _MATRIX_GENERATORS[type].apply(this, args);
}
}
}
// parse transform into tree of render nodes, doing matrix multiplication
// when available
function _parseTransform(definition) {
var transformDefinition = definition.transform;
var opacity = definition.opacity;
var origin = definition.origin;
var size = definition.size;
var transform = Transform.identity;
if (transformDefinition instanceof Array) {
if (transformDefinition.length === 16 && typeof transformDefinition[0] === 'number') {
transform = transformDefinition;
}
else {
for (var i = 0; i < transformDefinition.length; i++) {
transform = Transform.multiply(transform, _resolveTransformMatrix(transformDefinition[i]));
}
}
}
else if (transformDefinition instanceof Object) {
transform = _resolveTransformMatrix(transformDefinition);
}
var result = new Modifier({
transform: transform,
opacity: opacity,
origin: origin,
size: size
});
return result;
}
function _parseArray(definition) {
var result = new RenderNode();
for (var i = 0; i < definition.length; i++) {
var obj = _parse.call(this, definition[i]);
if (obj) result.add(obj);
}
return result;
}
// parse object directly into tree of RenderNodes
function _parse(definition) {
var result;
var id;
if (definition instanceof Array) {
result = _parseArray.call(this, definition);
}
else {
id = this._objects.length;
if (definition.render && (definition.render instanceof Function)) {
result = definition;
}
else if (definition.target) {
var targetObj = _parse.call(this, definition.target);
var obj = _parseTransform.call(this, definition);
result = new RenderNode(obj);
result.add(targetObj);
if (definition.id) this.id[definition.id] = obj;
}
else if (definition.id) {
result = new RenderNode();
this.id[definition.id] = result;
}
}
this._objects[id] = result;
return result;
}
/**
* Builds and renders a scene graph based on a canonical declarative scene definition.
* See examples/Scene/example.js.
*
* @method load
* @param {Object} definition definition in the format of a render spec.
*/
Scene.prototype.load = function load(definition) {
this._definition = definition;
this.id = {};
this._objects = [];
this.node.set(_parse.call(this, definition));
};
/**
* Add renderables to this component's render tree
*
* @method add
*
* @param {Object} obj renderable object
* @return {RenderNode} Render wrapping provided object, if not already a RenderNode
*/
Scene.prototype.add = function add() {
return this.node.add.apply(this.node, arguments);
};
/**
* Generate a render spec from the contents of this component.
*
* @private
* @method render
* @return {number} Render spec for this component
*/
Scene.prototype.render = function render() {
return this.node.render.apply(this.node, arguments);
};
module.exports = Scene;
});