├── README.md
├── .gitignore
├── assets
├── gradient
│ ├── gradient.bin
│ ├── gradient0VS.glsl
│ ├── gradient0FS.glsl
│ └── gradient.json
└── picking
│ ├── pickingFS.glsl
│ ├── pickingVs.glsl
│ └── picking.json
├── ui
├── scene-viewer.reel
│ ├── scene-viewer.css
│ ├── scene-viewer.html
│ └── scene-viewer.js
└── view.reel
│ ├── view.css
│ ├── view.html
│ └── view.meta
├── runtime
├── web.config
├── scene.meta
├── node.meta
├── component-3d.meta
├── material.meta
├── base.js
├── camera.js
├── resource-loader.js
├── technique.js
├── builtin-assets.js
├── scene-resource-loader.js
├── resource-description.js
├── glTF-scene.js
├── node-wrapper.js
├── primitive.js
├── mesh.js
├── transform-helper.js
├── scene-helper.js
├── skin.js
├── glTF-material.js
├── scene.js
├── mesh-resource-loader.js
├── projection.js
├── animation-manager.js
├── transform.js
├── material.js
├── node.js
├── glTF-parser.js
├── scene-renderer.js
└── glTF-node.js
├── package.json
└── controllers
└── camera-controller.js
/README.md:
--------------------------------------------------------------------------------
1 | mjs-volume
2 | ==========
3 |
4 | MontageJS 3D Components
5 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /node_modules
2 | .DS_Store
3 | .idea
4 | node_modules
5 | npm-debug.log
6 | *$py.class
7 | console.log
--------------------------------------------------------------------------------
/assets/gradient/gradient.bin:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/emackey/mjs-volume/master/assets/gradient/gradient.bin
--------------------------------------------------------------------------------
/assets/picking/pickingFS.glsl:
--------------------------------------------------------------------------------
1 | precision highp float;
2 | uniform vec4 u_pickingColor;
3 | void main(void) {
4 | gl_FragColor = u_pickingColor;
5 | }
6 |
--------------------------------------------------------------------------------
/ui/scene-viewer.reel/scene-viewer.css:
--------------------------------------------------------------------------------
1 | .SceneViewer {
2 | -webkit-box-flex: 1;
3 | -ms-flex: 1;
4 | flex: 1;
5 | display: -webkit-box;
6 | display: -ms-flex;
7 | display: flex;
8 | height: 100%;
9 | }
10 |
--------------------------------------------------------------------------------
/assets/picking/pickingVs.glsl:
--------------------------------------------------------------------------------
1 | precision highp float;
2 | attribute vec3 a_position;
3 | uniform mat4 u_worldviewMatrix;
4 | uniform mat4 u_projectionMatrix;
5 | void main(void) {
6 | vec4 pos = u_worldviewMatrix * vec4(a_position,1.0);
7 | gl_Position = u_projectionMatrix * pos;
8 | }
9 |
--------------------------------------------------------------------------------
/ui/view.reel/view.css:
--------------------------------------------------------------------------------
1 | .View {
2 | -webkit-box-flex: 1;
3 | -ms-flex: 1;
4 | flex: 1;
5 | display: -webkit-box;
6 | display: -ms-flex;
7 | display: flex;
8 | }
9 |
10 | .View-canvas {
11 | -webkit-box-flex: 1;
12 | -ms-flex: 1;
13 | flex: 1;
14 | }
--------------------------------------------------------------------------------
/assets/gradient/gradient0VS.glsl:
--------------------------------------------------------------------------------
1 | precision highp float;
2 | attribute vec3 a_position;
3 | varying vec3 v_position;
4 | uniform mat4 u_projectionMatrix;
5 | void main(void)
6 | {
7 | v_position = a_position;
8 | gl_Position = u_projectionMatrix * vec4(a_position, 1.);
9 | }
10 |
11 |
--------------------------------------------------------------------------------
/assets/gradient/gradient0FS.glsl:
--------------------------------------------------------------------------------
1 | precision highp float;
2 | varying vec3 v_position;
3 | uniform vec3 u_color0;
4 | uniform vec3 u_color1;
5 | void main(void) {
6 | float intensity = (v_position.y / 2.) + 0.5;
7 |
8 | vec3 color = mix(u_color0, u_color1, intensity);
9 |
10 | gl_FragColor = vec4(color,.7);
11 | }
12 |
--------------------------------------------------------------------------------
/runtime/web.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name":"mjs-volume",
3 | "version":"0.1.0",
4 | "dependencies": {
5 | "montage": "0.13.7",
6 | "digit": "0.3.1",
7 | "matte": "0.1.1",
8 | "q" : "0.9.6",
9 | "collections": "~0.2.1"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "https://github.com/fabrobinet/mjs-volume.git"
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ui/scene-viewer.reel/scene-viewer.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
21 |
22 |
23 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/runtime/scene.meta:
--------------------------------------------------------------------------------
1 | {
2 |
3 |
4 | "path_property": {
5 | "prototype": "montage/core/meta/property-blueprint",
6 | "properties": {
7 | "name": "path",
8 | "valueType": "string",
9 | "blueprint": {
10 | "@": "root"
11 | }
12 | }
13 | },
14 |
15 | "root": {
16 | "prototype": "montage/core/meta/module-blueprint",
17 | "properties": {
18 | "name": "Scene",
19 | "propertyBlueprints": [
20 | {
21 | "@": "path_property"
22 | }
23 | ],
24 | "propertyBlueprintGroups": {
25 | "Scene": [
26 | {
27 | "@": "path_property"
28 | }
29 | ]
30 | },
31 | "blueprintModule": {
32 | "%": "runtime/scene.meta"
33 | },
34 | "exportName": "Scene",
35 | "module": {
36 | "%": "runtime/scene"
37 | }
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/runtime/node.meta:
--------------------------------------------------------------------------------
1 | {
2 | "hidden_property": {
3 | "prototype": "montage/core/meta/property-blueprint",
4 | "properties": {
5 | "name": "hidden",
6 | "valueType": "boolean",
7 | "blueprint": {
8 | "@": "root"
9 | }
10 | }
11 | },
12 |
13 | "blueprint_parent": {
14 | "prototype": "montage/core/meta/blueprint-reference",
15 | "properties": {
16 | "valueReference": {
17 | "blueprintName": "Component3D",
18 | "blueprintModule": {
19 | "%": "runtime/component-3d.meta"
20 | },
21 | "prototypeName": "Component3D"
22 | }
23 | }
24 | },
25 |
26 | "root": {
27 | "prototype": "montage/core/meta/module-blueprint",
28 | "properties": {
29 | "parent": {"@": "blueprint_parent"},
30 | "name": "Node",
31 | "propertyBlueprints": [
32 | {
33 | "@": "hidden_property"
34 | }
35 | ],
36 | "propertyBlueprintGroups": {
37 | "Node": [
38 | {
39 | "@": "hidden_property"
40 | }
41 | ]
42 | },
43 | "blueprintModule": {
44 | "%": "runtime/node.meta"
45 | },
46 | "exportName": "Node",
47 | "module": {
48 | "%": "runtime/node"
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/runtime/component-3d.meta:
--------------------------------------------------------------------------------
1 | {
2 | "scene_property": {
3 | "prototype": "montage/core/meta/property-blueprint",
4 | "properties": {
5 | "name": "scene",
6 | "valueType": "object",
7 | "blueprint": {
8 | "@": "root"
9 | }
10 | }
11 | },
12 |
13 | "id_property": {
14 | "prototype": "montage/core/meta/property-blueprint",
15 | "properties": {
16 | "name": "id",
17 | "valueType": "string",
18 | "blueprint": {
19 | "@": "root"
20 | }
21 | }
22 | },
23 |
24 | "root": {
25 | "prototype": "montage/core/meta/module-blueprint",
26 | "properties": {
27 | "name": "Component3D",
28 | "propertyBlueprints": [
29 | {
30 | "@": "id_property"
31 | },
32 | {
33 | "@": "scene_property"
34 | }
35 | ],
36 | "propertyBlueprintGroups": {
37 | "Component3D": [
38 | {
39 | "@": "id_property"
40 | },
41 | {
42 | "@": "scene_property"
43 | }
44 | ]
45 | },
46 | "blueprintModule": {
47 | "%": "runtime/component-3d.meta"
48 | },
49 | "exportName": "Component3D",
50 | "module": {
51 | "%": "runtime/component-3d"
52 | }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/runtime/material.meta:
--------------------------------------------------------------------------------
1 | {
2 | "image_property": {
3 | "prototype": "montage/core/meta/property-blueprint",
4 | "properties": {
5 | "name": "image",
6 | "valueType": "string",
7 | "blueprint": {
8 | "@": "root"
9 | }
10 | }
11 | },
12 |
13 | "opacity_property": {
14 | "prototype": "montage/core/meta/property-blueprint",
15 | "properties": {
16 | "name": "opacity",
17 | "valueType": "number",
18 | "blueprint": {
19 | "@": "root"
20 | }
21 | }
22 | },
23 |
24 | "blueprint_parent": {
25 | "prototype": "montage/core/meta/blueprint-reference",
26 | "properties": {
27 | "valueReference": {
28 | "blueprintName": "Component3D",
29 | "blueprintModule": {
30 | "%": "runtime/component-3d.meta"
31 | },
32 | "prototypeName": "Component3D"
33 | }
34 | }
35 | },
36 |
37 | "root": {
38 | "prototype": "montage/core/meta/module-blueprint",
39 | "properties": {
40 | "parent": {"@": "blueprint_parent"},
41 | "name": "Material",
42 | "propertyBlueprints": [
43 | {
44 | "@": "image_property"
45 | },
46 | {
47 | "@": "opacity_property"
48 | }
49 | ],
50 | "propertyBlueprintGroups": {
51 | "Material": [
52 | {
53 | "@": "image_property"
54 | },
55 | {
56 | "@": "opacity_property"
57 | }
58 | ]
59 | },
60 | "blueprintModule": {
61 | "%": "runtime/material.meta"
62 | },
63 | "exportName": "Material",
64 | "module": {
65 | "%": "runtime/material"
66 | }
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/runtime/base.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, Motorola Mobility, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither the name of the Motorola Mobility, Inc. nor the names of its
13 | // contributors may be used to endorse or promote products derived from this
14 | // software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | exports.Base = Object.create(Object.prototype, {
27 |
28 | _properties: { value: null, writable: true },
29 |
30 | properties: {
31 | get: function() {
32 | return this._properties;
33 | },
34 | set: function(value) {
35 | this._properties = value;
36 | }
37 | },
38 |
39 | __Base_init: {
40 | value: function() {
41 | this._properties = {};
42 | }
43 | }
44 |
45 | });
46 |
--------------------------------------------------------------------------------
/runtime/camera.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, Motorola Mobility, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither the name of the Motorola Mobility, Inc. nor the names of its
13 | // contributors may be used to endorse or promote products derived from this
14 | // software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 | var Base = require("runtime/base").Base;
28 |
29 | exports.Camera = Object.create(Base, {
30 |
31 | _projection: { value: null, writable: true },
32 |
33 | projection: {
34 | get: function() {
35 | return this._projection;
36 | },
37 | set: function(value) {
38 | this._projection = value;
39 | }
40 | },
41 |
42 | init: {
43 | value: function() {
44 | this.__Base_init();
45 | return this;
46 | }
47 | }
48 |
49 | });
50 |
51 |
--------------------------------------------------------------------------------
/assets/picking/picking.json:
--------------------------------------------------------------------------------
1 | {
2 | "profile": "WebGL 1.0",
3 | "programs": {
4 | "program_0": {
5 | "fragmentShader": "technique1FS",
6 | "vertexShader": "technique1VS"
7 | }
8 | },
9 | "renderBuffers" : {
10 | "depthBuffer" : {
11 | }
12 | },
13 | "shaders": {
14 | "technique1FS": {
15 | "path": "pickingFS.glsl"
16 | },
17 | "technique1VS": {
18 | "path": "pickingVS.glsl"
19 | }
20 | },
21 | "techniques": {
22 | "pickingTechnique": {
23 | "parameters": {
24 | "pickingColor": {
25 | "type": 35665
26 | },
27 | "position": {
28 | "semantic": "POSITION",
29 | "type": 35665
30 | },
31 | "projectionMatrix": {
32 | "semantic": "PROJECTION",
33 | "type": 35676
34 | },
35 | "worldViewMatrix": {
36 | "semantic": "MODELVIEW",
37 | "type": 35676
38 | }
39 | },
40 | "pass": "defaultPass",
41 | "passes": {
42 | "defaultPass": {
43 | "instanceProgram": {
44 | "attributes": {
45 | "a_position": "position"
46 | },
47 | "program": "program_0",
48 | "uniforms": {
49 | "u_pickingColor": "pickingColor",
50 | "u_projectionMatrix": "projectionMatrix",
51 | "u_worldviewMatrix": "worldViewMatrix"
52 | }
53 | },
54 | "states": {
55 | "blendEnable": 0,
56 | "cullFaceEnable": 1,
57 | "depthMask": 1,
58 | "depthTestEnable": 1,
59 | "extras" : {
60 | "comment" : "we ignore states here, we will use state used by the material associated with the primitive being drawn"
61 | }
62 | }
63 | }
64 | }
65 | }
66 | },
67 | "version": "0.3"
68 | }
--------------------------------------------------------------------------------
/ui/view.reel/view.html:
--------------------------------------------------------------------------------
1 |
2 |
32 |
33 |
34 |
35 |
36 |
37 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/ui/view.reel/view.meta:
--------------------------------------------------------------------------------
1 | {
2 | "scene_property": {
3 | "prototype": "montage/core/meta/property-blueprint",
4 | "properties": {
5 | "name": "scene",
6 | "valueType": "object",
7 | "blueprint": {
8 | "@": "root"
9 | }
10 | }
11 | },
12 |
13 | "viewPoint_property": {
14 | "prototype": "montage/core/meta/property-blueprint",
15 | "properties": {
16 | "name": "viewPoint",
17 | "valueType": "object",
18 | "blueprint": {
19 | "@": "root"
20 | }
21 | }
22 | },
23 |
24 | "width_property": {
25 | "prototype": "montage/core/meta/property-blueprint",
26 | "properties": {
27 | "name": "width",
28 | "valueType": "number",
29 | "blueprint": {
30 | "@": "root"
31 | }
32 | }
33 | },
34 | "height_property": {
35 | "prototype": "montage/core/meta/property-blueprint",
36 | "properties": {
37 | "name": "height",
38 | "valueType": "number",
39 | "blueprint": {
40 | "@": "root"
41 | }
42 | }
43 | },
44 |
45 | "root": {
46 | "prototype": "montage/core/meta/module-blueprint",
47 | "properties": {
48 | "name": "View",
49 | "propertyBlueprints": [
50 | {
51 | "@": "scene_property"
52 | },
53 | {
54 | "@": "viewPoint_property"
55 | },
56 | {
57 | "@": "width_property"
58 | },
59 | {
60 | "@": "height_property"
61 | }
62 | ],
63 | "propertyBlueprintGroups": {
64 | "Main": [
65 | {
66 | "@": "scene_property"
67 | },
68 | {
69 | "@": "viewPoint_property"
70 | },
71 | {
72 | "@": "width_property"
73 | },
74 | {
75 | "@": "height_property"
76 | }
77 | ]
78 | },
79 | "blueprintModule": {
80 | "%": "ui/view/view.meta"
81 | },
82 | "exportName": "View",
83 | "module": {
84 | "%": "ui/view.reel"
85 | }
86 | }
87 | }
88 | }
89 |
--------------------------------------------------------------------------------
/runtime/resource-loader.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | exports.ResourceLoader = Object.create(Object.prototype, {
25 |
26 | webGLRenderer: { value: null, writable:true},
27 |
28 | delegate: { value: null, writable:true},
29 |
30 | _trackedIds: { value: null, writable:true },
31 |
32 | _addTrackedId: {
33 | value: function(trackedId) {
34 | //console.log("add tracked resource:" + trackedId);
35 |
36 | if (this._trackedIds == null) {
37 | this._trackedIds = {};
38 | }
39 | // if (this._trackedIds[trackedId] == null)
40 | // console.log("add track"+trackedId);
41 | this._trackedIds[trackedId] = true;
42 | }
43 | },
44 |
45 | _removeTrackedId: {
46 | value: function(trackedId) {
47 | //console.log("remove track"+trackedId);
48 | if (this._trackedIds[trackedId] == null) {
49 | //we are listening to all request so we ignore this for now.
50 | //console.log("MeshLoader: inconsistency error")
51 | } else {
52 | //console.log("loaded:"+trackedId);
53 | delete this._trackedIds[trackedId];
54 | }
55 | }
56 | }
57 |
58 | });
59 |
--------------------------------------------------------------------------------
/runtime/technique.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, Motorola Mobility, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | var Base = require("runtime/base").Base;
25 |
26 | exports.Technique = Object.create(Base, {
27 |
28 | _parameters: { value: null, writable: true },
29 |
30 | _passName: { value: null, writable: true },
31 |
32 | _passes: { value: null, writable: true },
33 |
34 | init: {
35 | value: function() {
36 | this.__Base_init();
37 | this.passes = {};
38 | return this;
39 | }
40 | },
41 |
42 | parameters: {
43 | get: function() {
44 | return this._parameters;
45 | },
46 | set: function(value) {
47 | this._parameters = value;
48 | }
49 | },
50 |
51 | passName: {
52 | get: function() {
53 | return this._passName;
54 | },
55 | set: function(value) {
56 | if (this._passName != value) {
57 | this._passName = value;
58 | }
59 | }
60 | },
61 |
62 | rootPass: {
63 | get: function() {
64 | return this._passes[this.passName];
65 | }
66 | },
67 |
68 | passesDidChange: {
69 | value: function() {
70 | //update the @pass when passes is changed.
71 | //For convenience set to null if there are multiple passes or to the only pass contained when there is just a single one.
72 | var passesNames = Object.keys(this.passes);
73 | this.passName = (passesNames.length == 1) ? passesNames[0] : null;
74 | }
75 | },
76 |
77 | passes: {
78 | get: function() {
79 | return this._passes;
80 | },
81 | set: function(value) {
82 | if (this._passes != value) {
83 | this._passes = value;
84 | this.passesDidChange();
85 | }
86 | }
87 | },
88 |
89 | execute: {
90 | value: function(webGLRenderer, time, options) {
91 | webGLRenderer.resetStates();
92 | this.rootPass.execute(webGLRenderer, time, options);
93 | }
94 | }
95 |
96 | });
97 |
98 |
--------------------------------------------------------------------------------
/runtime/builtin-assets.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | var Q = require("q");
25 | var RuntimeTFLoader = require("runtime/runtime-tf-loader").RuntimeTFLoader;
26 |
27 | exports.BuiltInAssets = Object.create(Object.prototype, {
28 |
29 | _deferredForName: { value: {}, writable: true },
30 |
31 | _assetInfos: { value: {}, writable: true },
32 |
33 | registerBuiltinAssetsIfNeeded: {
34 | value: function() {
35 | var pickingLocation = require.location + "assets/picking/picking.json";
36 | var gradientLocation = require.location + "assets/gradient/gradient.json";
37 |
38 | this._assetInfos["pickingTechnique"] = { "location" : pickingLocation, "options" : {"ids": ["pickingTechnique"]} };
39 | this._assetInfos["gradient"] = { "location" : gradientLocation };
40 | }
41 | },
42 |
43 | assetInfosForName: {
44 | value: function(name) {
45 | this.registerBuiltinAssetsIfNeeded();
46 | return this._assetInfos[name];
47 | }
48 | },
49 |
50 | assetWithName: {
51 | value: function(assetName, options) {
52 | var deferred = this._deferredForName[assetName];
53 | if (!deferred) {
54 | deferred = Q.defer();
55 | this._deferredForName[assetName] = deferred;
56 | var readerDelegate = {};
57 | readerDelegate.loadCompleted = function (asset) {
58 | deferred.resolve(asset);
59 | }.bind(this);
60 |
61 | var loader = Object.create(RuntimeTFLoader);
62 | var assetInfos = this.assetInfosForName(assetName);
63 | if (!assetInfos) {
64 | deferred.reject("ERROR:"+assetName+" isn't registered as a built-in asset");
65 | } else {
66 | loader.initWithPath(assetInfos.location);
67 | loader.delegate = readerDelegate;
68 | loader.load(null, assetInfos.options);
69 | }
70 | }
71 |
72 | return deferred.promise;
73 | }
74 | }
75 |
76 | });
77 |
--------------------------------------------------------------------------------
/runtime/scene-resource-loader.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | var ResourceLoader = require("runtime/resource-loader").ResourceLoader;
25 | var MeshResourceLoader = require("runtime/mesh-resource-loader").MeshResourceLoader;
26 |
27 | exports.SceneResourceLoader = Object.create(ResourceLoader, {
28 |
29 | _scene: { value:null, writable: true },
30 |
31 | scene: {
32 | get: function() {
33 | return this._scene;
34 | },
35 | set: function(value) {
36 | this._scene = value;
37 | }
38 | },
39 |
40 | meshesDidLoad: {
41 | value: function() {
42 | if (this.delegate) {
43 | this.delegate.sceneResourcesDidPrepare(this.scene);
44 | }
45 | }
46 | },
47 |
48 | loadScene: {
49 | value: function() {
50 | var self = this;
51 | if (this.scene) {
52 | var node = this.scene.rootNode;
53 | var meshes = {};
54 | var meshesSet = [];
55 | node.apply( function(node, parent, parentTransform) {
56 | if (node.meshes) {
57 | if (node.meshes.length) {
58 | node.meshes.forEach( function(mesh) {
59 | if (meshes[mesh.id] == null) {
60 | meshesSet.push(mesh);
61 | meshes[mesh.id] = mesh;
62 | }
63 | }, this);
64 | }
65 | }
66 | return null;
67 | }, true, null);
68 |
69 | var meshResourceLoader = Object.create(MeshResourceLoader).init(meshesSet, self.webGLRenderer, this);
70 | meshResourceLoader.loadMeshes();
71 | }
72 | }
73 | },
74 |
75 | init: {
76 | value: function(scene, webGLRenderer, delegate) {
77 | if (delegate)
78 | this.delegate = delegate;
79 | this.webGLRenderer = webGLRenderer;
80 | this.scene = scene;
81 | webGLRenderer.resourceManager.observers.push(this);
82 | return this;
83 | }
84 | }
85 |
86 | });
87 |
--------------------------------------------------------------------------------
/runtime/resource-description.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, Motorola Mobility, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither the name of the Motorola Mobility, Inc. nor the names of its
13 | // contributors may be used to endorse or promote products derived from this
14 | // software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 | var global = window;
28 |
29 | (function (root, factory) {
30 | if (typeof exports === 'object') {
31 | // Node. Does not work with strict CommonJS, but
32 | // only CommonJS-like enviroments that support module.exports,
33 | // like Node.
34 | factory(module.exports);
35 | } else if (typeof define === 'function' && define.amd) {
36 | // AMD. Register as an anonymous module.
37 | define([], function () {
38 | return factory(root);
39 | });
40 | } else {
41 | // Browser globals
42 | factory(root);
43 | }
44 | }(this, function (root) {
45 | var ResourceDescription = Object.create(Object.prototype, {
46 |
47 | _description: { value: null, writable: true },
48 |
49 | _id: { value: null, writable: true },
50 |
51 | _type: { value: null, writable: true },
52 |
53 | init: {
54 | enumerable: true,
55 | value: function(id, description) {
56 | this._id = id;
57 | this._description = description;
58 | return this;
59 | }
60 | },
61 |
62 | description: {
63 | enumerable: true,
64 | get: function() {
65 | return this._description;
66 | }
67 | },
68 |
69 | id: {
70 | enumerable: true,
71 | get: function() {
72 | return this._id;
73 | },
74 | set: function(value) {
75 | this._id = value;
76 | }
77 | },
78 |
79 | type: {
80 | enumerable: true,
81 | get: function() {
82 | return this._type;
83 | },
84 | set: function(value) {
85 | this._type = value;
86 | }
87 | }
88 |
89 | });
90 |
91 | if(root) {
92 | root.ResourceDescription = ResourceDescription;
93 | }
94 |
95 | return ResourceDescription;
96 |
97 | }));
--------------------------------------------------------------------------------
/runtime/glTF-scene.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | var Montage = require("montage").Montage;
25 | var glTFNode = require("runtime/glTF-node").glTFNode;
26 |
27 | exports.glTFScene = Montage.specialize( {
28 |
29 | constructor: {
30 | value: function glTFScene() {
31 | this.super();
32 | }
33 | },
34 |
35 | _rootNode: { value : null, writable: true },
36 |
37 | rootNode: {
38 | get: function() {
39 | return this._rootNode;
40 | },
41 | set: function(value) {
42 | this._rootNode = value;
43 | }
44 | },
45 |
46 | _id: { value: null, writable: true },
47 |
48 | id: {
49 | get: function() {
50 | return this._id;
51 | },
52 | set: function(value) {
53 | this._id = value;
54 | }
55 | },
56 |
57 | baseURL: { value: null, writable:true },
58 |
59 | _animationManager: { value: null, writable: true },
60 |
61 | animationManager: {
62 | get: function() {
63 | return this._animationManager;
64 | },
65 | set: function(value) {
66 | this._animationManager = value;
67 | }
68 | },
69 |
70 | init: {
71 | value: function() {
72 | this.rootNode = Object.create(glTFNode);
73 | this.rootNode.initWithID();
74 | return this;
75 | }
76 | },
77 |
78 | startTime: {
79 | get: function() {
80 | var startTime = 0;
81 | if (this.animationManager) {
82 | return this.animationManager.startTime;
83 | }
84 | return startTime;
85 | }
86 | },
87 |
88 | endTime: {
89 | get: function() {
90 | var endTime = -1;
91 | if (this.animationManager) {
92 | return this.animationManager.endTime;
93 | }
94 | return endTime;
95 | }
96 | },
97 |
98 | _name: {
99 | value: null,
100 | writable: true
101 | },
102 |
103 | name: {
104 | enumerable: true,
105 | get: function() {
106 | return this._name;
107 | },
108 | set: function(value) {
109 | this._name = value;
110 | }
111 | }
112 | });
113 |
--------------------------------------------------------------------------------
/runtime/node-wrapper.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | require("runtime/dependencies/gl-matrix");
25 | var Utilities = require("runtime/utilities").Utilities;
26 | var TransformHelper = require("runtime/transform-helper").TransformHelper;
27 |
28 | exports.NodeWrapper = Object.create(Object.prototype, {
29 |
30 | _transformHelper: { value: null, writable: true },
31 |
32 | node: {
33 | get: function() {
34 | return this._transformHelper.node;
35 | }
36 | },
37 |
38 | init: {
39 | value: function(node) {
40 | this._transformHelper = Object.create(TransformHelper).init();
41 | this._transformHelper.node = node;
42 | return this;
43 | }
44 | },
45 |
46 | viewPointWillChange: {
47 | value: function(node, prev, transform) {
48 | }
49 | },
50 |
51 | viewPointDidChange: {
52 | value: function() {
53 | this._transformHelper.viewPoint = this._scenePassRenderer.viewPoint;
54 | }
55 | },
56 |
57 | viewPointMatrixDidUpdate: {
58 | value: function() {
59 | this._transformHelper.transformDidUpdate();
60 | }
61 | },
62 |
63 | //-------
64 |
65 | scenePassRenderer: {
66 | get: function() {
67 | return this._scenePassRenderer;
68 | },
69 | set: function(value) {
70 | if (this._scenePassRenderer != value) {
71 | if (this._scenePassRenderer) {
72 | this._scenePassRenderer.removeObserver(this)
73 | }
74 |
75 | this._scenePassRenderer = value;
76 | this._transformHelper.viewMatrix = value._viewPointMatrix;
77 |
78 | if (this._scenePassRenderer) {
79 | this._scenePassRenderer.addObserver(this);
80 | }
81 | }
82 | }
83 | },
84 |
85 | worldMatrix: {
86 | get: function() {
87 | return this.node.worldMatrix;
88 | }
89 | },
90 |
91 | worldViewMatrix: {
92 | get: function() {
93 | return this._transformHelper.worldViewMatrix;
94 | }
95 | },
96 |
97 | worldViewInverseTransposeMatrix: {
98 | get: function() {
99 | return this._transformHelper.worldViewInverseTransposeMatrix;
100 | }
101 | }
102 |
103 | });
104 |
105 |
--------------------------------------------------------------------------------
/runtime/primitive.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, Motorola Mobility, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither the name of the Motorola Mobility, Inc. nor the names of its
13 | // contributors may be used to endorse or promote products derived from this
14 | // software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 | require("runtime/dependencies/gl-matrix");
28 | var Utilities = require("runtime/utilities").Utilities;
29 |
30 | exports.Primitive = Object.create(Object.prototype, {
31 |
32 | _attributesCount: {
33 | enumerable: false,
34 | value: 0,
35 | writable: true
36 | },
37 |
38 | attributesCount : {
39 | enumerable: false,
40 | get: function() {
41 | return this._attributesCount;
42 | }
43 | },
44 |
45 | init: {
46 | value: function() {
47 | this.step = 0;
48 | this.semantics = {};
49 | return this;
50 | }
51 | },
52 |
53 | _semantics: {
54 | enumerable: false,
55 | value: null,
56 | writable: true
57 | },
58 |
59 | semantics: {
60 | enumerable: true,
61 | get: function() {
62 | return this._semantics;
63 | },
64 | set: function(value) {
65 | this._semantics = value;
66 | }
67 | },
68 |
69 | //since semantics/set got simplified we should get rid of this eventually
70 | addVertexAttribute: {
71 | enumerable: false,
72 | value: function(vertexAttribute) {
73 | if (vertexAttribute.semantic === "POSITION") {
74 | var bbox = null;
75 | var accessor = vertexAttribute.attribute;
76 | if (accessor.min && accessor.max) {
77 | bbox = [ accessor.min, accessor.max];
78 | }
79 | this.boundingBox = bbox;
80 | }
81 |
82 | if (!this.semantics[vertexAttribute.semantics]) {
83 | this.semantics[vertexAttribute.semantic] = vertexAttribute.attribute;
84 | this._attributesCount++;
85 | }
86 | }
87 | },
88 |
89 | _computeBBOXIfNeeded: {
90 | enumerable: false,
91 | value: function() {
92 | }
93 | },
94 |
95 | _boundingBox: {
96 | value: null,
97 | writable: true
98 | },
99 |
100 | boundingBox: {
101 | enumerable: true,
102 | get: function() {
103 | this._computeBBOXIfNeeded();
104 | return this._boundingBox;
105 | },
106 | // we let the possibility to override by hand the bounding volume.
107 | set: function(value) {
108 | this._boundingBox = value;
109 | }
110 | },
111 |
112 | _indices: { enumerable: false, value: null, writable: true },
113 |
114 | indices: {
115 | get: function() {
116 | return this._indices;
117 | },
118 | set: function(value) {
119 | this._indices = value;
120 | }
121 | },
122 |
123 | _material: { enumerable: false, value: null, writable: true },
124 |
125 | material: {
126 | get: function() {
127 | return this._material;
128 | },
129 | set: function(value) {
130 | this._material = value;
131 | }
132 | }
133 |
134 | });
135 |
--------------------------------------------------------------------------------
/runtime/mesh.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, Motorola Mobility, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither the name of the Motorola Mobility, Inc. nor the names of its
13 | // contributors may be used to endorse or promote products derived from this
14 | // software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 | require("runtime/dependencies/gl-matrix");
28 | var Base = require("runtime/base").Base;
29 | var Utilities = require("runtime/utilities").Utilities;
30 |
31 | exports.Mesh = Object.create(Base, {
32 |
33 | PRIMITIVES: { value: "primitives" },
34 |
35 | _primitives: {
36 | value: null,
37 | writable: true
38 | },
39 |
40 | primitives: {
41 | enumerable: true,
42 | get: function() {
43 | return this._primitives;
44 | },
45 | set: function(value) {
46 | this._primitives = value;
47 | }
48 | },
49 |
50 | //theses 2 propreties are just for the demo...
51 | step: { value: 0, writable:true },
52 | loadedPrimitivesCount: { value: 0, writable:true },
53 |
54 | loaded: {
55 | get: function() {
56 | return (this.loadedPrimitivesCount === this.primitives.length);
57 | }
58 | },
59 |
60 | _id: {
61 | value: null,
62 | writable: true
63 | },
64 |
65 | id: {
66 | enumerable: true,
67 | get: function() {
68 | return this._id;
69 | },
70 | set: function(value) {
71 | this._id = value;
72 | }
73 | },
74 |
75 | _name: {
76 | value: null,
77 | writable: true
78 | },
79 |
80 | name: {
81 | enumerable: true,
82 | get: function() {
83 | return this._name;
84 | },
85 | set: function(value) {
86 | this._name = value;
87 | }
88 | },
89 |
90 | _computeBBOXIfNeeded: {
91 | enumerable: false,
92 | value: function() {
93 | if ( (!this._boundingBox) && this.primitives) {
94 | var count = this.primitives.length;
95 | if (count > 0) {
96 | var bbox = this.primitives[0].boundingBox;
97 | if (bbox) {
98 | var i;
99 | for (i = 1 ; i < count ; i++) {
100 | if (this.primitives[i].boundingBox) { //it could be not here here as we are loading everything asynchronously
101 | bbox = Utilities.mergeBBox(bbox, this.primitives[i].boundingBox);
102 | }
103 | }
104 | this._boundingBox = bbox;
105 | }
106 | }
107 | }
108 | }
109 | },
110 |
111 | _boundingBox: {
112 | value: null,
113 | writable: true
114 | },
115 |
116 | boundingBox: {
117 | enumerable: true,
118 | get: function() {
119 | this._computeBBOXIfNeeded();
120 | return this._boundingBox;
121 | },
122 | // we let the possibility to override by hand the bounding volume.
123 | set: function(value) {
124 | this._boundingBox = value;
125 | }
126 | },
127 |
128 | init: {
129 | value: function() {
130 | this.__Base_init();
131 | this._primitives = [];
132 | return this;
133 | }
134 | }
135 | });
136 |
--------------------------------------------------------------------------------
/runtime/transform-helper.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Fabrice ROBINET
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | require("runtime/dependencies/gl-matrix");
25 | var Base = require("runtime/base").Base;
26 | var Utilities = require("runtime/utilities").Utilities;
27 |
28 | var TransformHelper = exports.TransformHelper = Object.create(Object.prototype, {
29 |
30 | _viewMatrix: { value: null, writable: true },
31 |
32 | _worldViewMatrix: { value: null, writable: true },
33 |
34 | _worldViewInverseTransposeMatrix: { value: null, writable: true },
35 |
36 | _dirty: { value: true, writable: true },
37 |
38 | _id: { value: 0, writable: true },
39 |
40 | //node observer for the viewPoint.transform and node.transform
41 | transformWillChange: {
42 | value: function(node, prev, transform) {
43 | this._dirty = true;
44 | }
45 | },
46 |
47 | transformDidChange: {
48 | value: function(node) {
49 | }
50 | },
51 |
52 | _node: { value: null, writable: true },
53 |
54 | node: {
55 | set: function(value) {
56 | if (this._node != value) {
57 | if (this._node) {
58 | this._node.transform.removeObserver(this);
59 | }
60 | this._node = value;
61 | if (this._node) {
62 | this._node.transform.addObserver(this);
63 | }
64 | this._dirty = true;
65 | }
66 | },
67 | get: function() {
68 | return this._node;
69 | }
70 | },
71 |
72 | _viewMatrix: { value: null, writable: true },
73 |
74 | viewMatrix: {
75 | set: function(value) {
76 | this._viewMatrix = value;
77 | this._dirty = true;
78 | },
79 | get: function() {
80 | return this._viewMatrix;
81 | }
82 | },
83 |
84 | transformDidUpdate: {
85 | value: function(transform) {
86 | this._dirty = true;
87 | }
88 | },
89 |
90 | updateMatricesIfNeeded: {
91 | value: function() {
92 | if (this._dirty) {
93 | mat4.multiply(this._viewMatrix, this._node.worldMatrix, this._worldViewMatrix);
94 | mat4.toInverseMat3(this._worldViewMatrix, this._worldViewInverseTransposeMatrix);
95 | mat3.transpose(this._worldViewInverseTransposeMatrix);
96 | this._dirty = false;
97 | }
98 | }
99 | },
100 |
101 | worldViewMatrix: {
102 | get: function() {
103 | if (this._dirty) { //add this non-strictly necessary test to potentially prevent a function call
104 | this.updateMatricesIfNeeded();
105 | }
106 | return this._worldViewMatrix;
107 | }
108 | },
109 |
110 | worldViewInverseTransposeMatrix: {
111 | get: function() {
112 | if (this._dirty) { //add this non-strictly necessary test to potentially prevent a function call
113 | this.updateMatricesIfNeeded();
114 | }
115 | return this._worldViewInverseTransposeMatrix;
116 | }
117 | },
118 |
119 | init: {
120 | value: function() {
121 | this._viewMatrix = mat4.identity();
122 | this._worldViewMatrix = mat4.identity();
123 | this._worldViewInverseTransposeMatrix = mat3.identity();
124 | return this;
125 | }
126 | }
127 |
128 | });
129 |
--------------------------------------------------------------------------------
/runtime/scene-helper.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | require("runtime/dependencies/gl-matrix");
25 | var Montage = require("montage").Montage;
26 | var Uuid = require("montage/core/uuid").Uuid;
27 | var glTFScene = require("runtime/glTF-scene").glTFScene;
28 | var glTFNode = require("runtime/glTF-node").glTFNode;
29 | var Scene = require("runtime/scene").Scene;
30 | var Node = require("runtime/node").Node;
31 | var SceneRenderer = require("runtime/scene-renderer").SceneRenderer;
32 | var glTFMaterial = require("runtime/glTF-material").glTFMaterial;
33 | var Utilities = require("runtime/utilities").Utilities;
34 | var Projection = require("runtime/projection").Projection;
35 | var Camera = require("runtime/camera").Camera;
36 | var BBox = require("runtime/utilities").BBox;
37 |
38 | var SceneHelper = exports.SceneHelper = Object.create(Object.prototype, {
39 |
40 | getGLTFViewPoints: {
41 | value: function(scene) {
42 | var viewPoints = [];
43 | var node = scene.glTFElement.rootNode;
44 | node.apply( function(node, parent, parentTransform) {
45 | if (node.cameras) {
46 | if (node.cameras.length)
47 | viewPoints = viewPoints.concat(node);
48 | }
49 | return null;
50 | }, true, null);
51 | return viewPoints;
52 | }
53 | },
54 |
55 | //we don't want to cache this to avoid synchronization here, so we don't want to call it often either :)
56 | getViewPoints: {
57 | value: function(scene) {
58 | var viewPoints = this.getGLTFViewPoints(scene);
59 | var m3dNodes = [];
60 | viewPoints.forEach( function(viewPoint) {
61 | var m3dNode = Montage.create(Node);
62 | m3dNode.scene = scene;
63 | //FIXME: should have probably used baseId here
64 | m3dNode.id = viewPoint.baseId;
65 | m3dNodes.push(m3dNode);
66 | }, this);
67 |
68 | return m3dNodes;
69 | }
70 | },
71 |
72 | createGLTFNodeIncludingCamera: {
73 | value: function(cameraName) {
74 | //TODO: make that a default projection method
75 | var projection = Object.create(Projection);
76 | projection.initWithDescription( {
77 | "type":"perspective",
78 | "perspective" : {
79 | "yfov":45,
80 | "aspectRatio":1,
81 | "znear":0.1,
82 | "zfar":100
83 | }
84 | });
85 |
86 | //create camera
87 | var camera = Object.create(Camera).init();
88 | camera.projection = projection;
89 | //create node to hold the camera
90 | var cameraNode = Object.create(glTFNode).init();
91 | camera.name = cameraNode.name = cameraName;
92 | cameraNode.id = Uuid.generate();
93 | cameraNode.baseId = cameraNode.id;
94 | cameraNode.cameras.push(camera);
95 | return cameraNode;
96 | }
97 | },
98 |
99 | createNodeIncludingCamera: {
100 | value: function(cameraName, m3dScene) {
101 | var cameraNode = SceneHelper.createGLTFNodeIncludingCamera(cameraName);
102 | var scene = m3dScene.glTFElement;
103 | scene.ids[cameraNode.baseId] = cameraNode;
104 | var m3dNode = Montage.create(Node);
105 | m3dNode.scene = m3dScene;
106 | m3dNode.id = cameraNode.baseId;
107 | return m3dNode;
108 | }
109 | }
110 |
111 | });
112 |
--------------------------------------------------------------------------------
/assets/gradient/gradient.json:
--------------------------------------------------------------------------------
1 | {
2 | "asset": {
3 | "generator": "hand-written"
4 | },
5 | "accessors": {
6 | "attribute_22": {
7 | "bufferView": "bufferView_28",
8 | "byteOffset": 0,
9 | "byteStride": 12,
10 | "count": 4,
11 | "max": [
12 | 0.5,
13 | 0.5,
14 | 0.5
15 | ],
16 | "min": [
17 | -0.5,
18 | -0.5,
19 | -0.5
20 | ],
21 | "type": 35665
22 | },
23 | "indices_20": {
24 | "bufferView": "bufferView_29",
25 | "byteOffset": 0,
26 | "count": 6,
27 | "type": 5123
28 | }
29 |
30 | },
31 | "bufferViews": {
32 | "bufferView_28": {
33 | "buffer": "gradient.bin",
34 | "byteLength": 48,
35 | "byteOffset": 0,
36 | "target": 34962
37 | },
38 | "bufferView_29": {
39 | "buffer": "gradient.bin",
40 | "byteLength": 12,
41 | "byteOffset": 48,
42 | "target": 34963
43 | }
44 | },
45 | "buffers": {
46 | "gradient.bin": {
47 | "byteLength": 60,
48 | "path": "gradient.bin"
49 | }
50 | },
51 | "cameras": {
52 | "camera_0": {
53 | "type": "orthographic",
54 | "orthographic" : {
55 | "xmag": 1,
56 | "ymag": 1,
57 | "zfar": 1000,
58 | "znear": 0
59 | }
60 | }
61 | },
62 | "materials": {
63 | "material.0": {
64 | "instanceTechnique": {
65 | "technique": "technique1"
66 | },
67 | "name": "blinn3"
68 | }
69 | },
70 | "meshes": {
71 | "quad_mesh": {
72 | "name": "quad_mesh",
73 | "primitives": [
74 | {
75 | "indices": "indices_20",
76 | "material": "material.0",
77 | "primitive": 4,
78 | "attributes": {
79 | "POSITION": "attribute_22"
80 | }
81 | }
82 | ]
83 | }
84 | },
85 | "nodes": {
86 | "node_0": {
87 | "meshes": [
88 | "quad_mesh"
89 | ],
90 | "name": "quad"
91 | },
92 | "node_1": {
93 | "camera": "camera_0",
94 | "name": "camera1"
95 | }
96 | },
97 | "profile": "WebGL 1.0",
98 | "programs": {
99 | "program_0": {
100 | "fragmentShader": "gradient0FS",
101 | "vertexShader": "gradient0VS"
102 | }
103 | },
104 | "scene": "defaultScene",
105 | "scenes": {
106 | "defaultScene": {
107 | "nodes": [
108 | "node_0",
109 | "node_1"
110 | ]
111 | }
112 | },
113 | "shaders": {
114 | "gradient0FS": {
115 | "path": "gradient0FS.glsl"
116 | },
117 | "gradient0VS": {
118 | "path": "gradient0VS.glsl"
119 | }
120 | },
121 | "techniques": {
122 | "technique1": {
123 | "parameters": {
124 | "color0": {
125 | "type": 35665,
126 | "value": [
127 | 1,
128 | 1,
129 | 1
130 | ]
131 | },
132 | "color1": {
133 | "type": 35665,
134 | "value": [
135 | 0,
136 | 0,
137 | 0
138 | ]
139 | },
140 | "position": {
141 | "semantic": "POSITION",
142 | "type": 35665
143 | },
144 | "projectionMatrix": {
145 | "semantic": "PROJECTION",
146 | "type": 35676
147 | }
148 | },
149 | "pass": "gradientPass",
150 | "passes": {
151 | "gradientPass": {
152 | "instanceProgram": {
153 | "attributes": {
154 | "a_position": "position"
155 | },
156 | "program": "program_0",
157 | "uniforms": {
158 | "u_color0": "color0",
159 | "u_color1": "color1",
160 | "u_projectionMatrix": "projectionMatrix"
161 | }
162 | },
163 | "states": {
164 | "blendEnable": 1,
165 | "blendEquation": 32774,
166 | "blendFunc": {
167 | "dfactor": 771,
168 | "sfactor": 770
169 | },
170 | "cullFaceEnable": 0,
171 | "depthMask": 0,
172 | "depthTestEnable": 0
173 | }
174 | }
175 | }
176 | }
177 | }
178 | }
--------------------------------------------------------------------------------
/runtime/skin.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013,Fabrice Robinet.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | require("runtime/dependencies/gl-matrix");
25 | var Base = require("runtime/base").Base;
26 | var Transform = require("runtime/transform").Transform;
27 | var Utilities = require("runtime/utilities").Utilities;
28 |
29 | exports.Skin = Object.create(Object.prototype, {
30 |
31 | jointsIds: { value: null, writable: true },
32 |
33 | nodesForSkeleton: { value: null, writable: true },
34 |
35 | bindShapeMatrix: { value: null, writable: true },
36 |
37 | inverseBindMatricesDescription: { value: null, writable: true },
38 |
39 | matricesForSkeleton: { value: null, writable: true },
40 |
41 | sources: { value: null, writable: true },
42 |
43 | init: {
44 | value: function() {
45 | this.jointsIds = [];
46 | this.nodesForSkeleton = {};
47 | this.matricesForSkeleton = {};
48 | this.sources = [];
49 | return this;
50 | }
51 | },
52 |
53 | inverseBindMatricesDelegate: {
54 | value: {
55 | handleError: function(errorCode, info) {
56 | console.log("ERROR:vertexAttributeBufferDelegate:"+errorCode+" :"+info);
57 | },
58 |
59 | convert: function (source, resource, ctx) {
60 | return new Float32Array(resource);
61 | },
62 |
63 | resourceAvailable: function (glResource, ctx) {
64 | }
65 | }
66 | },
67 |
68 | process: {
69 | value: function(node, resourceManager) {
70 | var skeletons = Object.keys(this.nodesForSkeleton);
71 |
72 | var objectSpace = mat4.create();
73 | mat4.inverse(node.worldMatrix, objectSpace);
74 |
75 | skeletons.forEach(function(skeleton) {
76 | var nodes = this.nodesForSkeleton[skeleton];
77 | var matrices = this.matricesForSkeleton[skeleton];
78 | if (!matrices) {
79 | var length = 16 * this.jointsIds.length;
80 | matrices = new Float32Array(length);
81 | this.matricesForSkeleton[skeleton] = matrices;
82 | var identity = mat4.identity();
83 | for (var i = 0 ; i < length ; i++) {
84 | matrices[i] = identity[i % 16];
85 | }
86 | }
87 | var inverseBindMatrices = resourceManager.getResource(this.inverseBindMatricesDescription, this.inverseBindMatricesDelegate);
88 | if (inverseBindMatrices) {
89 | this.sources.forEach(function(source) {
90 | //FIXME: assume mesh here but it could be morph (later..)
91 | var mesh = source;
92 |
93 | var BSM = this.bindShapeMatrix;
94 | var jointsCount = this.jointsIds.length;
95 | var IBM = mat4.create();
96 | for (var i = 0; i < jointsCount ; i++) {
97 | for (var j = 0; j < 16 ; j++) {
98 | IBM[j] = inverseBindMatrices[(i * 16) + j];
99 | }
100 |
101 | var JM = nodes[i].worldMatrix;
102 | var destMat = mat4.identity();
103 | mat4.multiply(destMat, objectSpace);
104 | mat4.multiply(destMat, JM);
105 | mat4.multiply(destMat, IBM);
106 | mat4.multiply(destMat, BSM);
107 | for (var j = 0; j < 16 ; j++) {
108 | matrices[(i*16)+j] = destMat[j];
109 | }
110 | }
111 |
112 | mesh.primitives.forEach(function(primitive) {
113 | if (primitive.material.parameters) {
114 | primitive.material.parameters["jointMat"].value = matrices;
115 | }
116 | }, this)
117 | }, this);
118 | }
119 | }, this);
120 | }
121 | }
122 |
123 | });
124 |
--------------------------------------------------------------------------------
/runtime/glTF-material.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, Motorola Mobility, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither the name of the Motorola Mobility, Inc. nor the names of its
13 | // contributors may be used to endorse or promote products derived from this
14 | // software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 | require("runtime/dependencies/gl-matrix");
28 | var Base = require("runtime/base").Base;
29 | var Technique = require("runtime/technique").Technique;
30 | var Pass = require("runtime/pass").Pass;
31 | var GLSLProgram = require("runtime/glsl-program").GLSLProgram;
32 | var ResourceDescription = require("runtime/resource-description").ResourceDescription;
33 |
34 | exports.glTFMaterial = Object.create(Base, {
35 |
36 | /*
37 | animationDuration: { value: 0.7, writable: false},
38 | animationDelegate: { value: null, writable: true},
39 | _techniqueForID: { value: {}, writable: true },
40 | inputWillChange: {
41 | value: function(name, value) {
42 | }
43 | },
44 |
45 | //update the technique when change parameters
46 | //the combinatory possibilties could explode here, and should not be handled that way for future devs..
47 | inputDidChange: {
48 | value: function(name) {
49 |
50 | }
51 | },
52 |
53 | _addInputPropertyIfNeeded: {
54 | value: function(property) {
55 | var privateName = "_" + property;
56 | var self = this;
57 | if (this.inputs.hasOwnProperty(property) === false) {
58 | Object.defineProperty(this.inputs, privateName, { writable:true , value: null });
59 |
60 | Object.defineProperty(this.inputs, property, {
61 | get: function() { return self.inputs[privateName]; },
62 | set: function(value) {
63 | var currentValue = self.inputs[property];
64 | self.inputWillChange.call(self, property, value);
65 | if ((property === "diffuseTexture")||(property === "reflectionTexture")) {
66 | if (typeof value === "string") {
67 | var texture = value;
68 | var imageResource = Object.create(ResourceDescription).init(texture, { path: texture });
69 | imageResource.type = "image";
70 | value = imageResource;
71 | } else if (value !== null) {
72 | var image = value;
73 | //check if the uuid that we potentially stored is here
74 | var uuid = image["__uuid"];
75 | if (!uuid) {
76 | image["__uuid"] = image.src ? src.split("/").join("_") : Uuid.generate();
77 | }
78 |
79 | var imageResource = Object.create(ResourceDescription).init(uuid, { "image": image });
80 | imageResource.type = "image";
81 | value = imageResource;
82 | }
83 | }
84 | self.inputs[privateName] = value;
85 | self.inputDidChange.call(self, property);
86 | }
87 | });
88 | }
89 | }
90 | },
91 |
92 | _prepareInputsProperties: {
93 | value: function() {
94 | var properties = ["diffuseColor", "diffuseTexture", "transparency", "reflectionTexture", "reflectionIntensity", "shininess", "specularColor"];
95 | properties.forEach( function(property) {
96 | this._addInputPropertyIfNeeded(property);
97 | }, this);
98 | }
99 | },
100 | */
101 |
102 | techniqueDidChange: {
103 | value: function() {
104 | //first thing when a technique is changed check for symbols.
105 | //these symbols will provides the names of the parameters to be tracked.
106 |
107 | }
108 | },
109 |
110 | _technique: { value: null, writable: true },
111 |
112 | technique: {
113 | enumerable: false,
114 | get: function() {
115 | return this._technique;
116 | },
117 | set: function(value) {
118 | if (this._technique !== value) {
119 | this._technique = value;
120 | this.techniqueDidChange();
121 | }
122 | }
123 | },
124 |
125 | _parameters: { value: null, writable: true },
126 |
127 | parameters: {
128 | enumerable: false,
129 | get: function() {
130 | return this._parameters;
131 | },
132 | set: function(value) {
133 | this._parameters = value;
134 | }
135 | },
136 |
137 | init: {
138 | value: function(id) {
139 | this.id = id;
140 | this.__Base_init();
141 | this._parameters = {};
142 | return this;
143 | }
144 | }
145 |
146 | });
--------------------------------------------------------------------------------
/runtime/scene.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | var Montage = require("montage").Montage;
25 | var Node = require("runtime/node").Node;
26 | var RuntimeTFLoader = require("runtime/runtime-tf-loader").RuntimeTFLoader;
27 | var URL = require("montage/core/url");
28 | var SceneResourceLoader = require("runtime/scene-resource-loader").SceneResourceLoader;
29 | var Q = require("q");
30 | var Target = require("montage/core/target").Target;
31 |
32 | exports.Scene = Target.specialize( {
33 |
34 | constructor: {
35 | value: function Scene() {
36 | this.super();
37 | }
38 | },
39 |
40 | _resourcesLoaded: { value: false, writable: true },
41 |
42 | _rootNode: { value: null, writable: true },
43 |
44 | rootNode: {
45 | get: function() {
46 | if (this.status === "loaded") {
47 | if (this._rootNode == null) {
48 | this._rootNode = Montage.create(Node);
49 | this._rootNode.scene = this;
50 | this._rootNode.id = this.glTFElement.rootNode.id;
51 | }
52 | }
53 | return this._rootNode;
54 | }
55 | },
56 |
57 | sceneResourcesDidPrepare: {
58 | value: function() {
59 | if (!this._resourcesLoaded) {
60 | if (this._prepareToRenderDefer) {
61 | this._prepareToRenderDefer.resolve();
62 | }
63 | this._resourcesLoaded = true;
64 | //FIXME: we should pass { scene:scene webGLContext:webGLContext
65 | //only problem now is pass the webGLContext through the promise properly
66 | this.dispatchEventNamed("resourcesDidLoad", true, false, this);
67 | this.status = "loaded";
68 | }
69 | }
70 | },
71 |
72 | isLoaded: {
73 | value: function() {
74 | return this.status == "loaded";
75 | }
76 | },
77 |
78 | status: { value: 0, writable:true},
79 |
80 | path: {
81 | set: function(value) {
82 | //Work-around until montage implements textfield that do not send continous input..
83 | if (value) {
84 | if (value.indexOf(".json") === -1)
85 | return;
86 |
87 | var URLObject = URL.parse(value);
88 | if (!URLObject.scheme) {
89 | var packages = Object.keys(require.packages);
90 | //HACK: for demo, packages[0] is guaranted to be the entry point
91 | value = URL.resolve(packages[0], value);
92 | }
93 | }
94 |
95 | if (value !== this._path) {
96 | var self = this;
97 | var readerDelegate = {};
98 | readerDelegate.loadCompleted = function (scene) {
99 | this.totalBufferSize = loader.totalBufferSize;
100 | this.glTFElement = scene;
101 | this.status = "loaded";
102 | console.log("scene loaded:"+this._path);
103 | }.bind(this);
104 |
105 | if (value) {
106 | var loader = Object.create(RuntimeTFLoader);
107 | this.status = "loading";
108 | loader.initWithPath(value);
109 | loader.delegate = readerDelegate;
110 | loader.load(null /* userInfo */, null /* options */);
111 | } else {
112 | this.scene = null;
113 | }
114 |
115 | this._path = value;
116 | }
117 | },
118 |
119 | get: function() {
120 | return this._path;
121 | }
122 | },
123 |
124 | _prepareToRenderDefer: { value: null, writable: true },
125 |
126 | /*
127 | This method doesn't need to be called directly if the rendering is done via a view.
128 | */
129 | prepareToRender: {
130 | value: function(webGLRenderer) {
131 | if (this._prepareToRenderDefer == null) {
132 | this._prepareToRenderDefer = Q.defer();
133 | var sceneResourceLoader = Object.create(SceneResourceLoader).init(this.glTFElement, webGLRenderer, this);
134 | sceneResourceLoader.loadScene();
135 | }
136 |
137 | return this._prepareToRenderDefer.promise;
138 | }
139 | },
140 |
141 | _styleSheets: { value: null, writable: true },
142 |
143 | styleSheets: {
144 | get: function() {
145 | return this._styleSheets;
146 | },
147 |
148 | set: function(value) {
149 | this._styleSheets = value;
150 | }
151 | },
152 |
153 | init: {
154 | value:function(glTFElement) {
155 | if (glTFElement) {
156 | this.glTFElement = glTFElement;
157 | this.status = "loaded";
158 | }
159 | return this;
160 | }
161 | }
162 |
163 | });
164 |
--------------------------------------------------------------------------------
/ui/scene-viewer.reel/scene-viewer.js:
--------------------------------------------------------------------------------
1 | var Montage = require("montage").Montage;
2 | var Component = require("montage/ui/component").Component;
3 | var Utilities = require("runtime/utilities").Utilities;
4 | var SceneHelper = require("runtime/scene-helper").SceneHelper;
5 |
6 | exports.SceneViewer = Component.specialize({
7 |
8 | /**
9 | * The Scene Object
10 | * @type {Object}
11 | */
12 | scene: {
13 | get: function() {
14 | return this._scene;
15 | },
16 | set: function(value) {
17 | if (value != this._scene) {
18 | this._scene = value;
19 | this.sceneDidChange();
20 | }
21 | }
22 | },
23 |
24 | /**
25 | * View that performs rendering of the Scene
26 | * @type {Object}
27 | */
28 | sceneView: {
29 | get: function() {
30 | return this.templateObjects ? this.templateObjects.sceneView : null;
31 | }
32 | },
33 |
34 | /**
35 | * If true the viewer will automatically switch from one animated viewPoint to another
36 | * @type {boolean}
37 | * @default true
38 | */
39 | automaticallyCyclesThroughViewPoints: { value: true, writable: true },
40 |
41 | play: {
42 | value: function() {
43 | if (this.sceneView) {
44 | this.sceneView.play();
45 | }
46 | }
47 | },
48 |
49 | pause: {
50 | value: function() {
51 | if (this.sceneView) {
52 | this.sceneView.pause();
53 | }
54 | }
55 | },
56 |
57 | stop: {
58 | value: function() {
59 | if (this.sceneView) {
60 | this.sceneView.stop();
61 | }
62 | }
63 | },
64 |
65 | /* private */
66 |
67 | _scene: { value: null, writable: true },
68 |
69 | constructor: {
70 | value: function SceneViewer () {
71 | this.super();
72 | }
73 | },
74 |
75 | /* internal montage framework + callbacks from various delegates */
76 |
77 | _sceneDidLoad: {
78 | value: function(scene) {
79 | if (scene.glTFElement) {
80 | if (this.scene.glTFElement.animationManager) {
81 | if (this.scene.glTFElement.animationManager) {
82 | this.scene.glTFElement.animationManager.delegate = this;
83 | }
84 | }
85 | }
86 | }
87 | },
88 |
89 | handleStatusChange: {
90 | value: function(status, key, object) {
91 | if (status === "loaded") {
92 | this._sceneDidLoad(object);
93 | //Work-around
94 | var self = this;
95 | setTimeout(function() {
96 | self.scene.removeOwnPropertyChangeListener("status", self);
97 | }, 1);
98 |
99 | }
100 | }
101 | },
102 |
103 | sceneDidChange: {
104 | value: function() {
105 | if (this.scene) {
106 | if (this.scene.isLoaded()) {
107 | this._sceneDidLoad(this.scene);
108 | } else {
109 | this.scene.addOwnPropertyChangeListener("status", this);
110 | }
111 |
112 | }
113 | if (this.sceneView) {
114 | this.sceneView.scene = this.scene;
115 | }
116 | }
117 | },
118 |
119 | sceneTimeWillChange: {
120 | value: function(animation, upcomingSceneTime) {
121 |
122 | }
123 | },
124 |
125 | sceneTimeDidChange: {
126 | value: function(animation) {
127 |
128 | if (this.scene == null)
129 | return;
130 | if (this.scene.glTFElement == null) {
131 | return;
132 | }
133 |
134 | var endTime = this.scene.glTFElement.endTime;
135 | if ((endTime !== -1) && (this.sceneView != null)) {
136 | var animationManager = this.scene.glTFElement.animationManager;
137 | if (animationManager.sceneTime / 1000. > endTime) {
138 | if (this.automaticallyCyclesThroughViewPoints == true) {
139 | var viewPointIndex = this.sceneView._viewPointIndex; //_viewPointIndex is private in view, we could actually put/access this info from scene
140 | var viewPoints = SceneHelper.getViewPoints(this.scene);
141 | if (viewPoints.length > 0) {
142 | var nextViewPoint;
143 | var checkIdx = 0;
144 | do {
145 | animationManager.sceneTime = 0;
146 | checkIdx++;
147 | viewPointIndex = ++viewPointIndex % viewPoints.length;
148 | nextViewPoint = viewPoints[viewPointIndex];
149 | } while ((checkIdx < viewPoints.length) && (animationManager.nodeHasAnimatedAncestor(nextViewPoint.glTFElement) == false));
150 | this.sceneView.viewPoint = nextViewPoint;
151 | }
152 | }
153 | }
154 | }
155 | }
156 | },
157 |
158 | templateDidLoad:{
159 | value:function () {
160 | //we ensure that we'll have the scene propagated to view by calling sceneDidChange() in templateDidLoad
161 | this.sceneDidChange();
162 | this.needsDraw = true;
163 | this.sceneView.needsDraw = true;
164 |
165 | }
166 | },
167 |
168 | enterDocument: {
169 | value: function(firstTime) {
170 | window.addEventListener("resize", this, true);
171 | }
172 | },
173 |
174 | exitDocument: {
175 | value: function() {
176 | window.removeEventListener("resize", this, true);
177 | }
178 | },
179 |
180 | draw: {
181 | value: function() {
182 | }
183 | },
184 |
185 | willDraw: {
186 | value: function() {
187 | if (this.sceneView) {
188 | this.sceneView.needsDraw = true;
189 | }
190 | }
191 | },
192 |
193 | /* dom */
194 |
195 | captureResize: {
196 | value: function(evt) {
197 | this.needsDraw = true;
198 |
199 | var w = this.element.offsetWidth;
200 | var h = this.element.offsetHeight;
201 |
202 | this.sceneView.width = w;
203 | this.sceneView.height = h;
204 | this.sceneView.needsDraw = true;
205 |
206 | }
207 | }
208 |
209 | });
210 |
--------------------------------------------------------------------------------
/runtime/mesh-resource-loader.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | var ResourceLoader = require("runtime/resource-loader").ResourceLoader;
25 |
26 | exports.MeshResourceLoader = Object.create(ResourceLoader, {
27 |
28 | meshes: { value: null, writable:true},
29 |
30 | fireMeshesDidLoadIfNeeded: {
31 | value: function() {
32 |
33 | var ids = Object.keys(this._trackedIds);
34 | if (ids) {
35 | if (ids.length == 0) {
36 | if (this.delegate) {
37 | if (this.delegate.meshesDidLoad) {
38 | //FIXME: stop being an observer here
39 | this.delegate.meshesDidLoad(this.meshes);
40 | }
41 | }
42 | }
43 | }
44 | }
45 | },
46 |
47 | resourceAvailable: {
48 | value: function(resourceId) {
49 | //console.log("resource available:" + resourceId);
50 |
51 | this._removeTrackedId(resourceId);
52 | this.fireMeshesDidLoadIfNeeded();
53 | }
54 | },
55 |
56 | //load and upload to VRAM
57 | _fetchResources: {
58 | value: function(delegate, resources, ctx) {
59 | var webGLContext = this.webGLRenderer.webGLContext;
60 |
61 | //Load images an upload texture
62 | var resourceIds = Object.keys(resources);
63 | resourceIds.forEach(function(resourceId) {
64 | //FIXME: handle the case of vertexBuffer who expect the resource to be passed as context
65 | //We want here to change the resource manager to prevent this
66 | //convert/resourveAvailable method of delegate should have resource has first argument
67 | var resource = this.webGLRenderer.resourceManager.getResource(resources[resourceId], delegate, webGLContext);
68 | if (resource == null) {
69 | this._addTrackedId(resourceId);
70 | }
71 | }, this);
72 | }
73 | },
74 |
75 | _fetchAllResources: {
76 | value: function(resources) {
77 | var webGLContext = this.webGLRenderer.webGLContext;
78 |
79 | this._fetchResources(this.webGLRenderer.vertexAttributeBufferDelegate, resources.vertexBuffers, true);
80 | this._fetchResources(this.webGLRenderer.indicesDelegate, resources.allIndices);
81 | this._fetchResources(this.webGLRenderer.textureDelegate, resources.textures);
82 | this._fetchResources(this.webGLRenderer.programDelegate, resources.programs);
83 |
84 | //attempt a call to fireMeshesDidLoadIfNeeded just in case if nothing has to be fetched.
85 | //this might be more efficient to not go through the callback and return a bool here.
86 | this.fireMeshesDidLoadIfNeeded();
87 | }
88 | },
89 |
90 | _trackProgramsFromMaterial: {
91 | value: function(material, programs) {
92 | var technique = material.technique;
93 | if (technique) {
94 | for (var passId in technique.passes) {
95 | var pass = technique.passes[passId];
96 | var instanceProgram = pass.instanceProgram;
97 | if (instanceProgram) {
98 | programs[instanceProgram.program.id] = instanceProgram.program;
99 | this._addTrackedId(instanceProgram.program.id);
100 | }
101 | }
102 | }
103 | }
104 | },
105 |
106 | _trackTexturesFromMaterial: {
107 | value: function(material, textures) {
108 | var parameters = material.parameters;
109 | if (parameters) {
110 | var parametersKeys = Object.keys(parameters);
111 | if (parametersKeys.length > 0) {
112 | parametersKeys.forEach(function(parameterKey) {
113 | var parameter = parameters[parameterKey];
114 | if (parameter) {
115 | if (parameter.value) {
116 | var value = parameter.value;
117 | if ((value.type === "texture")) {
118 | textures[value.id] = value;
119 | this._addTrackedId(value.id);
120 | }
121 | }
122 | }
123 | }, this);
124 | }
125 | }
126 | }
127 | },
128 |
129 |
130 | _trackIndicesFromPrimitive: {
131 | value: function(primitive, allIndices) {
132 | var indices = primitive.indices;
133 | allIndices[indices.id] = indices;
134 | this._addTrackedId(indices.id);
135 | }
136 | },
137 |
138 | _trackVertexBuffersFromPrimitive: {
139 | value: function(primitive, vertexBuffers) {
140 | for (var semantic in primitive.semantics) {
141 | var vertexBuffer = primitive.semantics[semantic];
142 | vertexBuffers[vertexBuffer.id] = vertexBuffer;
143 | this._addTrackedId(vertexBuffer.id);
144 | }
145 | }
146 | },
147 |
148 | _trackMesh: {
149 | value: function(mesh, resources, webGLRenderer) {
150 |
151 | mesh.primitives.forEach( function(primitive) {
152 | this._trackTexturesFromMaterial(primitive.material, resources.textures);
153 | this._trackIndicesFromPrimitive(primitive, resources.allIndices);
154 | this._trackVertexBuffersFromPrimitive(primitive, resources.vertexBuffers);
155 | this._trackProgramsFromMaterial(primitive.material, resources.programs);
156 |
157 | }, this);
158 |
159 | }
160 | },
161 |
162 | _trackMeshes: {
163 | value: function(resources) {
164 | this.meshes.forEach( function(mesh) {
165 | this._trackMesh(mesh, resources, this.webGLRenderer);
166 | }, this);
167 | }
168 | },
169 |
170 | loadMeshes: {
171 | value: function() {
172 | var resources = {};
173 | //+ animations ? maybe not required in the pass of this
174 | //+ programs
175 |
176 | resources.textures = {};
177 | resources.allIndices = {};
178 | resources.vertexBuffers = {};
179 | resources.programs = {};
180 |
181 | this._trackMeshes(resources);
182 | this._fetchAllResources(resources, this.webGLRenderer);
183 | }
184 | },
185 |
186 | init: {
187 | value: function(meshes, webGLRenderer, delegate) {
188 | this.delegate = delegate;
189 | this.webGLRenderer = webGLRenderer;
190 | this.meshes = meshes;
191 | webGLRenderer.resourceManager.observers.push(this);
192 | return this;
193 | }
194 | }
195 |
196 | });
197 |
--------------------------------------------------------------------------------
/controllers/camera-controller.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Fabrice ROBINET
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | require("runtime/dependencies/gl-matrix");
25 | var Utilities = require("runtime/utilities").Utilities;
26 | var Transform = require("runtime/transform").Transform;
27 | var Montage = require("montage").Montage;
28 |
29 | exports.CameraController = Montage.specialize( {
30 |
31 | // Montage
32 | constructor: {
33 | value: function View() {
34 | this.super();
35 |
36 | this._lastPosition = [0 ,0];
37 | }
38 | },
39 |
40 | _viewPoint: { value: null, writable: true},
41 |
42 | viewPoint: {
43 | get: function() {
44 | return this._viewPoint;
45 | },
46 | set: function(value) {
47 | if (this._viewPoint != value) {
48 | this._viewPoint = value;
49 | this.zoomStep = 0;
50 | }
51 | }
52 | },
53 |
54 | _node: { value: null, writable: true},
55 |
56 | zoomStep: { value: 0, writable: true },
57 |
58 | node: {
59 | get: function() {
60 | return this._node;
61 | },
62 | set: function(value) {
63 | if (this._node != value) {
64 | this._node = value;
65 | this.zoomStep = 0;
66 | }
67 | }
68 | },
69 |
70 | _lastPosition: { value: null, writable: true },
71 |
72 | _transform: { value: null, writable: true },
73 |
74 | _axisUp: { value: null, writable: true },
75 |
76 | zoom: {
77 | value: function(event) {
78 | if (this.moving)
79 | return;
80 |
81 | var self = this;
82 | var direction = vec3.create();
83 | var eye = vec3.create(this.viewPoint.glTFElement.transform.translation);
84 |
85 | var targetPosition;
86 | var rootNode = this.node.glTFElement;
87 | var sceneBBox = rootNode.getBoundingBox(true);
88 | targetPosition = [
89 | (sceneBBox[0][0] + sceneBBox[1][0]) / 2,
90 | (sceneBBox[0][1] + sceneBBox[1][1]) / 2,
91 | (sceneBBox[0][2] + sceneBBox[1][2]) / 2];
92 |
93 | if (this.zoomStep == 0) {
94 | var lg = vec3.createFrom(sceneBBox[1][0] - sceneBBox[0][0], sceneBBox[1][1] - sceneBBox[0][1], sceneBBox[1][2] - sceneBBox[0][2])
95 | this.zoomStep = 0.0001 * vec3.length(lg);
96 |
97 | }
98 |
99 | direction[0] = targetPosition[0] - eye[0];
100 | direction[1] = targetPosition[1] - eye[1];
101 | direction[2] = targetPosition[2] - eye[2];
102 | vec3.normalize(direction);
103 |
104 | eye[0] += this.zoomStep * direction[0] * event.wheelDeltaY;
105 | eye[1] += this.zoomStep * direction[1] * event.wheelDeltaY;
106 | eye[2] += this.zoomStep * direction[2] * event.wheelDeltaY;
107 |
108 | this.viewPoint.glTFElement.transform.translation = eye;
109 | }
110 | },
111 |
112 | translate: {
113 | value: function(event) {
114 | this._transform.matrix = this.viewPoint.glTFElement.worldMatrix;
115 | if (this.moving == false)
116 | return;
117 |
118 | var xDelta = event.translateX - this._lastPosition[0];
119 | var yDelta = event.translateY - this._lastPosition[1];
120 |
121 | this._lastPosition[0] = event.translateX;
122 | this._lastPosition[1] = event.translateY;
123 |
124 | xDelta *= 0.05;
125 | yDelta *= -0.05;
126 |
127 | //if (this._axisUp == null) {
128 | this._axisUp = vec3.createFrom(0, 1, 0);
129 | mat4.rotateVec3(this._transform.matrix, this._axisUp);
130 | //}
131 | var hasTarget = false;
132 | var targetPosition;
133 | if (hasTarget == false) {
134 | var rootNode = this.node.glTFElement;
135 | var sceneBBox = rootNode.getBoundingBox(true);
136 | targetPosition = [
137 | (sceneBBox[0][0] + sceneBBox[1][0]) / 2,
138 | (sceneBBox[0][1] + sceneBBox[1][1]) / 2,
139 | (sceneBBox[0][2] + sceneBBox[1][2]) / 2];
140 | }
141 | var direction = vec3.create();
142 | var eye = vec3.create(this._transform.translation);
143 |
144 | direction[0] = targetPosition[0] - eye[0];
145 | direction[1] = targetPosition[1] - eye[1];
146 | direction[2] = targetPosition[2] - eye[2];
147 |
148 | var axisUpAdjusted = vec3.create(this._axisUp);
149 | var right = vec3.create();
150 | vec3.normalize(direction);
151 | vec3.cross(direction, this._axisUp, right);
152 | vec3.normalize(right);
153 | vec3.cross(direction, right, axisUpAdjusted);
154 | vec3.normalize(axisUpAdjusted);
155 |
156 | var cameraMat = mat4.identity();
157 |
158 | var ratio = 0;
159 | if (Math.abs(yDelta) > Math.abs(xDelta)) {
160 | ratio = Math.abs(yDelta) / Math.abs(xDelta);
161 | } else {
162 | ratio = Math.abs(xDelta) / Math.abs(yDelta);
163 | }
164 |
165 | if (ratio > 0.5) {
166 | mat4.rotate(cameraMat, xDelta, axisUpAdjusted);
167 | mat4.rotate(cameraMat, yDelta, right);
168 | } else
169 | if (Math.abs(yDelta) > Math.abs(xDelta))
170 | mat4.rotate(cameraMat, yDelta, right);
171 | else
172 | mat4.rotate(cameraMat, xDelta, axisUpAdjusted);
173 |
174 | eye[0] -= targetPosition[0];
175 | eye[1] -= targetPosition[1];
176 | eye[2] -= targetPosition[2];
177 |
178 | mat4.rotateVec3(cameraMat, eye);
179 |
180 | eye[0] += targetPosition[0];
181 | eye[1] += targetPosition[1];
182 | eye[2] += targetPosition[2];
183 |
184 | var rotationMatrix = mat4.identity();
185 | mat4.multiply3(cameraMat, this._transform.matrix, rotationMatrix);
186 |
187 | var translationMatrix = mat4.identity();
188 | mat4.translate(translationMatrix, eye);
189 |
190 | var finalMat = mat4.identity();
191 | mat4.multiply(translationMatrix, rotationMatrix, finalMat);
192 | this.viewPoint.glTFElement.transform.matrix = finalMat;
193 | }
194 | },
195 |
196 | beginTranslate: {
197 | value: function(event) {
198 | this.moving = true;
199 | if (this._transform == null) {
200 | this._transform = Object.create(Transform).init();
201 | }
202 | this._transform.matrix = this.viewPoint.glTFElement.worldMatrix;
203 | }
204 | },
205 |
206 | endTranslate: {
207 | value: function(event) {
208 | this.moving = false;
209 |
210 | this._axisUp = null;
211 | }
212 | }
213 |
214 | });
215 |
--------------------------------------------------------------------------------
/runtime/projection.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, Motorola Mobility, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither the name of the Motorola Mobility, Inc. nor the names of its
13 | // contributors may be used to endorse or promote products derived from this
14 | // software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 |
27 | require("runtime/dependencies/gl-matrix");
28 | var Base = require("runtime/base").Base;
29 |
30 | exports.Projection = Object.create(Base, {
31 |
32 | _matrix: { value: null, writable: true },
33 | _type: { value: null, writable: true },
34 | _xfov: { value: 0, writable: true },
35 | _yfov: { value: 0, writable: true },
36 | _xmag: { value: 0, writable: true },
37 | _ymag: { value: 0, writable: true },
38 | _znear: { value: 0, writable: true },
39 | _zfar: { value: 0, writable: true },
40 | _aspectRatio: { value: 0, writable: true },
41 |
42 | _dirtyFlag: { value : false, writable: true},
43 |
44 | projection: {
45 | get: function() {
46 | return this._type;
47 | },
48 | set: function(value) {
49 | if (this._type !== value) {
50 | this._type = value;
51 | this._dirtyFlag = true;
52 | }
53 | }
54 | },
55 |
56 | xfov: {
57 | get: function() {
58 | return this._xfov;
59 | },
60 | set: function(value) {
61 | if (this._xfov !== value) {
62 | this._xfov = value;
63 | this._dirtyFlag = true;
64 | }
65 | }
66 | },
67 |
68 | yfov: {
69 | get: function() {
70 | return this._yfov;
71 | },
72 | set: function(value) {
73 | if (this._yfov !== value) {
74 | this._yfov = value;
75 | this._dirtyFlag = true;
76 | }
77 | }
78 | },
79 |
80 | xmag: {
81 | get: function() {
82 | return this._xmag;
83 | },
84 | set: function(value) {
85 | if (this._xmag !== value) {
86 | this._xmag = value;
87 | this._dirtyFlag = true;
88 | }
89 | }
90 | },
91 |
92 | ymag: {
93 | get: function() {
94 | return this._ymag;
95 | },
96 | set: function(value) {
97 | if (this._ymag !== value) {
98 | this._ymag = value;
99 | this._dirtyFlag = true;
100 | }
101 | }
102 | },
103 |
104 | znear: {
105 | get: function() {
106 | return this._znear;
107 | },
108 | set: function(value) {
109 | if (this._znear !== value) {
110 | this._znear = value;
111 | this._dirtyFlag = true;
112 | }
113 | }
114 | },
115 |
116 | zfar: {
117 | get: function() {
118 | return this._zfar;
119 | },
120 | set: function(value) {
121 | if (this._zfar !== value) {
122 | this._zfar = value;
123 | this._dirtyFlag = true;
124 | }
125 | }
126 | },
127 |
128 | aspectRatio: {
129 | get: function() {
130 | return this._aspectRatio;
131 | },
132 | set: function(value) {
133 | var matrix = this.matrix;
134 | if (matrix) {
135 | if (this.yfov) {
136 | matrix[0] = this._scaleX / value ;
137 | } else if (this.xfov) {
138 | matrix[5] = this._scaleY * value ;
139 |
140 | }
141 | }
142 | this._aspectRatio = value;
143 | }
144 | },
145 |
146 | _scaleX : { value: 0, writable: true },
147 | _scaleY : { value: 0, writable: true },
148 |
149 | matrix: {
150 | get: function() {
151 | if (this._dirtyFlag)
152 | {
153 | if (this.projection === "perspective") {
154 | var degToRadians = 3.14159265359 / 360.0;
155 |
156 | var scaleX = 0;
157 | var scaleY = 0;
158 | if (this.yfov) {
159 | scaleY = 1./Math.tan(this.yfov * degToRadians);
160 | }
161 | if (this.xfov) {
162 | scaleX = 1./Math.tan(this.xfov * degToRadians);
163 | } else {
164 | scaleX = scaleY;
165 | }
166 | if (scaleY == 0) {
167 | scaleY = scaleX;
168 | }
169 | this._scaleX = scaleX;
170 | this._scaleY = scaleY;
171 | this._matrix = mat4.create();
172 |
173 | this._matrix[0] = scaleX;
174 | this._matrix[1] = 0.0;
175 | this._matrix[2] = 0.0;
176 | this._matrix[3] = 0.0;
177 |
178 | this._matrix[4] = 0.0;
179 | this._matrix[5]= scaleY;
180 | this._matrix[6] = 0.0;
181 | this._matrix[7] = 0.0;
182 |
183 | this._matrix[8] = 0.0;
184 | this._matrix[9] = 0.0;
185 | this._matrix[10] = (this.zfar + this.znear) / (this.znear - this.zfar);
186 | this._matrix[11] = -1.0;
187 |
188 | this._matrix[12] = 0.0;
189 | this._matrix[13] = 0.0;
190 | this._matrix[14] = (2.0 * this.zfar * this.znear) / (this.znear - this.zfar);
191 | this._matrix[15] = 0.0;
192 |
193 | } else if (this.projection === "orthographic") {
194 | this._matrix = mat4.ortho(-this.xmag, this.xmag, -this.ymag, this.ymag, this.znear, this.zfar);
195 | } else {
196 | console.log("WARNING: unhandled camera type:"+type)
197 | }
198 |
199 | this._dirtyFlag = false;
200 | }
201 | return this._matrix;
202 | },
203 | set: function(value ) {
204 | this._matrix = value;
205 | }
206 | },
207 |
208 |
209 | initWithDescription: {
210 | value: function(description) {
211 | this.__Base_init();
212 | this.projection = description.type;
213 | description = description[this.projection];
214 | this.xfov = description.xfov ? description.xfov : 0;
215 | this.yfov = description.yfov ? description.yfov : 0;
216 | this.xmag = description.xmag ? description.xmag : 1;
217 | this.ymag = description.ymag ? description.ymag : 1;
218 | this.znear = description.znear != null ? description.znear : 1;
219 | this.zfar = description.zfar != null ? description.zfar : 100;
220 | this.aspectRatio = description.aspect_ratio ? description.aspect_ratio : 0; //deprecate this one
221 | if (!this.aspectRatio)
222 | this.aspectRatio = description.aspectRatio ? description.aspectRatio : 0;
223 | this._dirtyFlag = true;
224 | }
225 | },
226 |
227 | init: {
228 | value: function() {
229 | this.__Base_init();
230 |
231 | this.projection = null;
232 | this.xfov = 0;
233 | this.yfov = 0;
234 | this.xmag = 1;
235 | this.ymag = 1;
236 | this.znear = 1;
237 | this.zfar = 100;
238 | this.aspectRatio = 4./3;
239 | this._dirtyFlag = true;
240 | }
241 | }
242 | });
243 |
244 |
--------------------------------------------------------------------------------
/runtime/animation-manager.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice ROBINET
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | require("runtime/dependencies/gl-matrix");
25 | var Base = require("runtime/base").Base;
26 | var KeyframeAnimation = require("runtime/animation").KeyframeAnimation;
27 | var BasicAnimation = require("runtime/animation").BasicAnimation;
28 | var Animation = require("runtime/animation").Animation;
29 |
30 | exports.AnimationManager = Object.create(Base, {
31 |
32 | startTime: {
33 | get: function() {
34 | if (this.animations) {
35 | if (this.animations.length > 0) {
36 | var startTime = this.animations[0].startTime;
37 | for (var i = 1 ; i < this.animations.length ; i++ ) {
38 | if (this.animations[i].startTime < startTime) {
39 | startTime = this.animations[i].startTime;
40 | }
41 | }
42 | return startTime;
43 | }
44 | return 0;
45 | }
46 | }
47 | },
48 |
49 | endTime: {
50 | get: function() {
51 | if (this.animations) {
52 | if (this.animations.length > 0) {
53 | var endTime = this.animations[0].endTime;
54 | for (var i = 1 ; i < this.animations.length ; i++ ) {
55 | if (this.animations[i].endTime > endTime) {
56 | endTime = this.animations[i].endTime;
57 | }
58 | }
59 | return endTime;
60 | }
61 | return -1;
62 | }
63 | }
64 | },
65 |
66 | _animations: { value: null, writable: true },
67 |
68 | animations: {
69 | get: function() {
70 | return this._animations;
71 | },
72 | set: function(value) {
73 | if (this._animations != value) {
74 | this._animations = value;
75 | }
76 | }
77 | },
78 |
79 | _sceneTime: { value: 0, writable: true },
80 |
81 | sceneTime: {
82 | get: function() {
83 | return this._sceneTime;
84 | },
85 | set: function(value) {
86 | if (this._delegate) {
87 | if (this._delegate.sceneTimeWillChange) {
88 | this._delegate.sceneTimeWillChange(this, value);
89 | }
90 | }
91 | this._sceneTime = value;
92 | if (this._delegate) {
93 | if (this._delegate.sceneTimeDidChange) {
94 | this._delegate.sceneTimeDidChange(this);
95 | }
96 | }
97 | }
98 | },
99 |
100 | _delegate: { value: 0, writable: true },
101 |
102 | delegate: {
103 | get: function() {
104 | return this._delegate;
105 | },
106 | set: function(value) {
107 | this._delegate = value;
108 | }
109 | },
110 |
111 | targets: {
112 | get: function() {
113 | var targets = [];
114 | if (this._animations != null) {
115 | this._animations.forEach(function(animation) {
116 | if (animation.type == Animation.KEYFRAME) {
117 | animation.channels.forEach(function(channel) {
118 | targets.push(channel.target.id);
119 | }, this);
120 | } else {
121 | if (animation.type == Animation.BASIC) {
122 | }
123 | }
124 |
125 | }, this);
126 | }
127 | return targets;
128 | }
129 | },
130 |
131 | hasAnimation: {
132 | value: function(targetUID, targets) {
133 | //it is a forEach, because eventually we will return all the animations for a given target.
134 | var animated = false;
135 | if (this._animations == null)
136 | return false;
137 | if (targets == null)
138 | targets = this.targets;
139 |
140 | return targets.indexOf(targetUID) !== -1;
141 | }
142 | },
143 |
144 | nodeHasAnimatedAncestor: {
145 | value: function(node) {
146 | do {
147 | if (this.hasAnimation(node.id)) {
148 | return true;
149 | }
150 | node = node.parent;
151 | } while (node != null);
152 | return false;
153 | }
154 | },
155 |
156 | //will be deprecated
157 | updateTargetsAtTime: {
158 | value: function(time, resourceManager) {
159 | if (this.animations) {
160 | this.animations.forEach( function(animation) {
161 | //FIXME: unify this - could just use a method called evaluate
162 | if (animation.type == Animation.KEYFRAME) {
163 | animation.updateTargetsAtTime(time, resourceManager);
164 | } else if (animation.type == Animation.BASIC) {
165 | //animation._evaluateAtTime(time);
166 | }
167 | }, this);
168 | }
169 | }
170 | },
171 |
172 | evaluateAtTime: {
173 | value: function(time, resourceManager) {
174 | if (this._activeAnimations) {
175 |
176 | this._activeAnimations.forEach( function(animation) {
177 | //FIXME: unify this - could just use a method called evaluate
178 | if (animation.type == Animation.KEYFRAME) {
179 | //animation.updateTargetsAtTime(time, resourceManager);
180 | } else if (animation.type == Animation.BASIC) {
181 | animation._evaluateAtTime(time);
182 | }
183 | }, this);
184 | }
185 | }
186 | },
187 |
188 | hasActiveAnimations: {
189 | value: function() {
190 | return this._activeAnimations.length > 0;
191 | }
192 | },
193 |
194 | _activeAnimations: { value: 0 , writable: true },
195 |
196 | _removeAnimationAtIndex: {
197 | value: function(index) {
198 | var animation = this._activeAnimations[index];
199 | //animation._evaluateAtTime(Date.now());
200 | if (animation.delegate) {
201 | animation.delegate.animationDidStop(animation);
202 | }
203 | this._activeAnimations.splice(index, 1);
204 | }
205 | },
206 |
207 | playAnimation: {
208 | value: function(animation) {
209 | var self = this;
210 | this._activeAnimations.push(animation);
211 | if (animation.delegate)
212 | animation.delegate.animationDidStart(animation);
213 | setTimeout(function() {
214 | //animation may have been removed
215 | var index = self._activeAnimations.indexOf(animation);
216 | if (index !== -1) {
217 | self._removeAnimationAtIndex(index);
218 | }
219 | }, animation.duration);
220 | }
221 | },
222 |
223 | init: {
224 | value: function() {
225 | this.__Base_init();
226 | this.animations = [];
227 | this._activeAnimations = [];
228 | return this;
229 | }
230 | },
231 |
232 | removeAnimationWithTargetAndPath: {
233 | value: function(target, path) {
234 | if (this._activeAnimations) {
235 | for (var i = 0 ; i < this._activeAnimations.length ; i++) {
236 | var animation = this._activeAnimations[i];
237 | if ((animation.target === target) && (animation.path == path)) {
238 | this._removeAnimationAtIndex(i);
239 | return;
240 | }
241 | }
242 | }
243 | }
244 | }
245 |
246 | });
247 |
--------------------------------------------------------------------------------
/runtime/transform.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) Fabrice ROBINET
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | require("runtime/dependencies/gl-matrix");
25 | var Base = require("runtime/base").Base;
26 | var Utilities = require("runtime/utilities").Utilities;
27 |
28 | //FIXME: add decomposition to be able to add getters in TRS
29 | var Transform = exports.Transform = Object.create(Base, {
30 | _matrix: { value: null, writable: true },
31 |
32 | _dirty: { value: true, writable: true },
33 | _dirtyAffines: { value: true, writable: true },
34 |
35 | _translation: { value: null, writable: true },
36 | _rotation: { value: null, writable: true },
37 | _scale: { value: null, writable: true },
38 |
39 | _id: { value: 0, writable: true },
40 |
41 | _fireTransformDidUpdate: {
42 | value: function(flag) {
43 | if (this._observers) {
44 | for (var i = 0 ; i < this._observers.length ; i++) {
45 | this._observers[i].transformDidUpdate(this);
46 | }
47 | }
48 | }
49 | },
50 |
51 | _updateDirtyFlag: {
52 | value: function(flag) {
53 | this._dirty = flag;
54 | this._fireTransformDidUpdate();
55 | }
56 | },
57 |
58 | interpolateToTransform: {
59 | value: function(to, step, destination) {
60 | step = Utilities.easeOut(step);
61 | this._rebuildAffinesIfNeeded();
62 | to._rebuildAffinesIfNeeded();
63 |
64 | Utilities.interpolateVec(this._translation, to._translation, step, destination._translation);
65 | Utilities.interpolateVec(this._scale, to._scale, step, destination._scale);
66 | Utilities.inverpolateAxisAngle(this._rotation, to._rotation, step, destination._rotation);
67 | //FIXME:breaks encapsulation
68 | destination._updateDirtyFlag(true);
69 | }
70 | },
71 |
72 | matrix: {
73 | get: function() {
74 | if (this._dirty) {
75 | if (this._matrix == null) {
76 | this._matrix = mat4.create();
77 | }
78 |
79 | if (this._intermediateMatrices == null) {
80 | this._intermediateMatrices = [];
81 |
82 | this._intermediateMatrices.push(mat4.identity()); //idx: 0 tmp
83 | this._intermediateMatrices.push(mat4.identity()); //idx: 1 tr
84 | this._intermediateMatrices.push(mat4.identity()); //idx: 2 scale
85 | this._intermediateMatrices.push(mat4.identity()); //idx: 3 rotation
86 | }
87 |
88 | mat4.identity(this._matrix);
89 | mat4.identity(this._intermediateMatrices[0]);
90 |
91 | mat4.set(this._intermediateMatrices[0], this._intermediateMatrices[1]); //tr
92 | mat4.set(this._intermediateMatrices[0], this._intermediateMatrices[2]); //scale
93 | mat4.set(this._intermediateMatrices[0], this._intermediateMatrices[3]); //rotation
94 |
95 | mat4.translate(this._intermediateMatrices[1], this._translation);
96 | mat4.scale(this._intermediateMatrices[2], this._scale);
97 | quat4.toMat4(this._rotation, this._intermediateMatrices[3]);
98 |
99 | mat4.multiply(this._matrix, this._intermediateMatrices[1]);
100 | mat4.multiply(this._matrix, this._intermediateMatrices[2]);
101 | mat4.multiply(this._matrix, this._intermediateMatrices[3]);
102 |
103 | //we can be silent about this one (not use this._updateDirtyFlag(false))
104 | this._dirty = false;
105 | }
106 |
107 | return this._matrix;
108 | },
109 | set: function(value ) {
110 | if (this._matrix == null) {
111 | this._matrix = mat4.create();
112 | }
113 |
114 | mat4.set(value, this._matrix);
115 | this._updateDirtyFlag(false);
116 | this._dirtyAffines = true;
117 | }
118 | },
119 |
120 | _rebuildAffinesIfNeeded: {
121 | value: function() {
122 | if (this._dirtyAffines === true) {
123 | Utilities.decomposeMat4(this.matrix, this._translation, this._rotation, this._scale);
124 | this._dirtyAffines = false;
125 | }
126 | }
127 | },
128 |
129 | translation : {
130 | set: function(value ) {
131 | this._translation = value;
132 | this._updateDirtyFlag(true);
133 | }, get: function(value) {
134 | this._rebuildAffinesIfNeeded();
135 | return this._translation;
136 | }
137 | },
138 |
139 | rotation : {
140 | set: function(value ) {
141 | this._rotation = value;
142 | this._updateDirtyFlag(true);
143 | }, get: function(value) {
144 | this._rebuildAffinesIfNeeded();
145 | return this._rotation;
146 | }
147 | },
148 |
149 | scale : {
150 | set: function(value ) {
151 | this._scale = value;
152 | this._updateDirtyFlag(true);
153 | }, get: function(value) {
154 | this._rebuildAffinesIfNeeded();
155 | return this._scale;
156 | }
157 | },
158 |
159 | _commonInit: {
160 | value: function() {
161 | this.translation = vec3.createFrom(0,0,0);
162 | this.rotation = vec4.createFrom(0,0,0,0);
163 | this.scale = vec3.createFrom(1,1,1);
164 | this.matrix = mat4.identity();
165 | this._id = Transform.bumpId();
166 | }
167 | },
168 |
169 | initWithDescription: {
170 | value: function(description) {
171 | this._commonInit();
172 |
173 | if (description.matrix) {
174 | this.matrix = mat4.create(description.matrix);
175 | } else if (description.translation || description.rotation || description.scale) {
176 | this.translation = description.translation ? vec3.create(description.translation) : vec3.createFrom(0,0,0);
177 | var r = description.rotation;
178 | this.rotation = r ? quat4.fromAngleAxis(r[3], vec3.createFrom(r[0],r[1],r[2])) : vec4.createFrom(0,0,0,0);
179 | this.scale = description.scale ? vec3.create(description.scale) : vec3.createFrom(1,1,1);
180 | } else {
181 | this.matrix = mat4.identity();
182 | }
183 | return this;
184 | }
185 | },
186 |
187 | init: {
188 | value: function() {
189 | this._commonInit();
190 | return this;
191 | }
192 | },
193 |
194 | bumpId: {
195 | value: function() {
196 | Transform._id++;
197 | return Transform._id;
198 | }
199 | },
200 |
201 | copy: {
202 | value: function() {
203 | var transform = Object.create(Transform).init();
204 |
205 | if (this._translation) {
206 | transform.translation = vec3.createFrom(this._translation[0], this._translation[1], this._translation[2]);
207 | }
208 |
209 | if (this._scale) {
210 | transform.scale = vec3.createFrom(this._scale[0], this._scale[1], this._scale[2]);
211 | }
212 |
213 | if (this._rotation) {
214 | transform.rotation = quat4.create(this._rotation);
215 | }
216 |
217 | transform.matrix = mat4.create(this.matrix);
218 | return transform;
219 | }
220 | },
221 |
222 | _observers: { value: null, writable: true},
223 |
224 | addObserver: {
225 | value: function(observer) {
226 | if (this._observers == null) {
227 | this._observers = [];
228 | }
229 |
230 | if (this._observers.indexOf(observer) === -1) {
231 | this._observers.push(observer);
232 | } else {
233 | console.log("WARNING attempt to add 2 times the same observer in transform")
234 | }
235 | }
236 | },
237 |
238 | removeObserver: {
239 | value: function(observer) {
240 | if (this._observers) {
241 | var index = this._observers.indexOf(observer);
242 | if (index !== -1) {
243 | this._observers.splice(index, 1);
244 | }
245 | }
246 | }
247 | }
248 |
249 | });
250 |
--------------------------------------------------------------------------------
/runtime/material.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | var Montage = require("montage").Montage;
25 | var Component3D = require("runtime/component-3d").Component3D;
26 | var BasicAnimation = require("runtime/animation").BasicAnimation;
27 |
28 | exports.Material = Component3D.specialize( {
29 |
30 | constructor: {
31 | value: function Material() {
32 | this.super();
33 |
34 | this.addRangeAtPathChangeListener("filterColor", this, "handleFilterColorChange");
35 | this.addOwnPropertyChangeListener("glTFElement", this);
36 | this.addOwnPropertyChangeListener("image", this);
37 | this.addOwnPropertyChangeListener("opacity", this);
38 | }
39 | },
40 |
41 | filterColor: { value: [1,1,1,1]},
42 |
43 | _originalOpacity: { value: 1, writable: true },
44 |
45 | handleGlTFElementChange: {
46 | value: function() {
47 | this.handleFilterColorChange();
48 | this.handleImageChange();
49 |
50 | this._originalOpacity = this._opacity;
51 | if (this._opacity == null) {
52 | if (this.glTFElement.parameters["transparency"] != null) {
53 | this._originalOpacity = this._opacity = this.glTFElement.parameters["transparency"].value;
54 | }
55 | } else {
56 | this.handleOpacityChange();
57 | }
58 | }
59 | },
60 |
61 | initialValueForStyleableProperty: {
62 | value: function(property) {
63 | if (property == "opacity") {
64 | return this._originalOpacity;
65 | }
66 | }
67 | },
68 |
69 | handleFilterColorChange: {
70 | value: function(plus, minus, index) {
71 | if (this.glTFElement != null) {
72 | if (this.glTFElement.parameters["filterColor"]) {
73 | this.glTFElement.parameters["filterColor"].value = this.filterColor;
74 | if (this.scene) {
75 | this.scene.dispatchEventNamed("materialUpdate", true, false, this);
76 | }
77 | }
78 | }
79 | }
80 | },
81 |
82 | handleOpacityChange: {
83 | value: function() {
84 | if (this.glTFElement != null) {
85 | if (this.glTFElement.parameters["transparency"]) {
86 | this.glTFElement.parameters["transparency"].value = this._opacity;
87 | if (this.scene) {
88 | this.scene.dispatchEventNamed("materialUpdate", true, false, this);
89 | }
90 | }
91 | }
92 | }
93 | },
94 |
95 | handleImageChange: {
96 | value: function() {
97 | if (this.glTFElement != null) {
98 | if (this.glTFElement.parameters["diffuse"]) {
99 | if (this._image) {
100 | var imagePath = this.resolvePathIfNeeded(this._image);
101 | var parameterValue = this.parameterForImagePath(imagePath);
102 | this.glTFElement.parameters["diffuse"] = parameterValue;
103 | if (this.scene) {
104 | this.scene.dispatchEventNamed("textureUpdate", true, false, parameterValue);
105 | }
106 | }
107 | }
108 | }
109 | }
110 | },
111 |
112 | parameterForImagePath: {
113 | value: function(imagePath) {
114 |
115 | var sampler = {
116 | "magFilter": WebGLRenderingContext.LINEAR,
117 | "minFilter": WebGLRenderingContext.LINEAR,
118 | "type": "sampler",
119 | "wrapS" : WebGLRenderingContext.REPEAT,
120 | "wrapT" : WebGLRenderingContext.REPEAT
121 | };
122 |
123 | var source = {
124 | "id" : "source-"+ imagePath,
125 | "type" : "image",
126 | "baseId" : "source-"+ imagePath,
127 | "description" : {
128 | "path" : imagePath
129 | }
130 | };
131 |
132 | var parameterValue = {
133 | "baseId": "texture-" + imagePath,
134 | "id": "texture-" + imagePath,
135 | "format": WebGLRenderingContext.RGBA,
136 | "internalFormat" : WebGLRenderingContext.RGBA,
137 | "sampler" : sampler,
138 | "source" : source,
139 | "type" : "texture",
140 | "target" : WebGLRenderingContext.TEXTURE_2D
141 | };
142 |
143 | var parameter = {
144 | "parameter": "diffuse",
145 | "value" : parameterValue
146 | };
147 |
148 | return parameter;
149 | }
150 | },
151 |
152 | _image: { value: null , writable:true },
153 |
154 | image: {
155 | set: function(value) {
156 | if (value) {
157 | //FIXME: remove this when we initialized property image with the path in place when the glTFElement comes up
158 | if (value.length == 0) {
159 | return;
160 | }
161 | } else {
162 | return;
163 | }
164 |
165 | var lowerCaseImage = value.toLowerCase();
166 | if ((lowerCaseImage.indexOf(".jpg") != -1) || (lowerCaseImage.indexOf(".jpeg") != -1) || (lowerCaseImage.indexOf(".png") != -1)) {
167 | if (this._image != value) {
168 | this._image = value;
169 | }
170 | }
171 | },
172 | get: function() {
173 | return this._image;
174 | }
175 | },
176 |
177 | _opacity: { value: null, writable:true },
178 |
179 | animationDidStart: {
180 | value: function(animation) {
181 | }
182 | },
183 |
184 | animationDidStop: {
185 | value: function(animation) {
186 | }
187 | },
188 |
189 | animationDidUpdate: {
190 | value: function(animation) {
191 | }
192 | },
193 |
194 | opacity_animationSetter: {
195 | set: function(value) {
196 | if (this._opacity != value) {
197 | this._opacity = value;
198 | this.handleOpacityChange();
199 | }
200 | }
201 | },
202 |
203 | opacity: {
204 | set: function(value) {
205 | if (this._opacity != value) {
206 | //remove animation if any
207 | if (this.glTFElement) {
208 | var animationManager = this.scene.glTFElement.animationManager;
209 | animationManager.removeAnimationWithTargetAndPath(this, "opacity_animationSetter");
210 | if (this._style) {
211 | if (this._style.transitions) {
212 | var transition = this._style.transitions["opacity"];
213 | if (transition != null) {
214 | if (transition.duration > 0) {
215 | var opacityAnimation = Object.create(BasicAnimation).init();
216 | opacityAnimation.path = "opacity_animationSetter";
217 | opacityAnimation.target = this;
218 | opacityAnimation.delegate = this;
219 | opacityAnimation.from = Number(this._opacity);
220 | opacityAnimation.to = Number(value);
221 | opacityAnimation.duration = transition.duration * 1000;
222 | animationManager.playAnimation(opacityAnimation);
223 | opacityAnimation.animationWasAddedToTarget();
224 | animationManager.evaluateAtTime(Date.now());
225 | return;
226 | }
227 | }
228 | }
229 | }
230 | }
231 |
232 | this._opacity = value;
233 | }
234 | },
235 | get: function() {
236 | return this._opacity;
237 | }
238 | },
239 |
240 | _stylableProperties: { value: ["opacity"]},
241 |
242 | styleableProperties: {
243 | get: function() {
244 | return this._stylableProperties;
245 | }
246 | }
247 |
248 | });
249 |
--------------------------------------------------------------------------------
/runtime/node.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | var Montage = require("montage").Montage;
25 | var Component3D = require("runtime/component-3d").Component3D;
26 | var Transform = require("runtime/transform").Transform;
27 | var BasicAnimation = require("runtime/animation").BasicAnimation;
28 | require("runtime/dependencies/gl-matrix");
29 |
30 | exports.Node = Component3D.specialize( {
31 |
32 | constructor: {
33 | value: function Node() {
34 | this.super();
35 | //FIXME: these guys are not removed
36 | this._hidden = false;
37 | this._visibility = "visible";
38 | this._offsetMatrix = mat4.identity();
39 |
40 | this.addOwnPropertyChangeListener("hidden", this);
41 | this.addOwnPropertyChangeListener("visibility", this);
42 | this.addOwnPropertyChangeListener("offsetMatrix", this);
43 | this.addOwnPropertyChangeListener("originVector", this);
44 | this.addOwnPropertyChangeListener("glTFElement", this);
45 | }
46 | },
47 |
48 | animationDidStart: {
49 | value: function(animation) {
50 | }
51 | },
52 |
53 | animationDidStop: {
54 | value: function(animation) {
55 | }
56 | },
57 |
58 | animationDidUpdate: {
59 | value: function(animation) {
60 | }
61 | },
62 |
63 | handleGlTFElementChange: {
64 | value: function() {
65 | this.handleHiddenChange();
66 | this.handleVisibilityChange();
67 | this.handleOffsetMatrixChange();
68 | this.handleOriginVectorChange();
69 |
70 | this._applyCSSPropertyWithValueForState(this.__STYLE_DEFAULT__, "offsetMatrix", this._offsetMatrix);
71 |
72 | }
73 | },
74 |
75 | handleHiddenChange: {
76 | value: function() {
77 | if (this.glTFElement != null) {
78 | this.glTFElement.hidden = this._hidden;
79 | //FIXME: user a more appropriate name for this, it will just trigger a redraw
80 | this.scene.dispatchEventNamed("materialUpdate", true, false, this);
81 | }
82 | }
83 | },
84 |
85 | handleVisibilityChange: {
86 | value: function() {
87 | if (this.glTFElement != null) {
88 | this.glTFElement.hidden = this.visibility ? this.visibility === "hidden" : false;
89 | //FIXME: user a more appropriate name for this, it will just trigger a redraw
90 | this.scene.dispatchEventNamed("materialUpdate", true, false, this);
91 | }
92 | }
93 | },
94 |
95 | offsetMatrix_animationSetter: {
96 | set: function(value) {
97 | this._offsetMatrix = value.matrix;
98 | this.handleOffsetMatrixChange();
99 | }
100 | },
101 |
102 | handleOffsetMatrixChange: {
103 | value: function() {
104 | if (this.glTFElement != null) {
105 | //access a private property. not sure yet which name would be the most appropriate yet
106 | this.glTFElement._offsetMatrix = this._offsetMatrix;
107 | //FIXME: user a more appropriate name for this, it will just trigger a redraw
108 | this.scene.dispatchEventNamed("materialUpdate", true, false, this);
109 | }
110 | }
111 | },
112 |
113 | handleOriginVectorChange: {
114 | value: function() {
115 | if (this.glTFElement != null) {
116 | this.glTFElement._originVector = this._originVector;
117 | //FIXME: user a more appropriate name for this, it will just trigger a redraw
118 | this.scene.dispatchEventNamed("materialUpdate", true, false, this);
119 | }
120 | }
121 | },
122 |
123 | _hidden: { value: false, writable:true },
124 |
125 | //deprecated - just kept for the den-demo
126 | hidden: {
127 | set: function(value) {
128 | if (this._hidden != value) {
129 | this._hidden = value;
130 | }
131 | },
132 | get: function() {
133 | return this._hidden;
134 | }
135 | },
136 |
137 | _visibility: { value: false, writable:true },
138 |
139 | visibility: {
140 | set: function(value) {
141 | this._visibility = value;
142 | },
143 | get: function() {
144 | return this._visibility;
145 | }
146 | },
147 |
148 | _transform: { value: null, writable:true },
149 |
150 | transform: {
151 | set: function(value) {
152 | this._transform = value;
153 | },
154 | get: function() {
155 | return this._transform;
156 | }
157 | },
158 |
159 | _offsetMatrix: { value: null, writable:true },
160 |
161 | offsetMatrix: {
162 | set: function(value) {
163 | if (this.glTFElement) {
164 | var animationManager = this.scene.glTFElement.animationManager;
165 | animationManager.removeAnimationWithTargetAndPath(this, "offsetMatrix_animationSetter");
166 | if (this._style) {
167 | if (this._style.transitions) {
168 | var transition = this._style.transitions["offsetMatrix"];
169 | if (transition != null) {
170 | if (transition.duration > 0) {
171 | var fromTr = Object.create(Transform).init();
172 | var toTr = Object.create(Transform).init();
173 | fromTr.matrix = this._offsetMatrix;
174 | toTr.matrix = value;
175 | var transformAnimation = Object.create(BasicAnimation).init();
176 | transformAnimation.path = "offsetMatrix_animationSetter";
177 | transformAnimation.target = this;
178 | transformAnimation.delegate = this;
179 | transformAnimation.from = fromTr;
180 | transformAnimation.to = toTr;
181 | transformAnimation.duration = transition.duration * 1000;
182 | animationManager.playAnimation(transformAnimation);
183 | transformAnimation.animationWasAddedToTarget();
184 | animationManager.evaluateAtTime(Date.now());
185 | return;
186 | }
187 | }
188 | }
189 | }
190 | }
191 |
192 | this._offsetMatrix = value;
193 | },
194 | get: function() {
195 | return this._offsetMatrix;
196 | }
197 | },
198 |
199 | _originVector: { value: null, writable:true },
200 |
201 | originVector: {
202 | set: function(value) {
203 | this._originVector = value;
204 | },
205 | get: function() {
206 | return this._originVector;
207 | }
208 | },
209 |
210 | _observers: { value: null, writable: true},
211 |
212 | addObserver: {
213 | value: function(observer) {
214 | if (this._observers == null) {
215 | this._observers = [];
216 | }
217 |
218 | if (this._observers.indexOf(observer) === -1) {
219 | this._observers.push(observer);
220 | } else {
221 | console.log("WARNING attempt to add 2 times the same observer in glTFNode")
222 | }
223 | }
224 | },
225 |
226 | removeObserver: {
227 | value: function(observer) {
228 | if (this._observers) {
229 | var index = this._observers.indexOf(observer);
230 | if (index !== -1) {
231 | this._observers.splice(index, 1);
232 | }
233 | }
234 | }
235 | },
236 |
237 | _stylableProperties: { value: ["visibility", "offsetMatrix", "originVector"]},
238 |
239 | styleableProperties: {
240 | get: function() {
241 | return this._stylableProperties;
242 | }
243 | },
244 |
245 | initialValueForStyleableProperty: {
246 | value: function(property) {
247 | if (property === "visibility") {
248 | return "visible";
249 | } else if (property === "offsetMatrix") {
250 | return mat4.identity();
251 | } else if (property === "originVector") {
252 | return vec3.createFrom(50, 50, 50);
253 | }
254 | }
255 | }
256 |
257 | });
258 |
--------------------------------------------------------------------------------
/runtime/glTF-parser.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013 Fabrice Robinet
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | /*
25 | The Abstract Loader has two modes:
26 | #1: [static] load all the JSON at once [as of now]
27 | #2: [stream] stream and parse JSON progressively [not yet supported]
28 |
29 | Whatever is the mechanism used to parse the JSON (#1 or #2),
30 | The loader starts by resolving the paths to binaries and referenced json files (by replace the value of the path property with an absolute path if it was relative).
31 |
32 | In case #1: it is guaranteed to call the concrete loader implementation methods in a order that solves the dependencies between the entries.
33 | only the nodes requires an extra pass to set up the hirerarchy.
34 | In case #2: the concrete implementation will have to solve the dependencies. no order is guaranteed.
35 |
36 | When case #1 is used the followed dependency order is:
37 |
38 | scenes -> nodes -> meshes -> materials -> techniques -> shaders
39 | -> buffers
40 | -> cameras
41 | -> lights
42 |
43 | The readers starts with the leafs, i.e:
44 | shaders, techniques, materials, meshes, buffers, cameras, lights, nodes, scenes
45 |
46 | For each called handle method called the client should return true if the next handle can be call right after returning,
47 | or false if a callback on client side will notify the loader that the next handle method can be called.
48 |
49 | */
50 | var global = window;
51 | (function (root, factory) {
52 | if (typeof exports === 'object') {
53 | // Node. Does not work with strict CommonJS, but
54 | // only CommonJS-like enviroments that support module.exports,
55 | // like Node.
56 | factory(module.exports);
57 | } else if (typeof define === 'function' && define.amd) {
58 | // AMD. Register as an anonymous module.
59 | define([], function () {
60 | return factory(root);
61 | });
62 | } else {
63 | // Browser globals
64 | factory(root);
65 | }
66 | }(this, function (root) {
67 | "use strict";
68 |
69 | var categoriesDepsOrder = ["buffers", "bufferViews", "images", "videos", "samplers", "textures", "shaders", "programs", "techniques", "materials", "accessors", "meshes", "cameras", "lights", "skins", "nodes", "scenes", "animations"];
70 |
71 | var glTFParser = Object.create(Object.prototype, {
72 |
73 | _rootDescription: { value: null, writable: true },
74 |
75 | rootDescription: {
76 | set: function(value) {
77 | this._rootDescription = value;
78 | },
79 | get: function() {
80 | return this._rootDescription;
81 | }
82 | },
83 |
84 | baseURL: { value: null, writable: true },
85 |
86 | //detect absolute path following the same protocol than window.location
87 | _isAbsolutePath: {
88 | value: function(path) {
89 | var isAbsolutePathRegExp = new RegExp("^"+window.location.protocol, "i");
90 |
91 | return path.match(isAbsolutePathRegExp) ? true : false;
92 | }
93 | },
94 |
95 | resolvePathIfNeeded: {
96 | value: function(path) {
97 | if (this._isAbsolutePath(path)) {
98 | return path;
99 | }
100 |
101 | return this.baseURL + path;
102 | }
103 | },
104 |
105 | _resolvePathsForCategories: {
106 | value: function(categories) {
107 | categories.forEach( function(category) {
108 | var descriptions = this.json[category];
109 | if (descriptions) {
110 | var descriptionKeys = Object.keys(descriptions);
111 | descriptionKeys.forEach( function(descriptionKey) {
112 | var description = descriptions[descriptionKey];
113 | description.path = this.resolvePathIfNeeded(description.path);
114 | }, this);
115 | }
116 | }, this);
117 | }
118 | },
119 |
120 | _json: {
121 | value: null,
122 | writable: true
123 | },
124 |
125 | json: {
126 | enumerable: true,
127 | get: function() {
128 | return this._json;
129 | },
130 | set: function(value) {
131 | if (this._json !== value) {
132 | this._json = value;
133 | this._resolvePathsForCategories(["buffers", "shaders", "images", "videos"]);
134 | }
135 | }
136 | },
137 |
138 | _path: {
139 | value: null,
140 | writable: true
141 | },
142 |
143 | getEntryDescription: {
144 | value: function (entryID, entryType) {
145 | var entries = null;
146 |
147 | var category = entryType;
148 | entries = this.rootDescription[category];
149 | if (!entries) {
150 | console.log("ERROR:CANNOT find expected category named:"+category);
151 | return null;
152 | }
153 |
154 | return entries ? entries[entryID] : null;
155 | }
156 | },
157 |
158 | _stepToNextCategory: {
159 | value: function() {
160 | this._state.categoryIndex = this.getNextCategoryIndex(this._state.categoryIndex + 1);
161 | if (this._state.categoryIndex !== -1) {
162 | this._state.categoryState.index = 0;
163 | return true;
164 | }
165 |
166 | return false;
167 | }
168 | },
169 |
170 | _stepToNextDescription: {
171 | enumerable: false,
172 | value: function() {
173 | var categoryState = this._state.categoryState;
174 | var keys = categoryState.keys;
175 | if (!keys) {
176 | console.log("INCONSISTENCY ERROR");
177 | return false;
178 | }
179 |
180 | categoryState.index++;
181 | categoryState.keys = null;
182 | if (categoryState.index >= keys.length) {
183 | return this._stepToNextCategory();
184 | }
185 | return false;
186 | }
187 | },
188 |
189 | hasCategory: {
190 | value: function(category) {
191 | return this.rootDescription[category] ? true : false;
192 | }
193 | },
194 |
195 | _handleState: {
196 | value: function() {
197 |
198 | var methodForType = {
199 | "buffers" : this.handleBuffer,
200 | "bufferViews" : this.handleBufferView,
201 | "shaders" : this.handleShader,
202 | "programs" : this.handleProgram,
203 | "techniques" : this.handleTechnique,
204 | "materials" : this.handleMaterial,
205 | "meshes" : this.handleMesh,
206 | "cameras" : this.handleCamera,
207 | "lights" : this.handleLight,
208 | "nodes" : this.handleNode,
209 | "scenes" : this.handleScene,
210 | "images" : this.handleImage,
211 | "animations" : this.handleAnimation,
212 | "accessors" : this.handleAccessor,
213 | "skins" : this.handleSkin,
214 | "samplers" : this.handleSampler,
215 | "textures" : this.handleTexture,
216 | "videos" : this.handleVideo
217 |
218 | };
219 |
220 | var success = true;
221 | while (this._state.categoryIndex !== -1) {
222 | var category = categoriesDepsOrder[this._state.categoryIndex];
223 | var categoryState = this._state.categoryState;
224 | var keys = categoryState.keys;
225 | if (!keys) {
226 | categoryState.keys = keys = Object.keys(this.rootDescription[category]);
227 | if (keys) {
228 | if (keys.length == 0) {
229 | this._stepToNextDescription();
230 | continue;
231 | }
232 | }
233 | }
234 |
235 | var type = category;
236 | var entryID = keys[categoryState.index];
237 | var description = this.getEntryDescription(entryID, type);
238 | if (!description) {
239 | if (this.handleError) {
240 | this.handleError("INCONSISTENCY ERROR: no description found for entry "+entryID);
241 | success = false;
242 | break;
243 | }
244 | } else {
245 |
246 | if (methodForType[type]) {
247 | if (methodForType[type].call(this, entryID, description, this._state.userInfo) === false) {
248 | success = false;
249 | break;
250 | }
251 | }
252 |
253 | this._stepToNextDescription();
254 | }
255 | }
256 |
257 | if (this.handleLoadCompleted) {
258 | this.handleLoadCompleted(success);
259 | }
260 |
261 | }
262 | },
263 |
264 | _loadJSONIfNeeded: {
265 | enumerable: true,
266 | value: function(callback) {
267 | var self = this;
268 | //FIXME: handle error
269 | if (!this._json) {
270 | var jsonPath = this._path;
271 | var i = jsonPath.lastIndexOf("/");
272 | this.baseURL = (i !== 0) ? jsonPath.substring(0, i + 1) : '';
273 | var jsonfile = new XMLHttpRequest();
274 | jsonfile.open("GET", jsonPath, true);
275 | jsonfile.onreadystatechange = function() {
276 | if (jsonfile.readyState == 4) {
277 | if (jsonfile.status == 200) {
278 | self.json = JSON.parse(jsonfile.responseText);
279 | if (callback) {
280 | callback(self.json);
281 | }
282 | }
283 | }
284 | };
285 | jsonfile.send(null);
286 | } else {
287 | if (callback) {
288 | callback(this.json);
289 | }
290 | }
291 | }
292 | },
293 |
294 | /* load JSON and assign it as description to the reader */
295 | _buildLoader: {
296 | value: function(callback) {
297 | var self = this;
298 | function JSONReady(json) {
299 | self.rootDescription = json;
300 | if (callback)
301 | callback(this);
302 | }
303 |
304 | this._loadJSONIfNeeded(JSONReady);
305 | }
306 | },
307 |
308 | _state: { value: null, writable: true },
309 |
310 | _getEntryType: {
311 | value: function(entryID) {
312 | var rootKeys = categoriesDepsOrder;
313 | for (var i = 0 ; i < rootKeys.length ; i++) {
314 | var rootValues = this.rootDescription[rootKeys[i]];
315 | if (rootValues) {
316 | return rootKeys[i];
317 | }
318 | }
319 | return null;
320 | }
321 | },
322 |
323 | getNextCategoryIndex: {
324 | value: function(currentIndex) {
325 | for (var i = currentIndex ; i < categoriesDepsOrder.length ; i++) {
326 | if (this.hasCategory(categoriesDepsOrder[i])) {
327 | return i;
328 | }
329 | }
330 |
331 | return -1;
332 | }
333 | },
334 |
335 | load: {
336 | enumerable: true,
337 | value: function(userInfo, options) {
338 | var self = this;
339 | this._buildLoader(function loaderReady(reader) {
340 | var startCategory = self.getNextCategoryIndex.call(self,0);
341 | if (startCategory !== -1) {
342 | self._state = { "userInfo" : userInfo,
343 | "options" : options,
344 | "categoryIndex" : startCategory,
345 | "categoryState" : { "index" : "0" } };
346 | self._handleState();
347 | }
348 | });
349 | }
350 | },
351 |
352 | initWithPath: {
353 | value: function(path) {
354 | this._path = path;
355 | this._json = null;
356 | return this;
357 | }
358 | },
359 |
360 | //this is meant to be global and common for all instances
361 | _knownURLs: { writable: true, value: {} },
362 |
363 | //to be invoked by subclass, so that ids can be ensured to not overlap
364 | loaderContext: {
365 | value: function() {
366 | if (typeof this._knownURLs[this._path] === "undefined") {
367 | this._knownURLs[this._path] = Object.keys(this._knownURLs).length;
368 | }
369 | return "__" + this._knownURLs[this._path];
370 | }
371 | },
372 |
373 | initWithJSON: {
374 | value: function(json, baseURL) {
375 | this.json = json;
376 | this.baseURL = baseURL;
377 | if (!baseURL) {
378 | console.log("WARNING: no base URL passed to Reader:initWithJSON");
379 | }
380 | return this;
381 | }
382 | }
383 |
384 | });
385 |
386 | if(root) {
387 | root.glTFParser = glTFParser;
388 | }
389 |
390 | return glTFParser;
391 |
392 | }));
393 |
--------------------------------------------------------------------------------
/runtime/scene-renderer.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2012, Motorola Mobility, Inc.
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | // * Neither the name of the Motorola Mobility, Inc. nor the names of its
13 | // contributors may be used to endorse or promote products derived from this
14 | // software without specific prior written permission.
15 | //
16 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
20 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 | require("runtime/dependencies/gl-matrix");
27 | var Technique = require("runtime/technique").Technique;
28 | var ScenePass = require("runtime/pass").ScenePass;
29 | var BuiltInAssets = require("runtime/builtin-assets").BuiltInAssets;
30 | var o3dgc = require("runtime/dependencies/o3dgc");
31 | exports.SceneRenderer = Object.create(Object.prototype, {
32 |
33 | loadPickingTechnique: {
34 | value: function() {
35 | var self = this;
36 | var techniquePromise = BuiltInAssets.assetWithName( "pickingTechnique");
37 |
38 | techniquePromise.then(function (asset) {
39 | self.technique.rootPass.scenePassRenderer.pickingTechnique = asset;
40 | }, function (error) {
41 | }, function (progress) {
42 | });
43 | }
44 | },
45 |
46 | createTechniqueIfNeeded: {
47 | value: function() {
48 | if (!this._technique) {
49 | this._technique = Object.create(Technique).init();
50 | var pass = Object.create(ScenePass).init();
51 | //there is just one pass, so passName will be automatically set to "defaultPass"
52 | this._technique.passes = { "defaultPass": pass };
53 | }
54 | }
55 | },
56 |
57 | _webGLRenderer: { value: null, writable: true },
58 |
59 | _technique: { value: null, writable: true },
60 |
61 | technique: {
62 | get: function() {
63 | return this._technique;
64 | },
65 | set: function(value) {
66 | this._technique = value;
67 | }
68 | },
69 |
70 |
71 | compressedMeshDelegate: {
72 | value: {
73 | str2ab: function(str) {
74 | var buf = new ArrayBuffer(str.length);
75 | var bufView = new Uint8Array(buf);
76 | for (var i=0, strLen=str.length; i 0) {
107 | ifs.SetCoordIndex(new Uint16Array(bufferIndices, 0, 3 * ifs.GetNCoordIndex()));
108 | }
109 | if (ifs.GetNCoord() > 0) {
110 | ifs.SetCoord(new Float32Array(buffer, shift, 3 * ifs.GetNCoord()));
111 | shift += 12 * ifs.GetNCoord();
112 | }
113 | if (ifs.GetNNormal() > 0) {
114 | ifs.SetNormal(new Float32Array(buffer, shift, 3 * ifs.GetNNormal()));
115 | shift += 12 * ifs.GetNNormal();
116 | }
117 |
118 | var numNumFloatAttributes = ifs.GetNumFloatAttributes();
119 | for (var a = 0; a < numNumFloatAttributes; ++a){
120 | if (ifs.GetNFloatAttribute(a) > 0) {
121 | ifs.SetFloatAttribute(a, new Float32Array(ifs.GetFloatAttributeDim(a) * ifs.GetNFloatAttribute(a)));
122 | }
123 | }
124 | /*
125 | console.log("Mesh info ");
126 | console.log("\t# coords " + ifs.GetNCoord());
127 | console.log("\t# normals " + ifs.GetNNormal());
128 | console.log("\t# texcoords " + ifs.GetNTexCoord());
129 | console.log("\t# triangles " + ifs.GetNCoordIndex());
130 | */
131 | // decode mesh
132 | timer.Tic();
133 | decoder.DecodePlayload(ifs, bstream);
134 | timer.Toc();
135 | /*
136 | var size = arrayBuffer.byteLength;
137 | console.log("DecodePlayload time " + timer.GetElapsedTime() + " ms, " + size + " bytes (" + (8.0 * size / ifs.GetNCoord()) + " bpv)");
138 | console.log("Details");
139 | var stats = decoder.GetStats();
140 | console.log("\t CoordIndex " + stats.m_timeCoordIndex + " ms, " + stats.m_streamSizeCoordIndex + " bytes (" + (8.0 * stats.m_streamSizeCoordIndex / ifs.GetNCoord()) + " bpv)");
141 | console.log("\t Coord " + stats.m_timeCoord + " ms, " + stats.m_streamSizeCoord + " bytes (" + (8.0 * stats.m_streamSizeCoord / ifs.GetNCoord()) + " bpv)");
142 | console.log("\t Normal " + stats.m_timeNormal + " ms, " + stats.m_streamSizeNormal + " bytes (" + (8.0 * stats.m_streamSizeNormal / ifs.GetNCoord()) + " bpv)");
143 | console.log("\t TexCoord " + stats.m_timeTexCoord + " ms, " + stats.m_streamSizeTexCoord + " bytes (" + (8.0 * stats.m_streamSizeTexCoord / ifs.GetNCoord()) + " bpv)");
144 | console.log("\t Color " + stats.m_timeColor + " ms, " + stats.m_streamSizeColor + " bytes (" + (8.0 * stats.m_streamSizeColor / ifs.GetNCoord()) + " bpv)");
145 | console.log("\t Float Attributes " + stats.m_timeFloatAttribute + " ms, " + stats.m_streamSizeFloatAttribute + " bytes (" + (8.0 * stats.m_streamSizeFloatAttribute / ifs.GetNCoord()) + " bpv)");
146 | console.log("\t Integer Attributes " + stats.m_timeFloatAttribute + " ms, " + stats.m_streamSizeFloatAttribute + " bytes (" + (8.0 * stats.m_streamSizeFloatAttribute / ifs.GetNCoord()) + " bpv)");
147 | console.log("\t Reorder " + stats.m_timeReorder + " ms, " + 0 + " bytes (" + 0.0 + " bpv)");
148 | //SaveOBJ(ifs, fileName);
149 | */
150 | return ifs;
151 | }
152 | },
153 |
154 |
155 | handleError: function(errorCode, info) {
156 | console.log("ERROR:vertexAttributeBufferDelegate:"+errorCode+" :"+info);
157 | },
158 |
159 | decompressAttribsInner_: function(str, inputStart, inputEnd,
160 | output, outputStart, stride,
161 | decodeOffset, decodeScale) {
162 | var prev = 0;
163 | for (var j = inputStart; j < inputEnd; j++) {
164 | var code = str.charCodeAt(j);
165 | prev += (code >> 1) ^ (-(code & 1));
166 | output[outputStart] = decodeScale * (prev + decodeOffset);
167 | outputStart += stride;
168 | }
169 | },
170 |
171 | decompressIndices_: function(str, inputStart, numIndices,
172 | output, outputStart) {
173 | var highest = 0;
174 | for (var i = 0; i < numIndices; i++) {
175 | var code = str.charCodeAt(inputStart++);
176 | output[outputStart++] = highest - code;
177 | if (code == 0) {
178 | highest++;
179 | }
180 | }
181 | },
182 |
183 | decompressMesh: function(str, meshParams, decodeParams, callback) {
184 | // Extract conversion parameters from attribArrays.
185 | var stride = decodeParams.decodeScales.length;
186 | var decodeOffsets = decodeParams.decodeOffsets;
187 | var decodeScales = decodeParams.decodeScales;
188 | var attribStart = meshParams.attribRange[0];
189 | var numVerts = meshParams.attribRange[1];
190 |
191 | // Decode attributes.
192 | var inputOffset = attribStart;
193 | var attribsOut = new Float32Array(stride * numVerts);
194 | for (var j = 0; j < stride; j++) {
195 | var end = inputOffset + numVerts;
196 | var decodeScale = decodeScales[j];
197 | if (decodeScale) {
198 | // Assume if decodeScale is never set, simply ignore the
199 | // attribute.
200 | this.decompressAttribsInner_(str, inputOffset, end,
201 | attribsOut, j, stride,
202 | decodeOffsets[j], decodeScale);
203 | }
204 | inputOffset = end;
205 | }
206 |
207 | var indexStart = meshParams.indexRange[0];
208 | var numIndices = 3*meshParams.indexRange[1];
209 | var indicesOut = new Uint16Array(numIndices);
210 | this.decompressIndices_(str, inputOffset, numIndices, indicesOut, 0);
211 |
212 | // Decode bboxen.
213 | /*
214 | var bboxen = undefined;
215 | var bboxOffset = meshParams.bboxes;
216 | if (bboxOffset) {
217 | bboxen = decompressAABBs_(str, bboxOffset, meshParams.names.length,
218 | decodeOffsets, decodeScales);
219 | }
220 | */
221 | callback(attribsOut, indicesOut, null, meshParams);
222 | },
223 |
224 |
225 | convert: function (source, resource, ctx) {
226 | var compression = ctx.mesh.compression;
227 | if (compression.type == "won-compression") {
228 | var indexRange = compression.indexRange;
229 | if (indexRange) {
230 | var meshEnd = indexRange[0] + 3 * indexRange[1];
231 | var callback = null;
232 | this.decompressMesh(resource, compression, compression,
233 | function(attribsOut, indicesOut, bboxen, meshParams) {
234 | ctx.renderer.setupCompressedMesh(ctx.mesh, attribsOut, indicesOut);
235 | });
236 | }
237 | } else {
238 | var vertexCount = 0;
239 | var mesh = ctx.mesh;
240 | if (compression.compressedData) {
241 | var compressedData = compression.compressedData;
242 | vertexCount = compressedData.verticesCount;
243 | var ifs = this.decode(resource, compressedData.mode === "ascii");
244 | var indicesShort = ifs.GetCoordIndex();
245 | var positions = ifs.GetCoord();
246 | var normals = ifs.GetNNormal() > 0 ? ifs.GetNormal() : null;
247 | ctx.renderer.setupCompressedMesh2(ctx.mesh, vertexCount, positions, normals, ifs, compressedData.floatAttributesIndexes, indicesShort);
248 | }
249 | }
250 |
251 | return resource;
252 | },
253 |
254 | resourceAvailable: function (glResource, ctx) {
255 | }
256 | }
257 | },
258 |
259 | scene: {
260 | get: function() {
261 | return this.technique.rootPass.scene;
262 | },
263 | set: function(value) {
264 | var self = this;
265 | var scene = this.technique.rootPass.scene;
266 | if (scene != value) {
267 | this.technique.rootPass.scene = value;
268 |
269 | this.scene.rootNode.apply( function(node, parent, context) {
270 | if (node.meshes) {
271 | node.meshes.forEach(function (mesh) {
272 | if (mesh.compression) {
273 | var requestType = "text";
274 | if (mesh.compression.compressedData.mode) {
275 | if (mesh.compression.compressedData.mode == "binary") {
276 | requestType = "arraybuffer";
277 | }
278 | }
279 |
280 | mesh.compression.compressedData.requestType = requestType;
281 |
282 | self.webGLRenderer.resourceManager.getResource(
283 | mesh.compression.compressedData,
284 | self.compressedMeshDelegate,
285 | { "mesh" : mesh, "renderer" : self.webGLRenderer});
286 | }
287 | }, this);
288 | }
289 | } , true, null);
290 |
291 | }
292 | }
293 | },
294 |
295 | webGLRenderer: {
296 | get: function() {
297 | return this._webGLRenderer;
298 | },
299 | set: function(value) {
300 | this._webGLRenderer = value;
301 | }
302 | },
303 |
304 | init: {
305 | value: function( webGLRenderer, options) {
306 | this.webGLRenderer = webGLRenderer;
307 | this.createTechniqueIfNeeded();
308 | this.loadPickingTechnique();
309 | return this;
310 | }
311 | },
312 |
313 | render: {
314 | value: function(time, options) {
315 | if (this.technique)
316 | this.technique.execute(this.webGLRenderer, time, options);
317 | }
318 | }
319 |
320 | });
321 |
322 |
--------------------------------------------------------------------------------
/runtime/glTF-node.js:
--------------------------------------------------------------------------------
1 | // Copyright (c) 2013, Fabrice Robinet
2 | // All rights reserved.
3 | //
4 | // Redistribution and use in source and binary forms, with or without
5 | // modification, are permitted provided that the following conditions are met:
6 | //
7 | // * Redistributions of source code must retain the above copyright
8 | // notice, this list of conditions and the following disclaimer.
9 | // * Redistributions in binary form must reproduce the above copyright
10 | // notice, this list of conditions and the following disclaimer in the
11 | // documentation and/or other materials provided with the distribution.
12 | //
13 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
14 | // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 | // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 | // ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY
17 | // DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18 | // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
20 | // ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21 | // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22 | // THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 |
24 | require("runtime/dependencies/gl-matrix");
25 | var Base = require("runtime/base").Base;
26 | var Transform = require("runtime/transform").Transform;
27 | var Utilities = require("runtime/utilities").Utilities;
28 |
29 | var glTFNode = exports.glTFNode = Object.create(Base, {
30 |
31 | //just for glTFNode singleton
32 | currentId: { value: 0, writable:true },
33 |
34 | bumpId: {
35 | value: function() {
36 | return glTFNode._id++;
37 | }
38 | },
39 |
40 | _children: { value: null, writable: true },
41 |
42 | children: {
43 | get: function() {
44 | return this._children;
45 | },
46 | set: function(value) {
47 | this._children = value;
48 | }
49 | },
50 |
51 | _id: { value: null, writable: true },
52 |
53 | id: {
54 | get: function() {
55 | return this._id;
56 | },
57 | set: function(value) {
58 | this._id = value;
59 | }
60 | },
61 |
62 | _hidden: { value: null, writable: true },
63 |
64 | hidden: {
65 | get: function() {
66 | return this._hidden;
67 | },
68 | set: function(value) {
69 | this._hidden = value;
70 | }
71 | },
72 |
73 | _computeBBOXIfNeeded: {
74 | enumerable: false,
75 | value: function() {
76 | if (!this._boundingBox) {
77 | var meshes = this._properties["meshes"];
78 | var count = this.meshes.length;
79 | if (count > 0) {
80 | var bbox = this.meshes[0].boundingBox;
81 | if (bbox) {
82 | var i;
83 | for (i = 1 ; i < count ; i++) {
84 | var aBBox = this.meshes[i].boundingBox;
85 | if (aBBox) { //it could be not here here as we are loading everything asynchronously
86 | bbox = Utilities.mergeBBox(bbox, aBBox);
87 | }
88 | }
89 | this._boundingBox = bbox;//Utilities.transformBBox(bbox, this.transform);
90 | }
91 | }
92 | }
93 | }
94 | },
95 |
96 | getBoundingBox: {
97 | value: function(includesHierarchy) {
98 | //FIXME: this code is inefficient, BBOX be cached with dirty flags and invalidation (just like for worldMatrix)
99 | if (includesHierarchy) {
100 | var ctx = mat4.identity();
101 | var hierarchicalBBOX = this.boundingBox;
102 | this.apply( function(node, parent, parentTransform) {
103 | var modelMatrix = mat4.create();
104 | mat4.multiply( parentTransform, node.transform.matrix, modelMatrix);
105 | if (node.boundingBox) {
106 | var bbox = Utilities.transformBBox(node.boundingBox, modelMatrix);
107 |
108 | if (hierarchicalBBOX) {
109 | if (node.meshes) {
110 | if (node.meshes.length > 0)
111 | hierarchicalBBOX = Utilities.mergeBBox(bbox, hierarchicalBBOX);
112 | }
113 | } else {
114 | hierarchicalBBOX = bbox;
115 | }
116 | }
117 | return modelMatrix;
118 | }, true, ctx);
119 | return hierarchicalBBOX;
120 | } else {
121 | return this.boundingBox;
122 | }
123 | }
124 | },
125 |
126 | _boundingBox: {
127 | enumerable: false,
128 | value: null,
129 | writable: true
130 | },
131 |
132 | boundingBox: {
133 | enumerable: true,
134 | get: function() {
135 | this._computeBBOXIfNeeded();
136 | return this._boundingBox;
137 | },
138 | // we let the possibility to override by hand the bounding volume.
139 | set: function(value) {
140 | this._boundingBox = value;
141 | }
142 | },
143 |
144 | meshesDidChange: {
145 | value: function(meshes) {
146 | this._boundingBox = null; //invalidate bounding box
147 | }
148 | },
149 |
150 | nodesDidChange: {
151 | value: function(nodes) {
152 | }
153 | },
154 |
155 | _parent: { value: null, writable: true},
156 |
157 | parent: {
158 | get: function() {
159 | return this._parent;
160 | }
161 | },
162 |
163 | init: {
164 | value: function() {
165 | this.__Base_init();
166 | this._children = [];
167 | this.transform = Object.create(Transform).init();
168 | this._properties["meshes"] = [];
169 |
170 | var self = this;
171 | this._properties["meshes"].push = function(data) {
172 | var result = Array.prototype.push.call(this, data);
173 | self.meshesDidChange(this);
174 | return result;
175 | }
176 |
177 | this._children.push = function(data) {
178 | var result = Array.prototype.push.call(this, data);
179 | data._parent = self;
180 | self.nodesDidChange(this);
181 | return result;
182 | }
183 |
184 | this._properties["cameras"] = [];
185 | this._properties["lights"] = [];
186 |
187 | this._worldMatrixIsDirty = true;
188 | this._worldMatrix = mat4.create();
189 |
190 | return this;
191 | }
192 | },
193 |
194 | initWithID: {
195 | value: function(id) {
196 | if (id == null)
197 | this.id = this.id + "-" +this.bumpId();
198 | else
199 | this.id = id;
200 | return this.init();
201 | }
202 | },
203 |
204 | getPropertyArrayNamed: {
205 | value: function(name) {
206 | return this._properties[name]
207 | }
208 | },
209 |
210 | _observers: { value: null, writable: true},
211 |
212 | addObserver: {
213 | value: function(observer) {
214 | if (this._observers == null) {
215 | this._observers = [];
216 | }
217 |
218 | if (this._observers.indexOf(observer) === -1) {
219 | this._observers.push(observer);
220 | } else {
221 | console.log("WARNING attempt to add 2 times the same observer in transform")
222 | }
223 | }
224 | },
225 |
226 | removeObserver: {
227 | value: function(observer) {
228 | if (this._observers) {
229 | var index = this._observers.indexOf(observer);
230 | if (index !== -1) {
231 | this._observers.splice(index, 1);
232 | }
233 | }
234 | }
235 | },
236 |
237 | _transform: { value: null, writable: true },
238 |
239 | transform: {
240 | get: function() {
241 | if (this.target) {
242 | var targetWorldMatrix = this.target.worldMatrix;
243 |
244 | var sourcePosition = this._transform.translation;
245 | var targetPosition = vec3.create();
246 | var up = [0 , 1, 0];
247 |
248 | Utilities.decomposeMat4(targetWorldMatrix, targetPosition, null, null);
249 |
250 | var lookatmat = mat4.lookAt(sourcePosition, targetPosition, up);
251 | mat4.inverse(lookatmat);
252 | var transform = Object.create(Transform).init();
253 | transform.matrix = lookatmat;
254 |
255 | this._transform.rotation = transform.rotation;
256 | }
257 | return this._transform;
258 | },
259 | set: function(value) {
260 | if (this._observers) {
261 | for (var i = 0 ; i < this._observers.length ; i++) {
262 | this._observers[i].transformWillChange(this, this._transform, value);
263 | }
264 | }
265 |
266 | if (this._transform) {
267 | this._transform.removeObserver(this);
268 | }
269 | this._transform = value;
270 | this._invalidateWorldMatrix();
271 |
272 | if (this._transform) {
273 | this._transform.addObserver(this);
274 | }
275 |
276 | if (this._observers) {
277 | for (var i = 0 ; i < this._observers.length ; i++) {
278 | this._observers[i].transformDidChange(this);
279 | }
280 | }
281 |
282 | }
283 | },
284 |
285 | meshes: {
286 | get: function() {
287 | return this.getPropertyArrayNamed("meshes");
288 | },
289 | set: function(value) {
290 | this._properties["meshes"] = value;
291 | this.meshesDidChange(value);
292 | }
293 | },
294 |
295 | cameras: {
296 | get: function() {
297 | return this.getPropertyArrayNamed("cameras");
298 | },
299 | set: function(value) {
300 | this._properties["cameras"] = value;
301 | }
302 | },
303 |
304 | lights: {
305 | get: function() {
306 | return this.getPropertyArrayNamed("lights");
307 | },
308 | set: function(value) {
309 | this._properties["lights"] = value;
310 | }
311 | },
312 |
313 | _apply: {
314 | value: function( callback, recurse, parent, ctx) {
315 |
316 | if (callback) {
317 | ctx = callback(this, parent, ctx);
318 |
319 | if (recurse) {
320 | this.children.forEach( function(node) {
321 | node._apply(callback, recurse, this, ctx);
322 | }, this);
323 | }
324 | }
325 | }
326 | },
327 |
328 | apply: {
329 | value: function( callback, recurse, ctx) {
330 | this._apply(callback, recurse, null, ctx);
331 | }
332 | },
333 |
334 | //TODO: generalize nodeWithName and apply
335 | _nodeWithName: {
336 | value: function( name) {
337 | if (this.name === name)
338 | return this;
339 |
340 | if (this.children) {
341 | for (var i = 0 ; i < this.children.length ; i++) {
342 | var node = this.children[i];
343 | var res = node._nodeWithName(name);
344 | if (res) {
345 | return res;
346 | }
347 | }
348 | }
349 |
350 | return null;
351 | }
352 | },
353 |
354 | nodeWithName: {
355 | value: function(name) {
356 | return this._nodeWithName(name);
357 | }
358 | },
359 |
360 | _nodeWithID: {
361 | value: function( id) {
362 | if (this.id === id)
363 | return this;
364 |
365 | if (this.children) {
366 | for (var i = 0 ; i < this.children.length ; i++) {
367 | var node = this.children[i];
368 | var res = node._nodeWithID(id);
369 | if (res) {
370 | return res;
371 | }
372 | }
373 | }
374 |
375 | return null;
376 | }
377 | },
378 |
379 | nodeWithJointID: {
380 | value: function(id) {
381 | return this._nodeWithJointID(id);
382 | }
383 | },
384 |
385 | _nodeWithJointID: {
386 | value: function( id) {
387 | if (this.jointId === id)
388 | return this;
389 |
390 | if (this.children) {
391 | for (var i = 0 ; i < this.children.length ; i++) {
392 | var node = this.children[i];
393 | var res = node._nodeWithJointID(id);
394 | if (res) {
395 | return res;
396 | }
397 | }
398 | }
399 |
400 | return null;
401 | }
402 | },
403 |
404 | nodeWithID: {
405 | value: function(id) {
406 | return this._nodeWithID(id);
407 | }
408 | },
409 |
410 | copy: {
411 | value: function(node) {
412 | var node = Object.create(glTFNode).init();
413 |
414 | node.name = this.name;
415 | if (this.meshes) {
416 | this.meshes.forEach( function(mesh) {
417 | node.meshes.push(mesh);
418 | }, this);
419 | }
420 | if (this.lights) {
421 | this.lights.forEach( function(light) {
422 | node.lights.push(light);
423 | }, this);
424 | }
425 | if (this.cameras) {
426 | this.cameras.forEach( function(camera) {
427 | node.cameras.push(camera);
428 | }, this);
429 | }
430 |
431 | //for copies of nodes coming from a DAG we keep track of the id but still, we want to be different
432 | var postId = this.bumpId();
433 | node.id = this.id + "-" +postId;
434 | node.baseId = this.baseId + "-" +postId;
435 | node.transform = this.transform.copy();
436 |
437 | return node;
438 | }
439 | },
440 |
441 | _worldMatrixIsDirty: { value: true, writable:true },
442 |
443 | _worldMatrix: { value: null, writable:true },
444 |
445 | _offsetMatrix: { value: null, writable:true },
446 |
447 | _originVector: { value: null, writable:true },
448 |
449 | worldMatrix: {
450 | get: function() {
451 | if (this.parent) {
452 | //TODO: handle case with target !
453 | if (this._worldMatrixIsDirty || (this.target != null)) {
454 | mat4.multiply(this.parent.worldMatrix, this.transform.matrix, this._worldMatrix);
455 | this._worldMatrixIsDirty = false;
456 | }
457 | if (this._offsetMatrix != null) {
458 | var bbox = this.getBoundingBox(false);
459 | if (bbox != null) {
460 | //this is now just for testing purposes, not optimized * at all *
461 | var inv = mat4.create();
462 | var res = mat4.identity();
463 | var res2 = mat4.create();
464 |
465 | var originVector = vec3.createFrom(0.5, 0.5, 0.5);
466 | if (this._originVector != null) {
467 | originVector[0] = this._originVector[0] / 100.0;
468 | originVector[1] = this._originVector[1] / 100.0;
469 | originVector[2] = this._originVector[2] / 100.0;
470 | }
471 |
472 | var mid = [
473 | (bbox[0][0] + bbox[1][0]) * originVector[0],
474 | (bbox[0][1] + bbox[1][1]) * originVector[0],
475 | (bbox[0][2] + bbox[1][2]) * originVector[0]];
476 |
477 | var tr1 = vec3.create(mid);
478 | mat4.translate(res, tr1);
479 | mat4.multiply(res, this._offsetMatrix, res2);
480 | mat4.multiply(this._worldMatrix, res2, res);
481 | tr1[0] = -tr1[0];
482 | tr1[1] = -tr1[1];
483 | tr1[2] = -tr1[2];
484 | mat4.translate(res, tr1);
485 |
486 | return res;
487 | }
488 | }
489 |
490 | return this._worldMatrix;
491 | } else {
492 | this._worldMatrixIsDirty = false;
493 | return this.transform.matrix;
494 | }
495 | }
496 | },
497 |
498 | _ignoresTransformUpdates: { value: false, writable: true },
499 |
500 | _invalidateWorldMatrix: {
501 | value: function() {
502 | this._worldMatrixIsDirty = true;
503 |
504 | //hack to tell observer to invalidate themselves
505 | this._ignoresTransformUpdates = true;
506 | this._transform._fireTransformDidUpdate();
507 | this._ignoresTransformUpdates = false;
508 |
509 | if (this._children) {
510 | for (var i = 0 ; i < this._children.length ; i++) {
511 | this._children[i]._invalidateWorldMatrix();
512 | }
513 | }
514 | }
515 | },
516 |
517 | transformDidUpdate: {
518 | value: function() {
519 | if (this._ignoresTransformUpdates === false)
520 | this._invalidateWorldMatrix();
521 | }
522 | },
523 |
524 | nodeWithJointID: {
525 | value: function(id) {
526 | return this._nodeWithJointID(id);
527 | }
528 | },
529 |
530 | nodeWithPropertyNamed: {
531 | value: function( propertyName) {
532 | if (this[propertyName] != null)
533 | return this;
534 |
535 | if (this.children) {
536 | for (var i = 0 ; i < this.children.length ; i++) {
537 | var node = this.children[i];
538 | var res = node.nodeWithPropertyNamed(propertyName);
539 | if (res) {
540 | return res;
541 | }
542 | }
543 | }
544 | return null;
545 | }
546 | },
547 |
548 | _target: { value:null , writable:true },
549 |
550 | target: {
551 | get: function() {
552 | return this._target;
553 | },
554 | set: function(target) {
555 | this._target = target;
556 | }
557 | }
558 |
559 | });
560 |
--------------------------------------------------------------------------------