├── favicon.ico
├── screenshot.jpg
├── index.html
├── js
└── vendor
│ ├── threejs
│ ├── texture-loader.js
│ ├── obj-loader.js
│ └── collada-loader.js
│ └── codemirror
│ ├── active-line.js
│ ├── matchbrackets.js
│ ├── closebrackets.js
│ └── clojure.js
├── css
├── vendor
│ ├── neo.css
│ └── codemirror.css
└── main.css
└── README.md
/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roman01la/threejs-cljs-playground/gh-pages/favicon.ico
--------------------------------------------------------------------------------
/screenshot.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/roman01la/threejs-cljs-playground/gh-pages/screenshot.jpg
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | the CSS class "CodeMirror-activeline",
8 | // and gives its background
the class "CodeMirror-activeline-background".
9 |
10 | (function(mod) {
11 | if (typeof exports == "object" && typeof module == "object") // CommonJS
12 | mod(require("../../lib/codemirror"));
13 | else if (typeof define == "function" && define.amd) // AMD
14 | define(["../../lib/codemirror"], mod);
15 | else // Plain browser env
16 | mod(CodeMirror);
17 | })(function(CodeMirror) {
18 | "use strict";
19 | var WRAP_CLASS = "CodeMirror-activeline";
20 | var BACK_CLASS = "CodeMirror-activeline-background";
21 |
22 | CodeMirror.defineOption("styleActiveLine", false, function(cm, val, old) {
23 | var prev = old && old != CodeMirror.Init;
24 | if (val && !prev) {
25 | cm.state.activeLines = [];
26 | updateActiveLines(cm, cm.listSelections());
27 | cm.on("beforeSelectionChange", selectionChange);
28 | } else if (!val && prev) {
29 | cm.off("beforeSelectionChange", selectionChange);
30 | clearActiveLines(cm);
31 | delete cm.state.activeLines;
32 | }
33 | });
34 |
35 | function clearActiveLines(cm) {
36 | for (var i = 0; i < cm.state.activeLines.length; i++) {
37 | cm.removeLineClass(cm.state.activeLines[i], "wrap", WRAP_CLASS);
38 | cm.removeLineClass(cm.state.activeLines[i], "background", BACK_CLASS);
39 | }
40 | }
41 |
42 | function sameArray(a, b) {
43 | if (a.length != b.length) return false;
44 | for (var i = 0; i < a.length; i++)
45 | if (a[i] != b[i]) return false;
46 | return true;
47 | }
48 |
49 | function updateActiveLines(cm, ranges) {
50 | var active = [];
51 | for (var i = 0; i < ranges.length; i++) {
52 | var range = ranges[i];
53 | if (!range.empty()) continue;
54 | var line = cm.getLineHandleVisualStart(range.head.line);
55 | if (active[active.length - 1] != line) active.push(line);
56 | }
57 | if (sameArray(cm.state.activeLines, active)) return;
58 | cm.operation(function() {
59 | clearActiveLines(cm);
60 | for (var i = 0; i < active.length; i++) {
61 | cm.addLineClass(active[i], "wrap", WRAP_CLASS);
62 | cm.addLineClass(active[i], "background", BACK_CLASS);
63 | }
64 | cm.state.activeLines = active;
65 | });
66 | }
67 |
68 | function selectionChange(cm, sel) {
69 | updateActiveLines(cm, sel.ranges);
70 | }
71 | });
72 |
--------------------------------------------------------------------------------
/js/vendor/codemirror/matchbrackets.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | var ie_lt8 = /MSIE \d/.test(navigator.userAgent) &&
13 | (document.documentMode == null || document.documentMode < 8);
14 |
15 | var Pos = CodeMirror.Pos;
16 |
17 | var matching = {"(": ")>", ")": "(<", "[": "]>", "]": "[<", "{": "}>", "}": "{<"};
18 |
19 | function findMatchingBracket(cm, where, strict, config) {
20 | var line = cm.getLineHandle(where.line), pos = where.ch - 1;
21 | var match = (pos >= 0 && matching[line.text.charAt(pos)]) || matching[line.text.charAt(++pos)];
22 | if (!match) return null;
23 | var dir = match.charAt(1) == ">" ? 1 : -1;
24 | if (strict && (dir > 0) != (pos == where.ch)) return null;
25 | var style = cm.getTokenTypeAt(Pos(where.line, pos + 1));
26 |
27 | var found = scanForBracket(cm, Pos(where.line, pos + (dir > 0 ? 1 : 0)), dir, style || null, config);
28 | if (found == null) return null;
29 | return {from: Pos(where.line, pos), to: found && found.pos,
30 | match: found && found.ch == match.charAt(0), forward: dir > 0};
31 | }
32 |
33 | // bracketRegex is used to specify which type of bracket to scan
34 | // should be a regexp, e.g. /[[\]]/
35 | //
36 | // Note: If "where" is on an open bracket, then this bracket is ignored.
37 | //
38 | // Returns false when no bracket was found, null when it reached
39 | // maxScanLines and gave up
40 | function scanForBracket(cm, where, dir, style, config) {
41 | var maxScanLen = (config && config.maxScanLineLength) || 10000;
42 | var maxScanLines = (config && config.maxScanLines) || 1000;
43 |
44 | var stack = [];
45 | var re = config && config.bracketRegex ? config.bracketRegex : /[(){}[\]]/;
46 | var lineEnd = dir > 0 ? Math.min(where.line + maxScanLines, cm.lastLine() + 1)
47 | : Math.max(cm.firstLine() - 1, where.line - maxScanLines);
48 | for (var lineNo = where.line; lineNo != lineEnd; lineNo += dir) {
49 | var line = cm.getLine(lineNo);
50 | if (!line) continue;
51 | var pos = dir > 0 ? 0 : line.length - 1, end = dir > 0 ? line.length : -1;
52 | if (line.length > maxScanLen) continue;
53 | if (lineNo == where.line) pos = where.ch - (dir < 0 ? 1 : 0);
54 | for (; pos != end; pos += dir) {
55 | var ch = line.charAt(pos);
56 | if (re.test(ch) && (style === undefined || cm.getTokenTypeAt(Pos(lineNo, pos + 1)) == style)) {
57 | var match = matching[ch];
58 | if ((match.charAt(1) == ">") == (dir > 0)) stack.push(ch);
59 | else if (!stack.length) return {pos: Pos(lineNo, pos), ch: ch};
60 | else stack.pop();
61 | }
62 | }
63 | }
64 | return lineNo - dir == (dir > 0 ? cm.lastLine() : cm.firstLine()) ? false : null;
65 | }
66 |
67 | function matchBrackets(cm, autoclear, config) {
68 | // Disable brace matching in long lines, since it'll cause hugely slow updates
69 | var maxHighlightLen = cm.state.matchBrackets.maxHighlightLineLength || 1000;
70 | var marks = [], ranges = cm.listSelections();
71 | for (var i = 0; i < ranges.length; i++) {
72 | var match = ranges[i].empty() && findMatchingBracket(cm, ranges[i].head, false, config);
73 | if (match && cm.getLine(match.from.line).length <= maxHighlightLen) {
74 | var style = match.match ? "CodeMirror-matchingbracket" : "CodeMirror-nonmatchingbracket";
75 | marks.push(cm.markText(match.from, Pos(match.from.line, match.from.ch + 1), {className: style}));
76 | if (match.to && cm.getLine(match.to.line).length <= maxHighlightLen)
77 | marks.push(cm.markText(match.to, Pos(match.to.line, match.to.ch + 1), {className: style}));
78 | }
79 | }
80 |
81 | if (marks.length) {
82 | // Kludge to work around the IE bug from issue #1193, where text
83 | // input stops going to the textare whever this fires.
84 | if (ie_lt8 && cm.state.focused) cm.focus();
85 |
86 | var clear = function() {
87 | cm.operation(function() {
88 | for (var i = 0; i < marks.length; i++) marks[i].clear();
89 | });
90 | };
91 | if (autoclear) setTimeout(clear, 800);
92 | else return clear;
93 | }
94 | }
95 |
96 | var currentlyHighlighted = null;
97 | function doMatchBrackets(cm) {
98 | cm.operation(function() {
99 | if (currentlyHighlighted) {currentlyHighlighted(); currentlyHighlighted = null;}
100 | currentlyHighlighted = matchBrackets(cm, false, cm.state.matchBrackets);
101 | });
102 | }
103 |
104 | CodeMirror.defineOption("matchBrackets", false, function(cm, val, old) {
105 | if (old && old != CodeMirror.Init)
106 | cm.off("cursorActivity", doMatchBrackets);
107 | if (val) {
108 | cm.state.matchBrackets = typeof val == "object" ? val : {};
109 | cm.on("cursorActivity", doMatchBrackets);
110 | }
111 | });
112 |
113 | CodeMirror.defineExtension("matchBrackets", function() {matchBrackets(this, true);});
114 | CodeMirror.defineExtension("findMatchingBracket", function(pos, strict, config){
115 | return findMatchingBracket(this, pos, strict, config);
116 | });
117 | CodeMirror.defineExtension("scanForBracket", function(pos, dir, style, config){
118 | return scanForBracket(this, pos, dir, style, config);
119 | });
120 | });
121 |
--------------------------------------------------------------------------------
/js/vendor/codemirror/closebrackets.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | (function(mod) {
5 | if (typeof exports == "object" && typeof module == "object") // CommonJS
6 | mod(require("../../lib/codemirror"));
7 | else if (typeof define == "function" && define.amd) // AMD
8 | define(["../../lib/codemirror"], mod);
9 | else // Plain browser env
10 | mod(CodeMirror);
11 | })(function(CodeMirror) {
12 | var defaults = {
13 | pairs: "()[]{}''\"\"",
14 | triples: "",
15 | explode: "[]{}"
16 | };
17 |
18 | var Pos = CodeMirror.Pos;
19 |
20 | CodeMirror.defineOption("autoCloseBrackets", false, function(cm, val, old) {
21 | if (old && old != CodeMirror.Init) {
22 | cm.removeKeyMap(keyMap);
23 | cm.state.closeBrackets = null;
24 | }
25 | if (val) {
26 | cm.state.closeBrackets = val;
27 | cm.addKeyMap(keyMap);
28 | }
29 | });
30 |
31 | function getOption(conf, name) {
32 | if (name == "pairs" && typeof conf == "string") return conf;
33 | if (typeof conf == "object" && conf[name] != null) return conf[name];
34 | return defaults[name];
35 | }
36 |
37 | var bind = defaults.pairs + "`";
38 | var keyMap = {Backspace: handleBackspace, Enter: handleEnter};
39 | for (var i = 0; i < bind.length; i++)
40 | keyMap["'" + bind.charAt(i) + "'"] = handler(bind.charAt(i));
41 |
42 | function handler(ch) {
43 | return function(cm) { return handleChar(cm, ch); };
44 | }
45 |
46 | function getConfig(cm) {
47 | var deflt = cm.state.closeBrackets;
48 | if (!deflt) return null;
49 | var mode = cm.getModeAt(cm.getCursor());
50 | return mode.closeBrackets || deflt;
51 | }
52 |
53 | function handleBackspace(cm) {
54 | var conf = getConfig(cm);
55 | if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
56 |
57 | var pairs = getOption(conf, "pairs");
58 | var ranges = cm.listSelections();
59 | for (var i = 0; i < ranges.length; i++) {
60 | if (!ranges[i].empty()) return CodeMirror.Pass;
61 | var around = charsAround(cm, ranges[i].head);
62 | if (!around || pairs.indexOf(around) % 2 != 0) return CodeMirror.Pass;
63 | }
64 | for (var i = ranges.length - 1; i >= 0; i--) {
65 | var cur = ranges[i].head;
66 | cm.replaceRange("", Pos(cur.line, cur.ch - 1), Pos(cur.line, cur.ch + 1));
67 | }
68 | }
69 |
70 | function handleEnter(cm) {
71 | var conf = getConfig(cm);
72 | var explode = conf && getOption(conf, "explode");
73 | if (!explode || cm.getOption("disableInput")) return CodeMirror.Pass;
74 |
75 | var ranges = cm.listSelections();
76 | for (var i = 0; i < ranges.length; i++) {
77 | if (!ranges[i].empty()) return CodeMirror.Pass;
78 | var around = charsAround(cm, ranges[i].head);
79 | if (!around || explode.indexOf(around) % 2 != 0) return CodeMirror.Pass;
80 | }
81 | cm.operation(function() {
82 | cm.replaceSelection("\n\n", null);
83 | cm.execCommand("goCharLeft");
84 | ranges = cm.listSelections();
85 | for (var i = 0; i < ranges.length; i++) {
86 | var line = ranges[i].head.line;
87 | cm.indentLine(line, null, true);
88 | cm.indentLine(line + 1, null, true);
89 | }
90 | });
91 | }
92 |
93 | function handleChar(cm, ch) {
94 | var conf = getConfig(cm);
95 | if (!conf || cm.getOption("disableInput")) return CodeMirror.Pass;
96 |
97 | var pairs = getOption(conf, "pairs");
98 | var pos = pairs.indexOf(ch);
99 | if (pos == -1) return CodeMirror.Pass;
100 | var triples = getOption(conf, "triples");
101 |
102 | var identical = pairs.charAt(pos + 1) == ch;
103 | var ranges = cm.listSelections();
104 | var opening = pos % 2 == 0;
105 |
106 | var type, next;
107 | for (var i = 0; i < ranges.length; i++) {
108 | var range = ranges[i], cur = range.head, curType;
109 | var next = cm.getRange(cur, Pos(cur.line, cur.ch + 1));
110 | if (opening && !range.empty()) {
111 | curType = "surround";
112 | } else if ((identical || !opening) && next == ch) {
113 | if (triples.indexOf(ch) >= 0 && cm.getRange(cur, Pos(cur.line, cur.ch + 3)) == ch + ch + ch)
114 | curType = "skipThree";
115 | else
116 | curType = "skip";
117 | } else if (identical && cur.ch > 1 && triples.indexOf(ch) >= 0 &&
118 | cm.getRange(Pos(cur.line, cur.ch - 2), cur) == ch + ch &&
119 | (cur.ch <= 2 || cm.getRange(Pos(cur.line, cur.ch - 3), Pos(cur.line, cur.ch - 2)) != ch)) {
120 | curType = "addFour";
121 | } else if (identical) {
122 | if (!CodeMirror.isWordChar(next) && enteringString(cm, cur, ch)) curType = "both";
123 | else return CodeMirror.Pass;
124 | } else if (opening && (cm.getLine(cur.line).length == cur.ch ||
125 | isClosingBracket(next, pairs) ||
126 | /\s/.test(next))) {
127 | curType = "both";
128 | } else {
129 | return CodeMirror.Pass;
130 | }
131 | if (!type) type = curType;
132 | else if (type != curType) return CodeMirror.Pass;
133 | }
134 |
135 | var left = pos % 2 ? pairs.charAt(pos - 1) : ch;
136 | var right = pos % 2 ? ch : pairs.charAt(pos + 1);
137 | cm.operation(function() {
138 | if (type == "skip") {
139 | cm.execCommand("goCharRight");
140 | } else if (type == "skipThree") {
141 | for (var i = 0; i < 3; i++)
142 | cm.execCommand("goCharRight");
143 | } else if (type == "surround") {
144 | var sels = cm.getSelections();
145 | for (var i = 0; i < sels.length; i++)
146 | sels[i] = left + sels[i] + right;
147 | cm.replaceSelections(sels, "around");
148 | } else if (type == "both") {
149 | cm.replaceSelection(left + right, null);
150 | cm.triggerElectric(left + right);
151 | cm.execCommand("goCharLeft");
152 | } else if (type == "addFour") {
153 | cm.replaceSelection(left + left + left + left, "before");
154 | cm.execCommand("goCharRight");
155 | }
156 | });
157 | }
158 |
159 | function isClosingBracket(ch, pairs) {
160 | var pos = pairs.lastIndexOf(ch);
161 | return pos > -1 && pos % 2 == 1;
162 | }
163 |
164 | function charsAround(cm, pos) {
165 | var str = cm.getRange(Pos(pos.line, pos.ch - 1),
166 | Pos(pos.line, pos.ch + 1));
167 | return str.length == 2 ? str : null;
168 | }
169 |
170 | // Project the token type that will exists after the given char is
171 | // typed, and use it to determine whether it would cause the start
172 | // of a string token.
173 | function enteringString(cm, pos, ch) {
174 | var line = cm.getLine(pos.line);
175 | var token = cm.getTokenAt(pos);
176 | if (/\bstring2?\b/.test(token.type)) return false;
177 | var stream = new CodeMirror.StringStream(line.slice(0, pos.ch) + ch + line.slice(pos.ch), 4);
178 | stream.pos = stream.start = token.start;
179 | for (;;) {
180 | var type1 = cm.getMode().token(stream, token.state);
181 | if (stream.pos >= pos.ch + 1) return /\bstring2?\b/.test(type1);
182 | stream.start = stream.pos;
183 | }
184 | }
185 | });
186 |
--------------------------------------------------------------------------------
/css/vendor/codemirror.css:
--------------------------------------------------------------------------------
1 | /* BASICS */
2 |
3 | .CodeMirror {
4 | /* Set height, width, borders, and global font properties here */
5 | font-family: monospace;
6 | height: 300px;
7 | color: black;
8 | }
9 |
10 | /* PADDING */
11 |
12 | .CodeMirror-lines {
13 | padding: 4px 0; /* Vertical padding around content */
14 | }
15 | .CodeMirror pre {
16 | padding: 0 4px; /* Horizontal padding of content */
17 | }
18 |
19 | .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
20 | background-color: white; /* The little square between H and V scrollbars */
21 | }
22 |
23 | /* GUTTER */
24 |
25 | .CodeMirror-gutters {
26 | border-right: 1px solid #ddd;
27 | background-color: #f7f7f7;
28 | white-space: nowrap;
29 | }
30 | .CodeMirror-linenumbers {}
31 | .CodeMirror-linenumber {
32 | padding: 0 3px 0 5px;
33 | min-width: 20px;
34 | text-align: right;
35 | color: #999;
36 | white-space: nowrap;
37 | }
38 |
39 | .CodeMirror-guttermarker { color: black; }
40 | .CodeMirror-guttermarker-subtle { color: #999; }
41 |
42 | /* CURSOR */
43 |
44 | .CodeMirror div.CodeMirror-cursor {
45 | border-left: 1px solid black;
46 | }
47 | /* Shown when moving in bi-directional text */
48 | .CodeMirror div.CodeMirror-secondarycursor {
49 | border-left: 1px solid silver;
50 | }
51 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursor {
52 | width: auto;
53 | border: 0;
54 | background: #7e7;
55 | }
56 | .CodeMirror.cm-fat-cursor div.CodeMirror-cursors {
57 | z-index: 1;
58 | }
59 |
60 | .cm-animate-fat-cursor {
61 | width: auto;
62 | border: 0;
63 | -webkit-animation: blink 1.06s steps(1) infinite;
64 | -moz-animation: blink 1.06s steps(1) infinite;
65 | animation: blink 1.06s steps(1) infinite;
66 | background-color: #7e7;
67 | }
68 | @-moz-keyframes blink {
69 | 0% {}
70 | 50% { background-color: transparent; }
71 | 100% {}
72 | }
73 | @-webkit-keyframes blink {
74 | 0% {}
75 | 50% { background-color: transparent; }
76 | 100% {}
77 | }
78 | @keyframes blink {
79 | 0% {}
80 | 50% { background-color: transparent; }
81 | 100% {}
82 | }
83 |
84 | /* Can style cursor different in overwrite (non-insert) mode */
85 | div.CodeMirror-overwrite div.CodeMirror-cursor {}
86 |
87 | .cm-tab { display: inline-block; text-decoration: inherit; }
88 |
89 | .CodeMirror-ruler {
90 | border-left: 1px solid #ccc;
91 | position: absolute;
92 | }
93 |
94 | /* DEFAULT THEME */
95 |
96 | .cm-s-default .cm-header {color: blue;}
97 | .cm-s-default .cm-quote {color: #090;}
98 | .cm-negative {color: #d44;}
99 | .cm-positive {color: #292;}
100 | .cm-header, .cm-strong {font-weight: bold;}
101 | .cm-em {font-style: italic;}
102 | .cm-link {text-decoration: underline;}
103 | .cm-strikethrough {text-decoration: line-through;}
104 |
105 | .cm-s-default .cm-keyword {color: #708;}
106 | .cm-s-default .cm-atom {color: #219;}
107 | .cm-s-default .cm-number {color: #164;}
108 | .cm-s-default .cm-def {color: #00f;}
109 | .cm-s-default .cm-variable,
110 | .cm-s-default .cm-punctuation,
111 | .cm-s-default .cm-property,
112 | .cm-s-default .cm-operator {}
113 | .cm-s-default .cm-variable-2 {color: #05a;}
114 | .cm-s-default .cm-variable-3 {color: #085;}
115 | .cm-s-default .cm-comment {color: #a50;}
116 | .cm-s-default .cm-string {color: #a11;}
117 | .cm-s-default .cm-string-2 {color: #f50;}
118 | .cm-s-default .cm-meta {color: #555;}
119 | .cm-s-default .cm-qualifier {color: #555;}
120 | .cm-s-default .cm-builtin {color: #30a;}
121 | .cm-s-default .cm-bracket {color: #997;}
122 | .cm-s-default .cm-tag {color: #170;}
123 | .cm-s-default .cm-attribute {color: #00c;}
124 | .cm-s-default .cm-hr {color: #999;}
125 | .cm-s-default .cm-link {color: #00c;}
126 |
127 | .cm-s-default .cm-error {color: #f00;}
128 | .cm-invalidchar {color: #f00;}
129 |
130 | .CodeMirror-composing { border-bottom: 2px solid; }
131 |
132 | /* Default styles for common addons */
133 |
134 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
135 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
136 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
137 | .CodeMirror-activeline-background {background: #e8f2ff;}
138 |
139 | /* STOP */
140 |
141 | /* The rest of this file contains styles related to the mechanics of
142 | the editor. You probably shouldn't touch them. */
143 |
144 | .CodeMirror {
145 | position: relative;
146 | overflow: hidden;
147 | background: white;
148 | }
149 |
150 | .CodeMirror-scroll {
151 | overflow: scroll !important; /* Things will break if this is overridden */
152 | /* 30px is the magic margin used to hide the element's real scrollbars */
153 | /* See overflow: hidden in .CodeMirror */
154 | margin-bottom: -30px; margin-right: -30px;
155 | padding-bottom: 30px;
156 | height: 100%;
157 | outline: none; /* Prevent dragging from highlighting the element */
158 | position: relative;
159 | }
160 | .CodeMirror-sizer {
161 | position: relative;
162 | border-right: 30px solid transparent;
163 | }
164 |
165 | /* The fake, visible scrollbars. Used to force redraw during scrolling
166 | before actuall scrolling happens, thus preventing shaking and
167 | flickering artifacts. */
168 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
169 | position: absolute;
170 | z-index: 6;
171 | display: none;
172 | }
173 | .CodeMirror-vscrollbar {
174 | right: 0; top: 0;
175 | overflow-x: hidden;
176 | overflow-y: scroll;
177 | }
178 | .CodeMirror-hscrollbar {
179 | bottom: 0; left: 0;
180 | overflow-y: hidden;
181 | overflow-x: scroll;
182 | }
183 | .CodeMirror-scrollbar-filler {
184 | right: 0; bottom: 0;
185 | }
186 | .CodeMirror-gutter-filler {
187 | left: 0; bottom: 0;
188 | }
189 |
190 | .CodeMirror-gutters {
191 | position: absolute; left: 0; top: 0;
192 | z-index: 3;
193 | }
194 | .CodeMirror-gutter {
195 | white-space: normal;
196 | height: 100%;
197 | display: inline-block;
198 | margin-bottom: -30px;
199 | /* Hack to make IE7 behave */
200 | *zoom:1;
201 | *display:inline;
202 | }
203 | .CodeMirror-gutter-wrapper {
204 | position: absolute;
205 | z-index: 4;
206 | background: none !important;
207 | border: none !important;
208 | }
209 | .CodeMirror-gutter-background {
210 | position: absolute;
211 | top: 0; bottom: 0;
212 | z-index: 4;
213 | }
214 | .CodeMirror-gutter-elt {
215 | position: absolute;
216 | cursor: default;
217 | z-index: 4;
218 | }
219 | .CodeMirror-gutter-wrapper {
220 | -webkit-user-select: none;
221 | -moz-user-select: none;
222 | user-select: none;
223 | }
224 |
225 | .CodeMirror-lines {
226 | cursor: text;
227 | min-height: 1px; /* prevents collapsing before first draw */
228 | }
229 | .CodeMirror pre {
230 | /* Reset some styles that the rest of the page might have set */
231 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
232 | border-width: 0;
233 | background: transparent;
234 | font-family: inherit;
235 | font-size: inherit;
236 | margin: 0;
237 | white-space: pre;
238 | word-wrap: normal;
239 | line-height: inherit;
240 | color: inherit;
241 | z-index: 2;
242 | position: relative;
243 | overflow: visible;
244 | -webkit-tap-highlight-color: transparent;
245 | }
246 | .CodeMirror-wrap pre {
247 | word-wrap: break-word;
248 | white-space: pre-wrap;
249 | word-break: normal;
250 | }
251 |
252 | .CodeMirror-linebackground {
253 | position: absolute;
254 | left: 0; right: 0; top: 0; bottom: 0;
255 | z-index: 0;
256 | }
257 |
258 | .CodeMirror-linewidget {
259 | position: relative;
260 | z-index: 2;
261 | overflow: auto;
262 | }
263 |
264 | .CodeMirror-widget {}
265 |
266 | .CodeMirror-code {
267 | outline: none;
268 | }
269 |
270 | /* Force content-box sizing for the elements where we expect it */
271 | .CodeMirror-scroll,
272 | .CodeMirror-sizer,
273 | .CodeMirror-gutter,
274 | .CodeMirror-gutters,
275 | .CodeMirror-linenumber {
276 | -moz-box-sizing: content-box;
277 | box-sizing: content-box;
278 | }
279 |
280 | .CodeMirror-measure {
281 | position: absolute;
282 | width: 100%;
283 | height: 0;
284 | overflow: hidden;
285 | visibility: hidden;
286 | }
287 | .CodeMirror-measure pre { position: static; }
288 |
289 | .CodeMirror div.CodeMirror-cursor {
290 | position: absolute;
291 | border-right: none;
292 | width: 0;
293 | }
294 |
295 | div.CodeMirror-cursors {
296 | visibility: hidden;
297 | position: relative;
298 | z-index: 3;
299 | }
300 | .CodeMirror-focused div.CodeMirror-cursors {
301 | visibility: visible;
302 | }
303 |
304 | .CodeMirror-selected { background: #d9d9d9; }
305 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
306 | .CodeMirror-crosshair { cursor: crosshair; }
307 | .CodeMirror-line::selection, .CodeMirror-line > span::selection, .CodeMirror-line > span > span::selection { background: #d7d4f0; }
308 | .CodeMirror-line::-moz-selection, .CodeMirror-line > span::-moz-selection, .CodeMirror-line > span > span::-moz-selection { background: #d7d4f0; }
309 |
310 | .cm-searching {
311 | background: #ffa;
312 | background: rgba(255, 255, 0, .4);
313 | }
314 |
315 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
316 | .CodeMirror span { *vertical-align: text-bottom; }
317 |
318 | /* Used to force a border model for a node */
319 | .cm-force-border { padding-right: .1px; }
320 |
321 | @media print {
322 | /* Hide the cursor when printing */
323 | .CodeMirror div.CodeMirror-cursors {
324 | visibility: hidden;
325 | }
326 | }
327 |
328 | /* See issue #2901 */
329 | .cm-tab-wrap-hack:after { content: ''; }
330 |
331 | /* Help users use markselection to safely style text background */
332 | span.CodeMirror-selectedtext { background: none; }
333 |
--------------------------------------------------------------------------------
/js/vendor/threejs/obj-loader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author mrdoob / http://mrdoob.com/
3 | */
4 |
5 | THREE.OBJLoader = function ( manager ) {
6 |
7 | this.manager = ( manager !== undefined ) ? manager : THREE.DefaultLoadingManager;
8 |
9 | };
10 |
11 | THREE.OBJLoader.prototype = {
12 |
13 | constructor: THREE.OBJLoader,
14 |
15 | load: function ( url, onLoad, onProgress, onError ) {
16 |
17 | var scope = this;
18 |
19 | var loader = new THREE.XHRLoader( scope.manager );
20 | loader.setCrossOrigin( this.crossOrigin );
21 | loader.load( url, function ( text ) {
22 |
23 | onLoad( scope.parse( text ) );
24 |
25 | }, onProgress, onError );
26 |
27 | },
28 |
29 | parse: function ( text ) {
30 |
31 | console.time( 'OBJLoader' );
32 |
33 | var object, objects = [];
34 | var geometry, material;
35 |
36 | function parseVertexIndex( value ) {
37 |
38 | var index = parseInt( value );
39 |
40 | return ( index >= 0 ? index - 1 : index + vertices.length / 3 ) * 3;
41 |
42 | }
43 |
44 | function parseNormalIndex( value ) {
45 |
46 | var index = parseInt( value );
47 |
48 | return ( index >= 0 ? index - 1 : index + normals.length / 3 ) * 3;
49 |
50 | }
51 |
52 | function parseUVIndex( value ) {
53 |
54 | var index = parseInt( value );
55 |
56 | return ( index >= 0 ? index - 1 : index + uvs.length / 2 ) * 2;
57 |
58 | }
59 |
60 | function addVertex( a, b, c ) {
61 |
62 | geometry.vertices.push(
63 | vertices[ a ], vertices[ a + 1 ], vertices[ a + 2 ],
64 | vertices[ b ], vertices[ b + 1 ], vertices[ b + 2 ],
65 | vertices[ c ], vertices[ c + 1 ], vertices[ c + 2 ]
66 | );
67 |
68 | }
69 |
70 | function addNormal( a, b, c ) {
71 |
72 | geometry.normals.push(
73 | normals[ a ], normals[ a + 1 ], normals[ a + 2 ],
74 | normals[ b ], normals[ b + 1 ], normals[ b + 2 ],
75 | normals[ c ], normals[ c + 1 ], normals[ c + 2 ]
76 | );
77 |
78 | }
79 |
80 | function addUV( a, b, c ) {
81 |
82 | geometry.uvs.push(
83 | uvs[ a ], uvs[ a + 1 ],
84 | uvs[ b ], uvs[ b + 1 ],
85 | uvs[ c ], uvs[ c + 1 ]
86 | );
87 |
88 | }
89 |
90 | function addFace( a, b, c, d, ua, ub, uc, ud, na, nb, nc, nd ) {
91 |
92 | var ia = parseVertexIndex( a );
93 | var ib = parseVertexIndex( b );
94 | var ic = parseVertexIndex( c );
95 | var id;
96 |
97 | if ( d === undefined ) {
98 |
99 | addVertex( ia, ib, ic );
100 |
101 | } else {
102 |
103 | id = parseVertexIndex( d );
104 |
105 | addVertex( ia, ib, id );
106 | addVertex( ib, ic, id );
107 |
108 | }
109 |
110 | if ( ua !== undefined ) {
111 |
112 | ia = parseUVIndex( ua );
113 | ib = parseUVIndex( ub );
114 | ic = parseUVIndex( uc );
115 |
116 | if ( d === undefined ) {
117 |
118 | addUV( ia, ib, ic );
119 |
120 | } else {
121 |
122 | id = parseUVIndex( ud );
123 |
124 | addUV( ia, ib, id );
125 | addUV( ib, ic, id );
126 |
127 | }
128 |
129 | }
130 |
131 | if ( na !== undefined ) {
132 |
133 | ia = parseNormalIndex( na );
134 | ib = parseNormalIndex( nb );
135 | ic = parseNormalIndex( nc );
136 |
137 | if ( d === undefined ) {
138 |
139 | addNormal( ia, ib, ic );
140 |
141 | } else {
142 |
143 | id = parseNormalIndex( nd );
144 |
145 | addNormal( ia, ib, id );
146 | addNormal( ib, ic, id );
147 |
148 | }
149 |
150 | }
151 |
152 | }
153 |
154 | // create mesh if no objects in text
155 |
156 | if ( /^o /gm.test( text ) === false ) {
157 |
158 | geometry = {
159 | vertices: [],
160 | normals: [],
161 | uvs: []
162 | };
163 |
164 | material = {
165 | name: ''
166 | };
167 |
168 | object = {
169 | name: '',
170 | geometry: geometry,
171 | material: material
172 | };
173 |
174 | objects.push( object );
175 |
176 | }
177 |
178 | var vertices = [];
179 | var normals = [];
180 | var uvs = [];
181 |
182 | // v float float float
183 |
184 | var vertex_pattern = /v( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
185 |
186 | // vn float float float
187 |
188 | var normal_pattern = /vn( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
189 |
190 | // vt float float
191 |
192 | var uv_pattern = /vt( +[\d|\.|\+|\-|e|E]+)( +[\d|\.|\+|\-|e|E]+)/;
193 |
194 | // f vertex vertex vertex ...
195 |
196 | var face_pattern1 = /f( +-?\d+)( +-?\d+)( +-?\d+)( +-?\d+)?/;
197 |
198 | // f vertex/uv vertex/uv vertex/uv ...
199 |
200 | var face_pattern2 = /f( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+))?/;
201 |
202 | // f vertex/uv/normal vertex/uv/normal vertex/uv/normal ...
203 |
204 | var face_pattern3 = /f( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))( +(-?\d+)\/(-?\d+)\/(-?\d+))?/;
205 |
206 | // f vertex//normal vertex//normal vertex//normal ...
207 |
208 | var face_pattern4 = /f( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))( +(-?\d+)\/\/(-?\d+))?/
209 |
210 | //
211 |
212 | var lines = text.split( '\n' );
213 |
214 | for ( var i = 0; i < lines.length; i ++ ) {
215 |
216 | var line = lines[ i ];
217 | line = line.trim();
218 |
219 | var result;
220 |
221 | if ( line.length === 0 || line.charAt( 0 ) === '#' ) {
222 |
223 | continue;
224 |
225 | } else if ( ( result = vertex_pattern.exec( line ) ) !== null ) {
226 |
227 | // ["v 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
228 |
229 | vertices.push(
230 | parseFloat( result[ 1 ] ),
231 | parseFloat( result[ 2 ] ),
232 | parseFloat( result[ 3 ] )
233 | );
234 |
235 | } else if ( ( result = normal_pattern.exec( line ) ) !== null ) {
236 |
237 | // ["vn 1.0 2.0 3.0", "1.0", "2.0", "3.0"]
238 |
239 | normals.push(
240 | parseFloat( result[ 1 ] ),
241 | parseFloat( result[ 2 ] ),
242 | parseFloat( result[ 3 ] )
243 | );
244 |
245 | } else if ( ( result = uv_pattern.exec( line ) ) !== null ) {
246 |
247 | // ["vt 0.1 0.2", "0.1", "0.2"]
248 |
249 | uvs.push(
250 | parseFloat( result[ 1 ] ),
251 | parseFloat( result[ 2 ] )
252 | );
253 |
254 | } else if ( ( result = face_pattern1.exec( line ) ) !== null ) {
255 |
256 | // ["f 1 2 3", "1", "2", "3", undefined]
257 |
258 | addFace(
259 | result[ 1 ], result[ 2 ], result[ 3 ], result[ 4 ]
260 | );
261 |
262 | } else if ( ( result = face_pattern2.exec( line ) ) !== null ) {
263 |
264 | // ["f 1/1 2/2 3/3", " 1/1", "1", "1", " 2/2", "2", "2", " 3/3", "3", "3", undefined, undefined, undefined]
265 |
266 | addFace(
267 | result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
268 | result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
269 | );
270 |
271 | } else if ( ( result = face_pattern3.exec( line ) ) !== null ) {
272 |
273 | // ["f 1/1/1 2/2/2 3/3/3", " 1/1/1", "1", "1", "1", " 2/2/2", "2", "2", "2", " 3/3/3", "3", "3", "3", undefined, undefined, undefined, undefined]
274 |
275 | addFace(
276 | result[ 2 ], result[ 6 ], result[ 10 ], result[ 14 ],
277 | result[ 3 ], result[ 7 ], result[ 11 ], result[ 15 ],
278 | result[ 4 ], result[ 8 ], result[ 12 ], result[ 16 ]
279 | );
280 |
281 | } else if ( ( result = face_pattern4.exec( line ) ) !== null ) {
282 |
283 | // ["f 1//1 2//2 3//3", " 1//1", "1", "1", " 2//2", "2", "2", " 3//3", "3", "3", undefined, undefined, undefined]
284 |
285 | addFace(
286 | result[ 2 ], result[ 5 ], result[ 8 ], result[ 11 ],
287 | undefined, undefined, undefined, undefined,
288 | result[ 3 ], result[ 6 ], result[ 9 ], result[ 12 ]
289 | );
290 |
291 | } else if ( /^o /.test( line ) ) {
292 |
293 | geometry = {
294 | vertices: [],
295 | normals: [],
296 | uvs: []
297 | };
298 |
299 | material = {
300 | name: ''
301 | };
302 |
303 | object = {
304 | name: line.substring( 2 ).trim(),
305 | geometry: geometry,
306 | material: material
307 | };
308 |
309 | objects.push( object )
310 |
311 | } else if ( /^g /.test( line ) ) {
312 |
313 | // group
314 |
315 | } else if ( /^usemtl /.test( line ) ) {
316 |
317 | // material
318 |
319 | material.name = line.substring( 7 ).trim();
320 |
321 | } else if ( /^mtllib /.test( line ) ) {
322 |
323 | // mtl file
324 |
325 | } else if ( /^s /.test( line ) ) {
326 |
327 | // smooth shading
328 |
329 | } else {
330 |
331 | // console.log( "THREE.OBJLoader: Unhandled line " + line );
332 |
333 | }
334 |
335 | }
336 |
337 | var container = new THREE.Object3D();
338 |
339 | for ( var i = 0, l = objects.length; i < l; i ++ ) {
340 |
341 | object = objects[ i ];
342 | geometry = object.geometry;
343 |
344 | var buffergeometry = new THREE.BufferGeometry();
345 |
346 | buffergeometry.addAttribute( 'position', new THREE.BufferAttribute( new Float32Array( geometry.vertices ), 3 ) );
347 |
348 | if ( geometry.normals.length > 0 ) {
349 | buffergeometry.addAttribute( 'normal', new THREE.BufferAttribute( new Float32Array( geometry.normals ), 3 ) );
350 | }
351 |
352 | if ( geometry.uvs.length > 0 ) {
353 | buffergeometry.addAttribute( 'uv', new THREE.BufferAttribute( new Float32Array( geometry.uvs ), 2 ) );
354 | }
355 |
356 | material = new THREE.MeshLambertMaterial();
357 | material.name = object.material.name;
358 |
359 | var mesh = new THREE.Mesh( buffergeometry, material );
360 | mesh.name = object.name;
361 |
362 | container.add( mesh );
363 |
364 | }
365 |
366 | console.timeEnd( 'OBJLoader' );
367 |
368 | return container;
369 |
370 | }
371 |
372 | };
373 |
--------------------------------------------------------------------------------
/js/vendor/codemirror/clojure.js:
--------------------------------------------------------------------------------
1 | // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 | // Distributed under an MIT license: http://codemirror.net/LICENSE
3 |
4 | /**
5 | * Author: Hans Engel
6 | * Branched from CodeMirror's Scheme mode (by Koh Zi Han, based on implementation by Koh Zi Chun)
7 | */
8 |
9 | (function(mod) {
10 | if (typeof exports == "object" && typeof module == "object") // CommonJS
11 | mod(require("../../lib/codemirror"));
12 | else if (typeof define == "function" && define.amd) // AMD
13 | define(["../../lib/codemirror"], mod);
14 | else // Plain browser env
15 | mod(CodeMirror);
16 | })(function(CodeMirror) {
17 | "use strict";
18 |
19 | CodeMirror.defineMode("clojure", function (options) {
20 | var BUILTIN = "builtin", COMMENT = "comment", STRING = "string", CHARACTER = "string-2",
21 | ATOM = "atom", NUMBER = "number", BRACKET = "bracket", KEYWORD = "keyword", VAR = "variable";
22 | var INDENT_WORD_SKIP = options.indentUnit || 2;
23 | var NORMAL_INDENT_UNIT = options.indentUnit || 2;
24 |
25 | function makeKeywords(str) {
26 | var obj = {}, words = str.split(" ");
27 | for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
28 | return obj;
29 | }
30 |
31 | var atoms = makeKeywords("true false nil");
32 |
33 | var keywords = makeKeywords(
34 | "defn defn- def def- defonce defmulti defmethod defmacro defstruct deftype defprotocol defrecord defproject deftest slice defalias defhinted defmacro- defn-memo defnk defnk defonce- defunbound defunbound- defvar defvar- let letfn do case cond condp for loop recur when when-not when-let when-first if if-let if-not . .. -> ->> doto and or dosync doseq dotimes dorun doall load import unimport ns in-ns refer try catch finally throw with-open with-local-vars binding gen-class gen-and-load-class gen-and-save-class handler-case handle");
35 |
36 | var builtins = makeKeywords(
37 | "* *' *1 *2 *3 *agent* *allow-unresolved-vars* *assert* *clojure-version* *command-line-args* *compile-files* *compile-path* *compiler-options* *data-readers* *e *err* *file* *flush-on-newline* *fn-loader* *in* *math-context* *ns* *out* *print-dup* *print-length* *print-level* *print-meta* *print-readably* *read-eval* *source-path* *unchecked-math* *use-context-classloader* *verbose-defrecords* *warn-on-reflection* + +' - -' -> ->> ->ArrayChunk ->Vec ->VecNode ->VecSeq -cache-protocol-fn -reset-methods .. / < <= = == > >= EMPTY-NODE accessor aclone add-classpath add-watch agent agent-error agent-errors aget alength alias all-ns alter alter-meta! alter-var-root amap ancestors and apply areduce array-map aset aset-boolean aset-byte aset-char aset-double aset-float aset-int aset-long aset-short assert assoc assoc! assoc-in associative? atom await await-for await1 bases bean bigdec bigint biginteger binding bit-and bit-and-not bit-clear bit-flip bit-not bit-or bit-set bit-shift-left bit-shift-right bit-test bit-xor boolean boolean-array booleans bound-fn bound-fn* bound? butlast byte byte-array bytes case cast char char-array char-escape-string char-name-string char? chars chunk chunk-append chunk-buffer chunk-cons chunk-first chunk-next chunk-rest chunked-seq? class class? clear-agent-errors clojure-version coll? comment commute comp comparator compare compare-and-set! compile complement concat cond condp conj conj! cons constantly construct-proxy contains? count counted? create-ns create-struct cycle dec dec' decimal? declare default-data-readers definline definterface defmacro defmethod defmulti defn defn- defonce defprotocol defrecord defstruct deftype delay delay? deliver denominator deref derive descendants destructure disj disj! dissoc dissoc! distinct distinct? doall dorun doseq dosync dotimes doto double double-array doubles drop drop-last drop-while empty empty? ensure enumeration-seq error-handler error-mode eval even? every-pred every? ex-data ex-info extend extend-protocol extend-type extenders extends? false? ffirst file-seq filter filterv find find-keyword find-ns find-protocol-impl find-protocol-method find-var first flatten float float-array float? floats flush fn fn? fnext fnil for force format frequencies future future-call future-cancel future-cancelled? future-done? future? gen-class gen-interface gensym get get-in get-method get-proxy-class get-thread-bindings get-validator group-by hash hash-combine hash-map hash-set identical? identity if-let if-not ifn? import in-ns inc inc' init-proxy instance? int int-array integer? interleave intern interpose into into-array ints io! isa? iterate iterator-seq juxt keep keep-indexed key keys keyword keyword? last lazy-cat lazy-seq let letfn line-seq list list* list? load load-file load-reader load-string loaded-libs locking long long-array longs loop macroexpand macroexpand-1 make-array make-hierarchy map map-indexed map? mapcat mapv max max-key memfn memoize merge merge-with meta method-sig methods min min-key mod munge name namespace namespace-munge neg? newline next nfirst nil? nnext not not-any? not-empty not-every? not= ns ns-aliases ns-imports ns-interns ns-map ns-name ns-publics ns-refers ns-resolve ns-unalias ns-unmap nth nthnext nthrest num number? numerator object-array odd? or parents partial partition partition-all partition-by pcalls peek persistent! pmap pop pop! pop-thread-bindings pos? pr pr-str prefer-method prefers primitives-classnames print print-ctor print-dup print-method print-simple print-str printf println println-str prn prn-str promise proxy proxy-call-with-super proxy-mappings proxy-name proxy-super push-thread-bindings pvalues quot rand rand-int rand-nth range ratio? rational? rationalize re-find re-groups re-matcher re-matches re-pattern re-seq read read-line read-string realized? reduce reduce-kv reductions ref ref-history-count ref-max-history ref-min-history ref-set refer refer-clojure reify release-pending-sends rem remove remove-all-methods remove-method remove-ns remove-watch repeat repeatedly replace replicate require reset! reset-meta! resolve rest restart-agent resultset-seq reverse reversible? rseq rsubseq satisfies? second select-keys send send-off seq seq? seque sequence sequential? set set-error-handler! set-error-mode! set-validator! set? short short-array shorts shuffle shutdown-agents slurp some some-fn sort sort-by sorted-map sorted-map-by sorted-set sorted-set-by sorted? special-symbol? spit split-at split-with str string? struct struct-map subs subseq subvec supers swap! symbol symbol? sync take take-last take-nth take-while test the-ns thread-bound? time to-array to-array-2d trampoline transient tree-seq true? type unchecked-add unchecked-add-int unchecked-byte unchecked-char unchecked-dec unchecked-dec-int unchecked-divide-int unchecked-double unchecked-float unchecked-inc unchecked-inc-int unchecked-int unchecked-long unchecked-multiply unchecked-multiply-int unchecked-negate unchecked-negate-int unchecked-remainder-int unchecked-short unchecked-subtract unchecked-subtract-int underive unquote unquote-splicing update-in update-proxy use val vals var-get var-set var? vary-meta vec vector vector-of vector? when when-first when-let when-not while with-bindings with-bindings* with-in-str with-loading-context with-local-vars with-meta with-open with-out-str with-precision with-redefs with-redefs-fn xml-seq zero? zipmap *default-data-reader-fn* as-> cond-> cond->> reduced reduced? send-via set-agent-send-executor! set-agent-send-off-executor! some-> some->>");
38 |
39 | var indentKeys = makeKeywords(
40 | // Built-ins
41 | "ns fn def defn defmethod bound-fn if if-not case condp when while when-not when-first do future comment doto locking proxy with-open with-precision reify deftype defrecord defprotocol extend extend-protocol extend-type try catch " +
42 |
43 | // Binding forms
44 | "let letfn binding loop for doseq dotimes when-let if-let " +
45 |
46 | // Data structures
47 | "defstruct struct-map assoc " +
48 |
49 | // clojure.test
50 | "testing deftest " +
51 |
52 | // contrib
53 | "handler-case handle dotrace deftrace");
54 |
55 | var tests = {
56 | digit: /\d/,
57 | digit_or_colon: /[\d:]/,
58 | hex: /[0-9a-f]/i,
59 | sign: /[+-]/,
60 | exponent: /e/i,
61 | keyword_char: /[^\s\(\[\;\)\]]/,
62 | symbol: /[\w*+!\-\._?:<>\/\xa1-\uffff]/
63 | };
64 |
65 | function stateStack(indent, type, prev) { // represents a state stack object
66 | this.indent = indent;
67 | this.type = type;
68 | this.prev = prev;
69 | }
70 |
71 | function pushStack(state, indent, type) {
72 | state.indentStack = new stateStack(indent, type, state.indentStack);
73 | }
74 |
75 | function popStack(state) {
76 | state.indentStack = state.indentStack.prev;
77 | }
78 |
79 | function isNumber(ch, stream){
80 | // hex
81 | if ( ch === '0' && stream.eat(/x/i) ) {
82 | stream.eatWhile(tests.hex);
83 | return true;
84 | }
85 |
86 | // leading sign
87 | if ( ( ch == '+' || ch == '-' ) && ( tests.digit.test(stream.peek()) ) ) {
88 | stream.eat(tests.sign);
89 | ch = stream.next();
90 | }
91 |
92 | if ( tests.digit.test(ch) ) {
93 | stream.eat(ch);
94 | stream.eatWhile(tests.digit);
95 |
96 | if ( '.' == stream.peek() ) {
97 | stream.eat('.');
98 | stream.eatWhile(tests.digit);
99 | }
100 |
101 | if ( stream.eat(tests.exponent) ) {
102 | stream.eat(tests.sign);
103 | stream.eatWhile(tests.digit);
104 | }
105 |
106 | return true;
107 | }
108 |
109 | return false;
110 | }
111 |
112 | // Eat character that starts after backslash \
113 | function eatCharacter(stream) {
114 | var first = stream.next();
115 | // Read special literals: backspace, newline, space, return.
116 | // Just read all lowercase letters.
117 | if (first && first.match(/[a-z]/) && stream.match(/[a-z]+/, true)) {
118 | return;
119 | }
120 | // Read unicode character: \u1000 \uA0a1
121 | if (first === "u") {
122 | stream.match(/[0-9a-z]{4}/i, true);
123 | }
124 | }
125 |
126 | return {
127 | startState: function () {
128 | return {
129 | indentStack: null,
130 | indentation: 0,
131 | mode: false
132 | };
133 | },
134 |
135 | token: function (stream, state) {
136 | if (state.indentStack == null && stream.sol()) {
137 | // update indentation, but only if indentStack is empty
138 | state.indentation = stream.indentation();
139 | }
140 |
141 | // skip spaces
142 | if (stream.eatSpace()) {
143 | return null;
144 | }
145 | var returnType = null;
146 |
147 | switch(state.mode){
148 | case "string": // multi-line string parsing mode
149 | var next, escaped = false;
150 | while ((next = stream.next()) != null) {
151 | if (next == "\"" && !escaped) {
152 |
153 | state.mode = false;
154 | break;
155 | }
156 | escaped = !escaped && next == "\\";
157 | }
158 | returnType = STRING; // continue on in string mode
159 | break;
160 | default: // default parsing mode
161 | var ch = stream.next();
162 |
163 | if (ch == "\"") {
164 | state.mode = "string";
165 | returnType = STRING;
166 | } else if (ch == "\\") {
167 | eatCharacter(stream);
168 | returnType = CHARACTER;
169 | } else if (ch == "'" && !( tests.digit_or_colon.test(stream.peek()) )) {
170 | returnType = ATOM;
171 | } else if (ch == ";") { // comment
172 | stream.skipToEnd(); // rest of the line is a comment
173 | returnType = COMMENT;
174 | } else if (isNumber(ch,stream)){
175 | returnType = NUMBER;
176 | } else if (ch == "(" || ch == "[" || ch == "{" ) {
177 | var keyWord = '', indentTemp = stream.column(), letter;
178 | /**
179 | Either
180 | (indent-word ..
181 | (non-indent-word ..
182 | (;something else, bracket, etc.
183 | */
184 |
185 | if (ch == "(") while ((letter = stream.eat(tests.keyword_char)) != null) {
186 | keyWord += letter;
187 | }
188 |
189 | if (keyWord.length > 0 && (indentKeys.propertyIsEnumerable(keyWord) ||
190 | /^(?:def|with)/.test(keyWord))) { // indent-word
191 | pushStack(state, indentTemp + INDENT_WORD_SKIP, ch);
192 | } else { // non-indent word
193 | // we continue eating the spaces
194 | stream.eatSpace();
195 | if (stream.eol() || stream.peek() == ";") {
196 | // nothing significant after
197 | // we restart indentation the user defined spaces after
198 | pushStack(state, indentTemp + NORMAL_INDENT_UNIT, ch);
199 | } else {
200 | pushStack(state, indentTemp + stream.current().length, ch); // else we match
201 | }
202 | }
203 | stream.backUp(stream.current().length - 1); // undo all the eating
204 |
205 | returnType = BRACKET;
206 | } else if (ch == ")" || ch == "]" || ch == "}") {
207 | returnType = BRACKET;
208 | if (state.indentStack != null && state.indentStack.type == (ch == ")" ? "(" : (ch == "]" ? "[" :"{"))) {
209 | popStack(state);
210 | }
211 | } else if ( ch == ":" ) {
212 | stream.eatWhile(tests.symbol);
213 | return ATOM;
214 | } else {
215 | stream.eatWhile(tests.symbol);
216 |
217 | if (keywords && keywords.propertyIsEnumerable(stream.current())) {
218 | returnType = KEYWORD;
219 | } else if (builtins && builtins.propertyIsEnumerable(stream.current())) {
220 | returnType = BUILTIN;
221 | } else if (atoms && atoms.propertyIsEnumerable(stream.current())) {
222 | returnType = ATOM;
223 | } else {
224 | returnType = VAR;
225 | }
226 | }
227 | }
228 |
229 | return returnType;
230 | },
231 |
232 | indent: function (state) {
233 | if (state.indentStack == null) return state.indentation;
234 | return state.indentStack.indent;
235 | },
236 |
237 | closeBrackets: {pairs: "()[]{}\"\""},
238 | lineComment: ";;"
239 | };
240 | });
241 |
242 | CodeMirror.defineMIME("text/x-clojure", "clojure");
243 |
244 | });
245 |
--------------------------------------------------------------------------------
/js/vendor/threejs/collada-loader.js:
--------------------------------------------------------------------------------
1 | /**
2 | * @author Tim Knip / http://www.floorplanner.com/ / tim at floorplanner.com
3 | * @author Tony Parisi / http://www.tonyparisi.com/
4 | */
5 |
6 | THREE.ColladaLoader = function () {
7 |
8 | var COLLADA = null;
9 | var scene = null;
10 | var visualScene;
11 | var kinematicsModel;
12 |
13 | var readyCallbackFunc = null;
14 |
15 | var sources = {};
16 | var images = {};
17 | var animations = {};
18 | var controllers = {};
19 | var geometries = {};
20 | var materials = {};
21 | var effects = {};
22 | var cameras = {};
23 | var lights = {};
24 |
25 | var animData;
26 | var kinematics;
27 | var visualScenes;
28 | var kinematicsModels;
29 | var baseUrl;
30 | var morphs;
31 | var skins;
32 |
33 | var flip_uv = true;
34 | var preferredShading = THREE.SmoothShading;
35 |
36 | var options = {
37 | // Force Geometry to always be centered at the local origin of the
38 | // containing Mesh.
39 | centerGeometry: false,
40 |
41 | // Axis conversion is done for geometries, animations, and controllers.
42 | // If we ever pull cameras or lights out of the COLLADA file, they'll
43 | // need extra work.
44 | convertUpAxis: false,
45 |
46 | subdivideFaces: true,
47 |
48 | upAxis: 'Y',
49 |
50 | // For reflective or refractive materials we'll use this cubemap
51 | defaultEnvMap: null
52 |
53 | };
54 |
55 | var colladaUnit = 1.0;
56 | var colladaUp = 'Y';
57 | var upConversion = null;
58 |
59 | function load ( url, readyCallback, progressCallback, failCallback ) {
60 |
61 | var length = 0;
62 |
63 | if ( document.implementation && document.implementation.createDocument ) {
64 |
65 | var request = new XMLHttpRequest();
66 |
67 | request.onreadystatechange = function() {
68 |
69 | if ( request.readyState === 4 ) {
70 |
71 | if ( request.status === 0 || request.status === 200 ) {
72 |
73 |
74 | if ( request.responseXML ) {
75 |
76 | readyCallbackFunc = readyCallback;
77 | parse( request.responseXML, undefined, url );
78 |
79 | } else if ( request.responseText ) {
80 |
81 | readyCallbackFunc = readyCallback;
82 | var xmlParser = new DOMParser();
83 | var responseXML = xmlParser.parseFromString( request.responseText, "application/xml" );
84 | parse( responseXML, undefined, url );
85 |
86 | } else {
87 |
88 | if ( faillCallback ) {
89 |
90 | failCallback();
91 |
92 | } else {
93 |
94 | console.error( "ColladaLoader: Empty or non-existing file (" + url + ")" );
95 |
96 | }
97 |
98 | }
99 |
100 | }
101 |
102 | } else if ( request.readyState === 3 ) {
103 |
104 | if ( progressCallback ) {
105 |
106 | if ( length === 0 ) {
107 |
108 | length = request.getResponseHeader( "Content-Length" );
109 |
110 | }
111 |
112 | progressCallback( { total: length, loaded: request.responseText.length } );
113 |
114 | }
115 |
116 | }
117 |
118 | }
119 |
120 | request.open( "GET", url, true );
121 | request.send( null );
122 |
123 | } else {
124 |
125 | alert( "Don't know how to parse XML!" );
126 |
127 | }
128 |
129 | }
130 |
131 | function parse( doc, callBack, url ) {
132 |
133 | COLLADA = doc;
134 | callBack = callBack || readyCallbackFunc;
135 |
136 | if ( url !== undefined ) {
137 |
138 | var parts = url.split( '/' );
139 | parts.pop();
140 | baseUrl = ( parts.length < 1 ? '.' : parts.join( '/' ) ) + '/';
141 |
142 | }
143 |
144 | parseAsset();
145 | setUpConversion();
146 | images = parseLib( "library_images image", _Image, "image" );
147 | materials = parseLib( "library_materials material", Material, "material" );
148 | effects = parseLib( "library_effects effect", Effect, "effect" );
149 | geometries = parseLib( "library_geometries geometry", Geometry, "geometry" );
150 | cameras = parseLib( "library_cameras camera", Camera, "camera" );
151 | lights = parseLib( "library_lights light", Light, "light" );
152 | controllers = parseLib( "library_controllers controller", Controller, "controller" );
153 | animations = parseLib( "library_animations animation", Animation, "animation" );
154 | visualScenes = parseLib( "library_visual_scenes visual_scene", VisualScene, "visual_scene" );
155 | kinematicsModels = parseLib( "library_kinematics_models kinematics_model", KinematicsModel, "kinematics_model" );
156 |
157 | morphs = [];
158 | skins = [];
159 |
160 | visualScene = parseScene();
161 | scene = new THREE.Group();
162 |
163 | for ( var i = 0; i < visualScene.nodes.length; i ++ ) {
164 |
165 | scene.add( createSceneGraph( visualScene.nodes[ i ] ) );
166 |
167 | }
168 |
169 | // unit conversion
170 | scene.scale.multiplyScalar( colladaUnit );
171 |
172 | createAnimations();
173 |
174 | kinematicsModel = parseKinematicsModel();
175 | createKinematics();
176 |
177 | var result = {
178 |
179 | scene: scene,
180 | morphs: morphs,
181 | skins: skins,
182 | animations: animData,
183 | kinematics: kinematics,
184 | dae: {
185 | images: images,
186 | materials: materials,
187 | cameras: cameras,
188 | lights: lights,
189 | effects: effects,
190 | geometries: geometries,
191 | controllers: controllers,
192 | animations: animations,
193 | visualScenes: visualScenes,
194 | visualScene: visualScene,
195 | scene: visualScene,
196 | kinematicsModels: kinematicsModels,
197 | kinematicsModel: kinematicsModel
198 | }
199 |
200 | };
201 |
202 | if ( callBack ) {
203 |
204 | callBack( result );
205 |
206 | }
207 |
208 | return result;
209 |
210 | }
211 |
212 | function setPreferredShading ( shading ) {
213 |
214 | preferredShading = shading;
215 |
216 | }
217 |
218 | function parseAsset () {
219 |
220 | var elements = COLLADA.querySelectorAll('asset');
221 |
222 | var element = elements[0];
223 |
224 | if ( element && element.childNodes ) {
225 |
226 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
227 |
228 | var child = element.childNodes[ i ];
229 |
230 | switch ( child.nodeName ) {
231 |
232 | case 'unit':
233 |
234 | var meter = child.getAttribute( 'meter' );
235 |
236 | if ( meter ) {
237 |
238 | colladaUnit = parseFloat( meter );
239 |
240 | }
241 |
242 | break;
243 |
244 | case 'up_axis':
245 |
246 | colladaUp = child.textContent.charAt(0);
247 | break;
248 |
249 | }
250 |
251 | }
252 |
253 | }
254 |
255 | }
256 |
257 | function parseLib ( q, classSpec, prefix ) {
258 |
259 | var elements = COLLADA.querySelectorAll(q);
260 |
261 | var lib = {};
262 |
263 | var i = 0;
264 |
265 | var elementsLength = elements.length;
266 |
267 | for ( var j = 0; j < elementsLength; j ++ ) {
268 |
269 | var element = elements[j];
270 | var daeElement = ( new classSpec() ).parse( element );
271 |
272 | if ( !daeElement.id || daeElement.id.length === 0 ) daeElement.id = prefix + ( i ++ );
273 | lib[ daeElement.id ] = daeElement;
274 |
275 | }
276 |
277 | return lib;
278 |
279 | }
280 |
281 | function parseScene() {
282 |
283 | var sceneElement = COLLADA.querySelectorAll('scene instance_visual_scene')[0];
284 |
285 | if ( sceneElement ) {
286 |
287 | var url = sceneElement.getAttribute( 'url' ).replace( /^#/, '' );
288 | return visualScenes[ url.length > 0 ? url : 'visual_scene0' ];
289 |
290 | } else {
291 |
292 | return null;
293 |
294 | }
295 |
296 | }
297 |
298 | function parseKinematicsModel() {
299 |
300 | var kinematicsModelElement = COLLADA.querySelectorAll('instance_kinematics_model')[0];
301 |
302 | if ( kinematicsModelElement ) {
303 |
304 | var url = kinematicsModelElement.getAttribute( 'url' ).replace(/^#/, '');
305 | return kinematicsModels[ url.length > 0 ? url : 'kinematics_model0' ];
306 |
307 | } else {
308 |
309 | return null;
310 |
311 | }
312 |
313 | }
314 |
315 | function createAnimations() {
316 |
317 | animData = [];
318 |
319 | // fill in the keys
320 | recurseHierarchy( scene );
321 |
322 | }
323 |
324 | function recurseHierarchy( node ) {
325 |
326 | var n = visualScene.getChildById( node.colladaId, true ),
327 | newData = null;
328 |
329 | if ( n && n.keys ) {
330 |
331 | newData = {
332 | fps: 60,
333 | hierarchy: [ {
334 | node: n,
335 | keys: n.keys,
336 | sids: n.sids
337 | } ],
338 | node: node,
339 | name: 'animation_' + node.name,
340 | length: 0
341 | };
342 |
343 | animData.push(newData);
344 |
345 | for ( var i = 0, il = n.keys.length; i < il; i ++ ) {
346 |
347 | newData.length = Math.max( newData.length, n.keys[i].time );
348 |
349 | }
350 |
351 | } else {
352 |
353 | newData = {
354 | hierarchy: [ {
355 | keys: [],
356 | sids: []
357 | } ]
358 | }
359 |
360 | }
361 |
362 | for ( var i = 0, il = node.children.length; i < il; i ++ ) {
363 |
364 | var d = recurseHierarchy( node.children[i] );
365 |
366 | for ( var j = 0, jl = d.hierarchy.length; j < jl; j ++ ) {
367 |
368 | newData.hierarchy.push( {
369 | keys: [],
370 | sids: []
371 | } );
372 |
373 | }
374 |
375 | }
376 |
377 | return newData;
378 |
379 | }
380 |
381 | function calcAnimationBounds () {
382 |
383 | var start = 1000000;
384 | var end = -start;
385 | var frames = 0;
386 | var ID;
387 | for ( var id in animations ) {
388 |
389 | var animation = animations[ id ];
390 | ID = ID || animation.id;
391 | for ( var i = 0; i < animation.sampler.length; i ++ ) {
392 |
393 | var sampler = animation.sampler[ i ];
394 |
395 | sampler.create();
396 |
397 | start = Math.min( start, sampler.startTime );
398 | end = Math.max( end, sampler.endTime );
399 | frames = Math.max( frames, sampler.input.length );
400 |
401 | }
402 |
403 | }
404 |
405 | return { start:start, end:end, frames:frames,ID:ID };
406 |
407 | }
408 |
409 | function createMorph ( geometry, ctrl ) {
410 |
411 | var morphCtrl = ctrl instanceof InstanceController ? controllers[ ctrl.url ] : ctrl;
412 |
413 | if ( !morphCtrl || !morphCtrl.morph ) {
414 |
415 | console.log("could not find morph controller!");
416 | return;
417 |
418 | }
419 |
420 | var morph = morphCtrl.morph;
421 |
422 | for ( var i = 0; i < morph.targets.length; i ++ ) {
423 |
424 | var target_id = morph.targets[ i ];
425 | var daeGeometry = geometries[ target_id ];
426 |
427 | if ( !daeGeometry.mesh ||
428 | !daeGeometry.mesh.primitives ||
429 | !daeGeometry.mesh.primitives.length ) {
430 | continue;
431 | }
432 |
433 | var target = daeGeometry.mesh.primitives[ 0 ].geometry;
434 |
435 | if ( target.vertices.length === geometry.vertices.length ) {
436 |
437 | geometry.morphTargets.push( { name: "target_1", vertices: target.vertices } );
438 |
439 | }
440 |
441 | }
442 |
443 | geometry.morphTargets.push( { name: "target_Z", vertices: geometry.vertices } );
444 |
445 | };
446 |
447 | function createSkin ( geometry, ctrl, applyBindShape ) {
448 |
449 | var skinCtrl = controllers[ ctrl.url ];
450 |
451 | if ( !skinCtrl || !skinCtrl.skin ) {
452 |
453 | console.log( "could not find skin controller!" );
454 | return;
455 |
456 | }
457 |
458 | if ( !ctrl.skeleton || !ctrl.skeleton.length ) {
459 |
460 | console.log( "could not find the skeleton for the skin!" );
461 | return;
462 |
463 | }
464 |
465 | var skin = skinCtrl.skin;
466 | var skeleton = visualScene.getChildById( ctrl.skeleton[ 0 ] );
467 | var hierarchy = [];
468 |
469 | applyBindShape = applyBindShape !== undefined ? applyBindShape : true;
470 |
471 | var bones = [];
472 | geometry.skinWeights = [];
473 | geometry.skinIndices = [];
474 |
475 | //createBones( geometry.bones, skin, hierarchy, skeleton, null, -1 );
476 | //createWeights( skin, geometry.bones, geometry.skinIndices, geometry.skinWeights );
477 |
478 | /*
479 | geometry.animation = {
480 | name: 'take_001',
481 | fps: 30,
482 | length: 2,
483 | JIT: true,
484 | hierarchy: hierarchy
485 | };
486 | */
487 |
488 | if ( applyBindShape ) {
489 |
490 | for ( var i = 0; i < geometry.vertices.length; i ++ ) {
491 |
492 | geometry.vertices[ i ].applyMatrix4( skin.bindShapeMatrix );
493 |
494 | }
495 |
496 | }
497 |
498 | }
499 |
500 | function setupSkeleton ( node, bones, frame, parent ) {
501 |
502 | node.world = node.world || new THREE.Matrix4();
503 | node.localworld = node.localworld || new THREE.Matrix4();
504 | node.world.copy( node.matrix );
505 | node.localworld.copy( node.matrix );
506 |
507 | if ( node.channels && node.channels.length ) {
508 |
509 | var channel = node.channels[ 0 ];
510 | var m = channel.sampler.output[ frame ];
511 |
512 | if ( m instanceof THREE.Matrix4 ) {
513 |
514 | node.world.copy( m );
515 | node.localworld.copy(m);
516 | if (frame === 0)
517 | node.matrix.copy(m);
518 | }
519 |
520 | }
521 |
522 | if ( parent ) {
523 |
524 | node.world.multiplyMatrices( parent, node.world );
525 |
526 | }
527 |
528 | bones.push( node );
529 |
530 | for ( var i = 0; i < node.nodes.length; i ++ ) {
531 |
532 | setupSkeleton( node.nodes[ i ], bones, frame, node.world );
533 |
534 | }
535 |
536 | }
537 |
538 | function setupSkinningMatrices ( bones, skin ) {
539 |
540 | // FIXME: this is dumb...
541 |
542 | for ( var i = 0; i < bones.length; i ++ ) {
543 |
544 | var bone = bones[ i ];
545 | var found = -1;
546 |
547 | if ( bone.type != 'JOINT' ) continue;
548 |
549 | for ( var j = 0; j < skin.joints.length; j ++ ) {
550 |
551 | if ( bone.sid === skin.joints[ j ] ) {
552 |
553 | found = j;
554 | break;
555 |
556 | }
557 |
558 | }
559 |
560 | if ( found >= 0 ) {
561 |
562 | var inv = skin.invBindMatrices[ found ];
563 |
564 | bone.invBindMatrix = inv;
565 | bone.skinningMatrix = new THREE.Matrix4();
566 | bone.skinningMatrix.multiplyMatrices(bone.world, inv); // (IBMi * JMi)
567 | bone.animatrix = new THREE.Matrix4();
568 |
569 | bone.animatrix.copy(bone.localworld);
570 | bone.weights = [];
571 |
572 | for ( var j = 0; j < skin.weights.length; j ++ ) {
573 |
574 | for (var k = 0; k < skin.weights[ j ].length; k ++ ) {
575 |
576 | var w = skin.weights[ j ][ k ];
577 |
578 | if ( w.joint === found ) {
579 |
580 | bone.weights.push( w );
581 |
582 | }
583 |
584 | }
585 |
586 | }
587 |
588 | } else {
589 |
590 | console.warn( "ColladaLoader: Could not find joint '" + bone.sid + "'." );
591 |
592 | bone.skinningMatrix = new THREE.Matrix4();
593 | bone.weights = [];
594 |
595 | }
596 | }
597 |
598 | }
599 |
600 | //Walk the Collada tree and flatten the bones into a list, extract the position, quat and scale from the matrix
601 | function flattenSkeleton(skeleton) {
602 |
603 | var list = [];
604 | var walk = function(parentid, node, list) {
605 |
606 | var bone = {};
607 | bone.name = node.sid;
608 | bone.parent = parentid;
609 | bone.matrix = node.matrix;
610 | var data = [ new THREE.Vector3(),new THREE.Quaternion(),new THREE.Vector3() ];
611 | bone.matrix.decompose(data[0], data[1], data[2]);
612 |
613 | bone.pos = [ data[0].x,data[0].y,data[0].z ];
614 |
615 | bone.scl = [ data[2].x,data[2].y,data[2].z ];
616 | bone.rotq = [ data[1].x,data[1].y,data[1].z,data[1].w ];
617 | list.push(bone);
618 |
619 | for (var i in node.nodes) {
620 |
621 | walk(node.sid, node.nodes[i], list);
622 |
623 | }
624 |
625 | };
626 |
627 | walk(-1, skeleton, list);
628 | return list;
629 |
630 | }
631 |
632 | //Move the vertices into the pose that is proper for the start of the animation
633 | function skinToBindPose(geometry,skeleton,skinController) {
634 |
635 | var bones = [];
636 | setupSkeleton( skeleton, bones, -1 );
637 | setupSkinningMatrices( bones, skinController.skin );
638 | v = new THREE.Vector3();
639 | var skinned = [];
640 |
641 | for (var i = 0; i < geometry.vertices.length; i ++) {
642 |
643 | skinned.push(new THREE.Vector3());
644 |
645 | }
646 |
647 | for ( i = 0; i < bones.length; i ++ ) {
648 |
649 | if ( bones[ i ].type != 'JOINT' ) continue;
650 |
651 | for ( j = 0; j < bones[ i ].weights.length; j ++ ) {
652 |
653 | w = bones[ i ].weights[ j ];
654 | vidx = w.index;
655 | weight = w.weight;
656 |
657 | o = geometry.vertices[vidx];
658 | s = skinned[vidx];
659 |
660 | v.x = o.x;
661 | v.y = o.y;
662 | v.z = o.z;
663 |
664 | v.applyMatrix4( bones[i].skinningMatrix );
665 |
666 | s.x += (v.x * weight);
667 | s.y += (v.y * weight);
668 | s.z += (v.z * weight);
669 | }
670 |
671 | }
672 |
673 | for (var i = 0; i < geometry.vertices.length; i ++) {
674 |
675 | geometry.vertices[i] = skinned[i];
676 |
677 | }
678 |
679 | }
680 |
681 | function applySkin ( geometry, instanceCtrl, frame ) {
682 |
683 | var skinController = controllers[ instanceCtrl.url ];
684 |
685 | frame = frame !== undefined ? frame : 40;
686 |
687 | if ( !skinController || !skinController.skin ) {
688 |
689 | console.log( 'ColladaLoader: Could not find skin controller.' );
690 | return;
691 |
692 | }
693 |
694 | if ( !instanceCtrl.skeleton || !instanceCtrl.skeleton.length ) {
695 |
696 | console.log( 'ColladaLoader: Could not find the skeleton for the skin. ' );
697 | return;
698 |
699 | }
700 |
701 | var animationBounds = calcAnimationBounds();
702 | var skeleton = visualScene.getChildById( instanceCtrl.skeleton[0], true ) || visualScene.getChildBySid( instanceCtrl.skeleton[0], true );
703 |
704 | //flatten the skeleton into a list of bones
705 | var bonelist = flattenSkeleton(skeleton);
706 | var joints = skinController.skin.joints;
707 |
708 | //sort that list so that the order reflects the order in the joint list
709 | var sortedbones = [];
710 | for (var i = 0; i < joints.length; i ++) {
711 |
712 | for (var j = 0; j < bonelist.length; j ++) {
713 |
714 | if (bonelist[j].name === joints[i]) {
715 |
716 | sortedbones[i] = bonelist[j];
717 |
718 | }
719 |
720 | }
721 |
722 | }
723 |
724 | //hook up the parents by index instead of name
725 | for (var i = 0; i < sortedbones.length; i ++) {
726 |
727 | for (var j = 0; j < sortedbones.length; j ++) {
728 |
729 | if (sortedbones[i].parent === sortedbones[j].name) {
730 |
731 | sortedbones[i].parent = j;
732 |
733 | }
734 |
735 | }
736 |
737 | }
738 |
739 |
740 | var i, j, w, vidx, weight;
741 | var v = new THREE.Vector3(), o, s;
742 |
743 | // move vertices to bind shape
744 | for ( i = 0; i < geometry.vertices.length; i ++ ) {
745 | geometry.vertices[i].applyMatrix4( skinController.skin.bindShapeMatrix );
746 | }
747 |
748 | var skinIndices = [];
749 | var skinWeights = [];
750 | var weights = skinController.skin.weights;
751 |
752 | // hook up the skin weights
753 | // TODO - this might be a good place to choose greatest 4 weights
754 | for ( var i =0; i < weights.length; i ++ ) {
755 |
756 | var indicies = new THREE.Vector4(weights[i][0] ? weights[i][0].joint : 0,weights[i][1] ? weights[i][1].joint : 0,weights[i][2] ? weights[i][2].joint : 0,weights[i][3] ? weights[i][3].joint : 0);
757 | var weight = new THREE.Vector4(weights[i][0] ? weights[i][0].weight : 0,weights[i][1] ? weights[i][1].weight : 0,weights[i][2] ? weights[i][2].weight : 0,weights[i][3] ? weights[i][3].weight : 0);
758 |
759 | skinIndices.push(indicies);
760 | skinWeights.push(weight);
761 |
762 | }
763 |
764 | geometry.skinIndices = skinIndices;
765 | geometry.skinWeights = skinWeights;
766 | geometry.bones = sortedbones;
767 | // process animation, or simply pose the rig if no animation
768 |
769 | //create an animation for the animated bones
770 | //NOTE: this has no effect when using morphtargets
771 | var animationdata = { "name":animationBounds.ID,"fps":30,"length":animationBounds.frames / 30,"hierarchy":[] };
772 |
773 | for (var j = 0; j < sortedbones.length; j ++) {
774 |
775 | animationdata.hierarchy.push({ parent:sortedbones[j].parent, name:sortedbones[j].name, keys:[] });
776 |
777 | }
778 |
779 | console.log( 'ColladaLoader:', animationBounds.ID + ' has ' + sortedbones.length + ' bones.' );
780 |
781 |
782 |
783 | skinToBindPose(geometry, skeleton, skinController);
784 |
785 |
786 | for ( frame = 0; frame < animationBounds.frames; frame ++ ) {
787 |
788 | var bones = [];
789 | var skinned = [];
790 | // process the frame and setup the rig with a fresh
791 | // transform, possibly from the bone's animation channel(s)
792 |
793 | setupSkeleton( skeleton, bones, frame );
794 | setupSkinningMatrices( bones, skinController.skin );
795 |
796 | for (var i = 0; i < bones.length; i ++) {
797 |
798 | for (var j = 0; j < animationdata.hierarchy.length; j ++) {
799 |
800 | if (animationdata.hierarchy[j].name === bones[i].sid) {
801 |
802 | var key = {};
803 | key.time = (frame / 30);
804 | key.matrix = bones[i].animatrix;
805 |
806 | if (frame === 0)
807 | bones[i].matrix = key.matrix;
808 |
809 | var data = [ new THREE.Vector3(),new THREE.Quaternion(),new THREE.Vector3() ];
810 | key.matrix.decompose(data[0], data[1], data[2]);
811 |
812 | key.pos = [ data[0].x,data[0].y,data[0].z ];
813 |
814 | key.scl = [ data[2].x,data[2].y,data[2].z ];
815 | key.rot = data[1];
816 |
817 | animationdata.hierarchy[j].keys.push(key);
818 |
819 | }
820 |
821 | }
822 |
823 | }
824 |
825 | geometry.animation = animationdata;
826 |
827 | }
828 |
829 | };
830 |
831 | function createKinematics() {
832 |
833 | if ( kinematicsModel && kinematicsModel.joints.length === 0 ) {
834 | kinematics = undefined;
835 | return;
836 | }
837 |
838 | var jointMap = {};
839 |
840 | var _addToMap = function( jointIndex, parentVisualElement ) {
841 |
842 | var parentVisualElementId = parentVisualElement.getAttribute( 'id' );
843 | var colladaNode = visualScene.getChildById( parentVisualElementId, true );
844 | var joint = kinematicsModel.joints[ jointIndex ];
845 |
846 | scene.traverse(function( node ) {
847 |
848 | if ( node.colladaId == parentVisualElementId ) {
849 |
850 | jointMap[ jointIndex ] = {
851 | node: node,
852 | transforms: colladaNode.transforms,
853 | joint: joint,
854 | position: joint.zeroPosition
855 | };
856 |
857 | }
858 |
859 | });
860 |
861 | };
862 |
863 | kinematics = {
864 |
865 | joints: kinematicsModel && kinematicsModel.joints,
866 |
867 | getJointValue: function( jointIndex ) {
868 |
869 | var jointData = jointMap[ jointIndex ];
870 |
871 | if ( jointData ) {
872 |
873 | return jointData.position;
874 |
875 | } else {
876 |
877 | console.log( 'getJointValue: joint ' + jointIndex + ' doesn\'t exist' );
878 |
879 | }
880 |
881 | },
882 |
883 | setJointValue: function( jointIndex, value ) {
884 |
885 | var jointData = jointMap[ jointIndex ];
886 |
887 | if ( jointData ) {
888 |
889 | var joint = jointData.joint;
890 |
891 | if ( value > joint.limits.max || value < joint.limits.min ) {
892 |
893 | console.log( 'setJointValue: joint ' + jointIndex + ' value ' + value + ' outside of limits (min: ' + joint.limits.min + ', max: ' + joint.limits.max + ')' );
894 |
895 | } else if ( joint.static ) {
896 |
897 | console.log( 'setJointValue: joint ' + jointIndex + ' is static' );
898 |
899 | } else {
900 |
901 | var threejsNode = jointData.node;
902 | var axis = joint.axis;
903 | var transforms = jointData.transforms;
904 |
905 | var matrix = new THREE.Matrix4();
906 |
907 | for (i = 0; i < transforms.length; i ++ ) {
908 |
909 | var transform = transforms[ i ];
910 |
911 | // kinda ghetto joint detection
912 | if ( transform.sid && transform.sid.indexOf( 'joint' + jointIndex ) !== -1 ) {
913 |
914 | // apply actual joint value here
915 | switch ( joint.type ) {
916 |
917 | case 'revolute':
918 |
919 | matrix.multiply( m1.makeRotationAxis( axis, THREE.Math.degToRad(value) ) );
920 | break;
921 |
922 | case 'prismatic':
923 |
924 | matrix.multiply( m1.makeTranslation(axis.x * value, axis.y * value, axis.z * value ) );
925 | break;
926 |
927 | default:
928 |
929 | console.warn( 'setJointValue: unknown joint type: ' + joint.type );
930 | break;
931 |
932 | }
933 |
934 | } else {
935 |
936 | var m1 = new THREE.Matrix4();
937 |
938 | switch ( transform.type ) {
939 |
940 | case 'matrix':
941 |
942 | matrix.multiply( transform.obj );
943 |
944 | break;
945 |
946 | case 'translate':
947 |
948 | matrix.multiply( m1.makeTranslation( transform.obj.x, transform.obj.y, transform.obj.z ) );
949 |
950 | break;
951 |
952 | case 'rotate':
953 |
954 | matrix.multiply( m1.makeRotationAxis( transform.obj, transform.angle ) );
955 |
956 | break;
957 |
958 | }
959 | }
960 | }
961 |
962 | // apply the matrix to the threejs node
963 | var elementsFloat32Arr = matrix.elements;
964 | var elements = Array.prototype.slice.call( elementsFloat32Arr );
965 |
966 | var elementsRowMajor = [
967 | elements[ 0 ],
968 | elements[ 4 ],
969 | elements[ 8 ],
970 | elements[ 12 ],
971 | elements[ 1 ],
972 | elements[ 5 ],
973 | elements[ 9 ],
974 | elements[ 13 ],
975 | elements[ 2 ],
976 | elements[ 6 ],
977 | elements[ 10 ],
978 | elements[ 14 ],
979 | elements[ 3 ],
980 | elements[ 7 ],
981 | elements[ 11 ],
982 | elements[ 15 ]
983 | ];
984 |
985 | threejsNode.matrix.set.apply( threejsNode.matrix, elementsRowMajor );
986 | threejsNode.matrix.decompose( threejsNode.position, threejsNode.quaternion, threejsNode.scale );
987 | }
988 |
989 | } else {
990 |
991 | console.log( 'setJointValue: joint ' + jointIndex + ' doesn\'t exist' );
992 |
993 | }
994 |
995 | }
996 |
997 | };
998 |
999 | var element = COLLADA.querySelector('scene instance_kinematics_scene');
1000 |
1001 | if ( element ) {
1002 |
1003 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1004 |
1005 | var child = element.childNodes[ i ];
1006 |
1007 | if ( child.nodeType != 1 ) continue;
1008 |
1009 | switch ( child.nodeName ) {
1010 |
1011 | case 'bind_joint_axis':
1012 |
1013 | var visualTarget = child.getAttribute( 'target' ).split( '/' ).pop();
1014 | var axis = child.querySelector('axis param').textContent;
1015 | var jointIndex = parseInt( axis.split( 'joint' ).pop().split( '.' )[0] );
1016 | var visualTargetElement = COLLADA.querySelector( '[sid="' + visualTarget + '"]' );
1017 |
1018 | if ( visualTargetElement ) {
1019 | var parentVisualElement = visualTargetElement.parentElement;
1020 | _addToMap(jointIndex, parentVisualElement);
1021 | }
1022 |
1023 | break;
1024 |
1025 | default:
1026 |
1027 | break;
1028 |
1029 | }
1030 |
1031 | }
1032 | }
1033 |
1034 | };
1035 |
1036 | function createSceneGraph ( node, parent ) {
1037 |
1038 | var obj = new THREE.Object3D();
1039 | var skinned = false;
1040 | var skinController;
1041 | var morphController;
1042 | var i, j;
1043 |
1044 | // FIXME: controllers
1045 |
1046 | for ( i = 0; i < node.controllers.length; i ++ ) {
1047 |
1048 | var controller = controllers[ node.controllers[ i ].url ];
1049 |
1050 | switch ( controller.type ) {
1051 |
1052 | case 'skin':
1053 |
1054 | if ( geometries[ controller.skin.source ] ) {
1055 |
1056 | var inst_geom = new InstanceGeometry();
1057 |
1058 | inst_geom.url = controller.skin.source;
1059 | inst_geom.instance_material = node.controllers[ i ].instance_material;
1060 |
1061 | node.geometries.push( inst_geom );
1062 | skinned = true;
1063 | skinController = node.controllers[ i ];
1064 |
1065 | } else if ( controllers[ controller.skin.source ] ) {
1066 |
1067 | // urgh: controller can be chained
1068 | // handle the most basic case...
1069 |
1070 | var second = controllers[ controller.skin.source ];
1071 | morphController = second;
1072 | // skinController = node.controllers[i];
1073 |
1074 | if ( second.morph && geometries[ second.morph.source ] ) {
1075 |
1076 | var inst_geom = new InstanceGeometry();
1077 |
1078 | inst_geom.url = second.morph.source;
1079 | inst_geom.instance_material = node.controllers[ i ].instance_material;
1080 |
1081 | node.geometries.push( inst_geom );
1082 |
1083 | }
1084 |
1085 | }
1086 |
1087 | break;
1088 |
1089 | case 'morph':
1090 |
1091 | if ( geometries[ controller.morph.source ] ) {
1092 |
1093 | var inst_geom = new InstanceGeometry();
1094 |
1095 | inst_geom.url = controller.morph.source;
1096 | inst_geom.instance_material = node.controllers[ i ].instance_material;
1097 |
1098 | node.geometries.push( inst_geom );
1099 | morphController = node.controllers[ i ];
1100 |
1101 | }
1102 |
1103 | console.log( 'ColladaLoader: Morph-controller partially supported.' );
1104 |
1105 | default:
1106 | break;
1107 |
1108 | }
1109 |
1110 | }
1111 |
1112 | // geometries
1113 |
1114 | var double_sided_materials = {};
1115 |
1116 | for ( i = 0; i < node.geometries.length; i ++ ) {
1117 |
1118 | var instance_geometry = node.geometries[i];
1119 | var instance_materials = instance_geometry.instance_material;
1120 | var geometry = geometries[ instance_geometry.url ];
1121 | var used_materials = {};
1122 | var used_materials_array = [];
1123 | var num_materials = 0;
1124 | var first_material;
1125 |
1126 | if ( geometry ) {
1127 |
1128 | if ( !geometry.mesh || !geometry.mesh.primitives )
1129 | continue;
1130 |
1131 | if ( obj.name.length === 0 ) {
1132 |
1133 | obj.name = geometry.id;
1134 |
1135 | }
1136 |
1137 | // collect used fx for this geometry-instance
1138 |
1139 | if ( instance_materials ) {
1140 |
1141 | for ( j = 0; j < instance_materials.length; j ++ ) {
1142 |
1143 | var instance_material = instance_materials[ j ];
1144 | var mat = materials[ instance_material.target ];
1145 | var effect_id = mat.instance_effect.url;
1146 | var shader = effects[ effect_id ].shader;
1147 | var material3js = shader.material;
1148 |
1149 | if ( geometry.doubleSided ) {
1150 |
1151 | if ( !( instance_material.symbol in double_sided_materials ) ) {
1152 |
1153 | var _copied_material = material3js.clone();
1154 | _copied_material.side = THREE.DoubleSide;
1155 | double_sided_materials[ instance_material.symbol ] = _copied_material;
1156 |
1157 | }
1158 |
1159 | material3js = double_sided_materials[ instance_material.symbol ];
1160 |
1161 | }
1162 |
1163 | material3js.opacity = !material3js.opacity ? 1 : material3js.opacity;
1164 | used_materials[ instance_material.symbol ] = num_materials;
1165 | used_materials_array.push( material3js );
1166 | first_material = material3js;
1167 | first_material.name = mat.name === null || mat.name === '' ? mat.id : mat.name;
1168 | num_materials ++;
1169 |
1170 | }
1171 |
1172 | }
1173 |
1174 | var mesh;
1175 | var material = first_material || new THREE.MeshLambertMaterial( { color: 0xdddddd, side: geometry.doubleSided ? THREE.DoubleSide : THREE.FrontSide } );
1176 | var geom = geometry.mesh.geometry3js;
1177 |
1178 | if ( num_materials > 1 ) {
1179 |
1180 | material = new THREE.MeshFaceMaterial( used_materials_array );
1181 |
1182 | for ( j = 0; j < geom.faces.length; j ++ ) {
1183 |
1184 | var face = geom.faces[ j ];
1185 | face.materialIndex = used_materials[ face.daeMaterial ]
1186 |
1187 | }
1188 |
1189 | }
1190 |
1191 | if ( skinController !== undefined ) {
1192 |
1193 |
1194 | applySkin( geom, skinController );
1195 |
1196 | if ( geom.morphTargets.length > 0 ) {
1197 |
1198 | material.morphTargets = true;
1199 | material.skinning = false;
1200 |
1201 | } else {
1202 |
1203 | material.morphTargets = false;
1204 | material.skinning = true;
1205 |
1206 | }
1207 |
1208 |
1209 | mesh = new THREE.SkinnedMesh( geom, material, false );
1210 |
1211 |
1212 | //mesh.skeleton = skinController.skeleton;
1213 | //mesh.skinController = controllers[ skinController.url ];
1214 | //mesh.skinInstanceController = skinController;
1215 | mesh.name = 'skin_' + skins.length;
1216 |
1217 |
1218 |
1219 | //mesh.animationHandle.setKey(0);
1220 | skins.push( mesh );
1221 |
1222 | } else if ( morphController !== undefined ) {
1223 |
1224 | createMorph( geom, morphController );
1225 |
1226 | material.morphTargets = true;
1227 |
1228 | mesh = new THREE.Mesh( geom, material );
1229 | mesh.name = 'morph_' + morphs.length;
1230 |
1231 | morphs.push( mesh );
1232 |
1233 | } else {
1234 |
1235 | if ( geom.isLineStrip === true ) {
1236 |
1237 | mesh = new THREE.Line( geom );
1238 |
1239 | } else {
1240 |
1241 | mesh = new THREE.Mesh( geom, material );
1242 |
1243 | }
1244 |
1245 | }
1246 |
1247 | obj.add(mesh);
1248 |
1249 | }
1250 |
1251 | }
1252 |
1253 | for ( i = 0; i < node.cameras.length; i ++ ) {
1254 |
1255 | var instance_camera = node.cameras[i];
1256 | var cparams = cameras[instance_camera.url];
1257 |
1258 | var cam = new THREE.PerspectiveCamera(cparams.yfov, parseFloat(cparams.aspect_ratio),
1259 | parseFloat(cparams.znear), parseFloat(cparams.zfar));
1260 |
1261 | obj.add(cam);
1262 | }
1263 |
1264 | for ( i = 0; i < node.lights.length; i ++ ) {
1265 |
1266 | var light = null;
1267 | var instance_light = node.lights[i];
1268 | var lparams = lights[instance_light.url];
1269 |
1270 | if ( lparams && lparams.technique ) {
1271 |
1272 | var color = lparams.color.getHex();
1273 | var intensity = lparams.intensity;
1274 | var distance = lparams.distance;
1275 | var angle = lparams.falloff_angle;
1276 | var exponent; // Intentionally undefined, don't know what this is yet
1277 |
1278 | switch ( lparams.technique ) {
1279 |
1280 | case 'directional':
1281 |
1282 | light = new THREE.DirectionalLight( color, intensity, distance );
1283 | light.position.set(0, 0, 1);
1284 | break;
1285 |
1286 | case 'point':
1287 |
1288 | light = new THREE.PointLight( color, intensity, distance );
1289 | break;
1290 |
1291 | case 'spot':
1292 |
1293 | light = new THREE.SpotLight( color, intensity, distance, angle, exponent );
1294 | light.position.set(0, 0, 1);
1295 | break;
1296 |
1297 | case 'ambient':
1298 |
1299 | light = new THREE.AmbientLight( color );
1300 | break;
1301 |
1302 | }
1303 |
1304 | }
1305 |
1306 | if (light) {
1307 | obj.add(light);
1308 | }
1309 | }
1310 |
1311 | obj.name = node.name || node.id || "";
1312 | obj.colladaId = node.id || "";
1313 | obj.layer = node.layer || "";
1314 | obj.matrix = node.matrix;
1315 | obj.matrix.decompose( obj.position, obj.quaternion, obj.scale );
1316 |
1317 | if ( options.centerGeometry && obj.geometry ) {
1318 |
1319 | var delta = obj.geometry.center();
1320 | delta.multiply( obj.scale );
1321 | delta.applyQuaternion( obj.quaternion );
1322 |
1323 | obj.position.sub( delta );
1324 |
1325 | }
1326 |
1327 | for ( i = 0; i < node.nodes.length; i ++ ) {
1328 |
1329 | obj.add( createSceneGraph( node.nodes[i], node ) );
1330 |
1331 | }
1332 |
1333 | return obj;
1334 |
1335 | };
1336 |
1337 | function getJointId( skin, id ) {
1338 |
1339 | for ( var i = 0; i < skin.joints.length; i ++ ) {
1340 |
1341 | if ( skin.joints[ i ] === id ) {
1342 |
1343 | return i;
1344 |
1345 | }
1346 |
1347 | }
1348 |
1349 | };
1350 |
1351 | function getLibraryNode( id ) {
1352 |
1353 | var nodes = COLLADA.querySelectorAll('library_nodes node');
1354 |
1355 | for ( var i = 0; i < nodes.length; i++ ) {
1356 |
1357 | var attObj = nodes[i].attributes.getNamedItem('id');
1358 |
1359 | if ( attObj && attObj.value === id ) {
1360 |
1361 | return nodes[i];
1362 |
1363 | }
1364 |
1365 | }
1366 |
1367 | return undefined;
1368 |
1369 | };
1370 |
1371 | function getChannelsForNode ( node ) {
1372 |
1373 | var channels = [];
1374 | var startTime = 1000000;
1375 | var endTime = -1000000;
1376 |
1377 | for ( var id in animations ) {
1378 |
1379 | var animation = animations[id];
1380 |
1381 | for ( var i = 0; i < animation.channel.length; i ++ ) {
1382 |
1383 | var channel = animation.channel[i];
1384 | var sampler = animation.sampler[i];
1385 | var id = channel.target.split('/')[0];
1386 |
1387 | if ( id == node.id ) {
1388 |
1389 | sampler.create();
1390 | channel.sampler = sampler;
1391 | startTime = Math.min(startTime, sampler.startTime);
1392 | endTime = Math.max(endTime, sampler.endTime);
1393 | channels.push(channel);
1394 |
1395 | }
1396 |
1397 | }
1398 |
1399 | }
1400 |
1401 | if ( channels.length ) {
1402 |
1403 | node.startTime = startTime;
1404 | node.endTime = endTime;
1405 |
1406 | }
1407 |
1408 | return channels;
1409 |
1410 | };
1411 |
1412 | function calcFrameDuration( node ) {
1413 |
1414 | var minT = 10000000;
1415 |
1416 | for ( var i = 0; i < node.channels.length; i ++ ) {
1417 |
1418 | var sampler = node.channels[i].sampler;
1419 |
1420 | for ( var j = 0; j < sampler.input.length - 1; j ++ ) {
1421 |
1422 | var t0 = sampler.input[ j ];
1423 | var t1 = sampler.input[ j + 1 ];
1424 | minT = Math.min( minT, t1 - t0 );
1425 |
1426 | }
1427 | }
1428 |
1429 | return minT;
1430 |
1431 | };
1432 |
1433 | function calcMatrixAt( node, t ) {
1434 |
1435 | var animated = {};
1436 |
1437 | var i, j;
1438 |
1439 | for ( i = 0; i < node.channels.length; i ++ ) {
1440 |
1441 | var channel = node.channels[ i ];
1442 | animated[ channel.sid ] = channel;
1443 |
1444 | }
1445 |
1446 | var matrix = new THREE.Matrix4();
1447 |
1448 | for ( i = 0; i < node.transforms.length; i ++ ) {
1449 |
1450 | var transform = node.transforms[ i ];
1451 | var channel = animated[ transform.sid ];
1452 |
1453 | if ( channel !== undefined ) {
1454 |
1455 | var sampler = channel.sampler;
1456 | var value;
1457 |
1458 | for ( j = 0; j < sampler.input.length - 1; j ++ ) {
1459 |
1460 | if ( sampler.input[ j + 1 ] > t ) {
1461 |
1462 | value = sampler.output[ j ];
1463 | //console.log(value.flatten)
1464 | break;
1465 |
1466 | }
1467 |
1468 | }
1469 |
1470 | if ( value !== undefined ) {
1471 |
1472 | if ( value instanceof THREE.Matrix4 ) {
1473 |
1474 | matrix.multiplyMatrices( matrix, value );
1475 |
1476 | } else {
1477 |
1478 | // FIXME: handle other types
1479 |
1480 | matrix.multiplyMatrices( matrix, transform.matrix );
1481 |
1482 | }
1483 |
1484 | } else {
1485 |
1486 | matrix.multiplyMatrices( matrix, transform.matrix );
1487 |
1488 | }
1489 |
1490 | } else {
1491 |
1492 | matrix.multiplyMatrices( matrix, transform.matrix );
1493 |
1494 | }
1495 |
1496 | }
1497 |
1498 | return matrix;
1499 |
1500 | };
1501 |
1502 | function bakeAnimations ( node ) {
1503 |
1504 | if ( node.channels && node.channels.length ) {
1505 |
1506 | var keys = [],
1507 | sids = [];
1508 |
1509 | for ( var i = 0, il = node.channels.length; i < il; i ++ ) {
1510 |
1511 | var channel = node.channels[i],
1512 | fullSid = channel.fullSid,
1513 | sampler = channel.sampler,
1514 | input = sampler.input,
1515 | transform = node.getTransformBySid( channel.sid ),
1516 | member;
1517 |
1518 | if ( channel.arrIndices ) {
1519 |
1520 | member = [];
1521 |
1522 | for ( var j = 0, jl = channel.arrIndices.length; j < jl; j ++ ) {
1523 |
1524 | member[ j ] = getConvertedIndex( channel.arrIndices[ j ] );
1525 |
1526 | }
1527 |
1528 | } else {
1529 |
1530 | member = getConvertedMember( channel.member );
1531 |
1532 | }
1533 |
1534 | if ( transform ) {
1535 |
1536 | if ( sids.indexOf( fullSid ) === -1 ) {
1537 |
1538 | sids.push( fullSid );
1539 |
1540 | }
1541 |
1542 | for ( var j = 0, jl = input.length; j < jl; j ++ ) {
1543 |
1544 | var time = input[j],
1545 | data = sampler.getData( transform.type, j, member ),
1546 | key = findKey( keys, time );
1547 |
1548 | if ( !key ) {
1549 |
1550 | key = new Key( time );
1551 | var timeNdx = findTimeNdx( keys, time );
1552 | keys.splice( timeNdx === -1 ? keys.length : timeNdx, 0, key );
1553 |
1554 | }
1555 |
1556 | key.addTarget( fullSid, transform, member, data );
1557 |
1558 | }
1559 |
1560 | } else {
1561 |
1562 | console.log( 'Could not find transform "' + channel.sid + '" in node ' + node.id );
1563 |
1564 | }
1565 |
1566 | }
1567 |
1568 | // post process
1569 | for ( var i = 0; i < sids.length; i ++ ) {
1570 |
1571 | var sid = sids[ i ];
1572 |
1573 | for ( var j = 0; j < keys.length; j ++ ) {
1574 |
1575 | var key = keys[ j ];
1576 |
1577 | if ( !key.hasTarget( sid ) ) {
1578 |
1579 | interpolateKeys( keys, key, j, sid );
1580 |
1581 | }
1582 |
1583 | }
1584 |
1585 | }
1586 |
1587 | node.keys = keys;
1588 | node.sids = sids;
1589 |
1590 | }
1591 |
1592 | };
1593 |
1594 | function findKey ( keys, time) {
1595 |
1596 | var retVal = null;
1597 |
1598 | for ( var i = 0, il = keys.length; i < il && retVal === null; i ++ ) {
1599 |
1600 | var key = keys[i];
1601 |
1602 | if ( key.time === time ) {
1603 |
1604 | retVal = key;
1605 |
1606 | } else if ( key.time > time ) {
1607 |
1608 | break;
1609 |
1610 | }
1611 |
1612 | }
1613 |
1614 | return retVal;
1615 |
1616 | };
1617 |
1618 | function findTimeNdx ( keys, time) {
1619 |
1620 | var ndx = -1;
1621 |
1622 | for ( var i = 0, il = keys.length; i < il && ndx === -1; i ++ ) {
1623 |
1624 | var key = keys[i];
1625 |
1626 | if ( key.time >= time ) {
1627 |
1628 | ndx = i;
1629 |
1630 | }
1631 |
1632 | }
1633 |
1634 | return ndx;
1635 |
1636 | };
1637 |
1638 | function interpolateKeys ( keys, key, ndx, fullSid ) {
1639 |
1640 | var prevKey = getPrevKeyWith( keys, fullSid, ndx ? ndx - 1 : 0 ),
1641 | nextKey = getNextKeyWith( keys, fullSid, ndx + 1 );
1642 |
1643 | if ( prevKey && nextKey ) {
1644 |
1645 | var scale = (key.time - prevKey.time) / (nextKey.time - prevKey.time),
1646 | prevTarget = prevKey.getTarget( fullSid ),
1647 | nextData = nextKey.getTarget( fullSid ).data,
1648 | prevData = prevTarget.data,
1649 | data;
1650 |
1651 | if ( prevTarget.type === 'matrix' ) {
1652 |
1653 | data = prevData;
1654 |
1655 | } else if ( prevData.length ) {
1656 |
1657 | data = [];
1658 |
1659 | for ( var i = 0; i < prevData.length; ++ i ) {
1660 |
1661 | data[ i ] = prevData[ i ] + ( nextData[ i ] - prevData[ i ] ) * scale;
1662 |
1663 | }
1664 |
1665 | } else {
1666 |
1667 | data = prevData + ( nextData - prevData ) * scale;
1668 |
1669 | }
1670 |
1671 | key.addTarget( fullSid, prevTarget.transform, prevTarget.member, data );
1672 |
1673 | }
1674 |
1675 | };
1676 |
1677 | // Get next key with given sid
1678 |
1679 | function getNextKeyWith( keys, fullSid, ndx ) {
1680 |
1681 | for ( ; ndx < keys.length; ndx ++ ) {
1682 |
1683 | var key = keys[ ndx ];
1684 |
1685 | if ( key.hasTarget( fullSid ) ) {
1686 |
1687 | return key;
1688 |
1689 | }
1690 |
1691 | }
1692 |
1693 | return null;
1694 |
1695 | };
1696 |
1697 | // Get previous key with given sid
1698 |
1699 | function getPrevKeyWith( keys, fullSid, ndx ) {
1700 |
1701 | ndx = ndx >= 0 ? ndx : ndx + keys.length;
1702 |
1703 | for ( ; ndx >= 0; ndx -- ) {
1704 |
1705 | var key = keys[ ndx ];
1706 |
1707 | if ( key.hasTarget( fullSid ) ) {
1708 |
1709 | return key;
1710 |
1711 | }
1712 |
1713 | }
1714 |
1715 | return null;
1716 |
1717 | };
1718 |
1719 | function _Image() {
1720 |
1721 | this.id = "";
1722 | this.init_from = "";
1723 |
1724 | };
1725 |
1726 | _Image.prototype.parse = function(element) {
1727 |
1728 | this.id = element.getAttribute('id');
1729 |
1730 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1731 |
1732 | var child = element.childNodes[ i ];
1733 |
1734 | if ( child.nodeName === 'init_from' ) {
1735 |
1736 | this.init_from = child.textContent;
1737 |
1738 | }
1739 |
1740 | }
1741 |
1742 | return this;
1743 |
1744 | };
1745 |
1746 | function Controller() {
1747 |
1748 | this.id = "";
1749 | this.name = "";
1750 | this.type = "";
1751 | this.skin = null;
1752 | this.morph = null;
1753 |
1754 | };
1755 |
1756 | Controller.prototype.parse = function( element ) {
1757 |
1758 | this.id = element.getAttribute('id');
1759 | this.name = element.getAttribute('name');
1760 | this.type = "none";
1761 |
1762 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1763 |
1764 | var child = element.childNodes[ i ];
1765 |
1766 | switch ( child.nodeName ) {
1767 |
1768 | case 'skin':
1769 |
1770 | this.skin = (new Skin()).parse(child);
1771 | this.type = child.nodeName;
1772 | break;
1773 |
1774 | case 'morph':
1775 |
1776 | this.morph = (new Morph()).parse(child);
1777 | this.type = child.nodeName;
1778 | break;
1779 |
1780 | default:
1781 | break;
1782 |
1783 | }
1784 | }
1785 |
1786 | return this;
1787 |
1788 | };
1789 |
1790 | function Morph() {
1791 |
1792 | this.method = null;
1793 | this.source = null;
1794 | this.targets = null;
1795 | this.weights = null;
1796 |
1797 | };
1798 |
1799 | Morph.prototype.parse = function( element ) {
1800 |
1801 | var sources = {};
1802 | var inputs = [];
1803 | var i;
1804 |
1805 | this.method = element.getAttribute( 'method' );
1806 | this.source = element.getAttribute( 'source' ).replace( /^#/, '' );
1807 |
1808 | for ( i = 0; i < element.childNodes.length; i ++ ) {
1809 |
1810 | var child = element.childNodes[ i ];
1811 | if ( child.nodeType != 1 ) continue;
1812 |
1813 | switch ( child.nodeName ) {
1814 |
1815 | case 'source':
1816 |
1817 | var source = ( new Source() ).parse( child );
1818 | sources[ source.id ] = source;
1819 | break;
1820 |
1821 | case 'targets':
1822 |
1823 | inputs = this.parseInputs( child );
1824 | break;
1825 |
1826 | default:
1827 |
1828 | console.log( child.nodeName );
1829 | break;
1830 |
1831 | }
1832 |
1833 | }
1834 |
1835 | for ( i = 0; i < inputs.length; i ++ ) {
1836 |
1837 | var input = inputs[ i ];
1838 | var source = sources[ input.source ];
1839 |
1840 | switch ( input.semantic ) {
1841 |
1842 | case 'MORPH_TARGET':
1843 |
1844 | this.targets = source.read();
1845 | break;
1846 |
1847 | case 'MORPH_WEIGHT':
1848 |
1849 | this.weights = source.read();
1850 | break;
1851 |
1852 | default:
1853 | break;
1854 |
1855 | }
1856 | }
1857 |
1858 | return this;
1859 |
1860 | };
1861 |
1862 | Morph.prototype.parseInputs = function(element) {
1863 |
1864 | var inputs = [];
1865 |
1866 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1867 |
1868 | var child = element.childNodes[i];
1869 | if ( child.nodeType != 1) continue;
1870 |
1871 | switch ( child.nodeName ) {
1872 |
1873 | case 'input':
1874 |
1875 | inputs.push( (new Input()).parse(child) );
1876 | break;
1877 |
1878 | default:
1879 | break;
1880 | }
1881 | }
1882 |
1883 | return inputs;
1884 |
1885 | };
1886 |
1887 | function Skin() {
1888 |
1889 | this.source = "";
1890 | this.bindShapeMatrix = null;
1891 | this.invBindMatrices = [];
1892 | this.joints = [];
1893 | this.weights = [];
1894 |
1895 | };
1896 |
1897 | Skin.prototype.parse = function( element ) {
1898 |
1899 | var sources = {};
1900 | var joints, weights;
1901 |
1902 | this.source = element.getAttribute( 'source' ).replace( /^#/, '' );
1903 | this.invBindMatrices = [];
1904 | this.joints = [];
1905 | this.weights = [];
1906 |
1907 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1908 |
1909 | var child = element.childNodes[i];
1910 | if ( child.nodeType != 1 ) continue;
1911 |
1912 | switch ( child.nodeName ) {
1913 |
1914 | case 'bind_shape_matrix':
1915 |
1916 | var f = _floats(child.textContent);
1917 | this.bindShapeMatrix = getConvertedMat4( f );
1918 | break;
1919 |
1920 | case 'source':
1921 |
1922 | var src = new Source().parse(child);
1923 | sources[ src.id ] = src;
1924 | break;
1925 |
1926 | case 'joints':
1927 |
1928 | joints = child;
1929 | break;
1930 |
1931 | case 'vertex_weights':
1932 |
1933 | weights = child;
1934 | break;
1935 |
1936 | default:
1937 |
1938 | console.log( child.nodeName );
1939 | break;
1940 |
1941 | }
1942 | }
1943 |
1944 | this.parseJoints( joints, sources );
1945 | this.parseWeights( weights, sources );
1946 |
1947 | return this;
1948 |
1949 | };
1950 |
1951 | Skin.prototype.parseJoints = function ( element, sources ) {
1952 |
1953 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1954 |
1955 | var child = element.childNodes[ i ];
1956 | if ( child.nodeType != 1 ) continue;
1957 |
1958 | switch ( child.nodeName ) {
1959 |
1960 | case 'input':
1961 |
1962 | var input = ( new Input() ).parse( child );
1963 | var source = sources[ input.source ];
1964 |
1965 | if ( input.semantic === 'JOINT' ) {
1966 |
1967 | this.joints = source.read();
1968 |
1969 | } else if ( input.semantic === 'INV_BIND_MATRIX' ) {
1970 |
1971 | this.invBindMatrices = source.read();
1972 |
1973 | }
1974 |
1975 | break;
1976 |
1977 | default:
1978 | break;
1979 | }
1980 |
1981 | }
1982 |
1983 | };
1984 |
1985 | Skin.prototype.parseWeights = function ( element, sources ) {
1986 |
1987 | var v, vcount, inputs = [];
1988 |
1989 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
1990 |
1991 | var child = element.childNodes[ i ];
1992 | if ( child.nodeType != 1 ) continue;
1993 |
1994 | switch ( child.nodeName ) {
1995 |
1996 | case 'input':
1997 |
1998 | inputs.push( ( new Input() ).parse( child ) );
1999 | break;
2000 |
2001 | case 'v':
2002 |
2003 | v = _ints( child.textContent );
2004 | break;
2005 |
2006 | case 'vcount':
2007 |
2008 | vcount = _ints( child.textContent );
2009 | break;
2010 |
2011 | default:
2012 | break;
2013 |
2014 | }
2015 |
2016 | }
2017 |
2018 | var index = 0;
2019 |
2020 | for ( var i = 0; i < vcount.length; i ++ ) {
2021 |
2022 | var numBones = vcount[i];
2023 | var vertex_weights = [];
2024 |
2025 | for ( var j = 0; j < numBones; j ++ ) {
2026 |
2027 | var influence = {};
2028 |
2029 | for ( var k = 0; k < inputs.length; k ++ ) {
2030 |
2031 | var input = inputs[ k ];
2032 | var value = v[ index + input.offset ];
2033 |
2034 | switch ( input.semantic ) {
2035 |
2036 | case 'JOINT':
2037 |
2038 | influence.joint = value;//this.joints[value];
2039 | break;
2040 |
2041 | case 'WEIGHT':
2042 |
2043 | influence.weight = sources[ input.source ].data[ value ];
2044 | break;
2045 |
2046 | default:
2047 | break;
2048 |
2049 | }
2050 |
2051 | }
2052 |
2053 | vertex_weights.push( influence );
2054 | index += inputs.length;
2055 | }
2056 |
2057 | for ( var j = 0; j < vertex_weights.length; j ++ ) {
2058 |
2059 | vertex_weights[ j ].index = i;
2060 |
2061 | }
2062 |
2063 | this.weights.push( vertex_weights );
2064 |
2065 | }
2066 |
2067 | };
2068 |
2069 | function VisualScene () {
2070 |
2071 | this.id = "";
2072 | this.name = "";
2073 | this.nodes = [];
2074 | this.scene = new THREE.Group();
2075 |
2076 | };
2077 |
2078 | VisualScene.prototype.getChildById = function( id, recursive ) {
2079 |
2080 | for ( var i = 0; i < this.nodes.length; i ++ ) {
2081 |
2082 | var node = this.nodes[ i ].getChildById( id, recursive );
2083 |
2084 | if ( node ) {
2085 |
2086 | return node;
2087 |
2088 | }
2089 |
2090 | }
2091 |
2092 | return null;
2093 |
2094 | };
2095 |
2096 | VisualScene.prototype.getChildBySid = function( sid, recursive ) {
2097 |
2098 | for ( var i = 0; i < this.nodes.length; i ++ ) {
2099 |
2100 | var node = this.nodes[ i ].getChildBySid( sid, recursive );
2101 |
2102 | if ( node ) {
2103 |
2104 | return node;
2105 |
2106 | }
2107 |
2108 | }
2109 |
2110 | return null;
2111 |
2112 | };
2113 |
2114 | VisualScene.prototype.parse = function( element ) {
2115 |
2116 | this.id = element.getAttribute( 'id' );
2117 | this.name = element.getAttribute( 'name' );
2118 | this.nodes = [];
2119 |
2120 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2121 |
2122 | var child = element.childNodes[ i ];
2123 | if ( child.nodeType != 1 ) continue;
2124 |
2125 | switch ( child.nodeName ) {
2126 |
2127 | case 'node':
2128 |
2129 | this.nodes.push( ( new Node() ).parse( child ) );
2130 | break;
2131 |
2132 | default:
2133 | break;
2134 |
2135 | }
2136 |
2137 | }
2138 |
2139 | return this;
2140 |
2141 | };
2142 |
2143 | function Node() {
2144 |
2145 | this.id = "";
2146 | this.name = "";
2147 | this.sid = "";
2148 | this.nodes = [];
2149 | this.controllers = [];
2150 | this.transforms = [];
2151 | this.geometries = [];
2152 | this.channels = [];
2153 | this.matrix = new THREE.Matrix4();
2154 |
2155 | };
2156 |
2157 | Node.prototype.getChannelForTransform = function( transformSid ) {
2158 |
2159 | for ( var i = 0; i < this.channels.length; i ++ ) {
2160 |
2161 | var channel = this.channels[i];
2162 | var parts = channel.target.split('/');
2163 | var id = parts.shift();
2164 | var sid = parts.shift();
2165 | var dotSyntax = (sid.indexOf(".") >= 0);
2166 | var arrSyntax = (sid.indexOf("(") >= 0);
2167 | var arrIndices;
2168 | var member;
2169 |
2170 | if ( dotSyntax ) {
2171 |
2172 | parts = sid.split(".");
2173 | sid = parts.shift();
2174 | member = parts.shift();
2175 |
2176 | } else if ( arrSyntax ) {
2177 |
2178 | arrIndices = sid.split("(");
2179 | sid = arrIndices.shift();
2180 |
2181 | for ( var j = 0; j < arrIndices.length; j ++ ) {
2182 |
2183 | arrIndices[ j ] = parseInt( arrIndices[ j ].replace( /\)/, '' ) );
2184 |
2185 | }
2186 |
2187 | }
2188 |
2189 | if ( sid === transformSid ) {
2190 |
2191 | channel.info = { sid: sid, dotSyntax: dotSyntax, arrSyntax: arrSyntax, arrIndices: arrIndices };
2192 | return channel;
2193 |
2194 | }
2195 |
2196 | }
2197 |
2198 | return null;
2199 |
2200 | };
2201 |
2202 | Node.prototype.getChildById = function ( id, recursive ) {
2203 |
2204 | if ( this.id === id ) {
2205 |
2206 | return this;
2207 |
2208 | }
2209 |
2210 | if ( recursive ) {
2211 |
2212 | for ( var i = 0; i < this.nodes.length; i ++ ) {
2213 |
2214 | var n = this.nodes[ i ].getChildById( id, recursive );
2215 |
2216 | if ( n ) {
2217 |
2218 | return n;
2219 |
2220 | }
2221 |
2222 | }
2223 |
2224 | }
2225 |
2226 | return null;
2227 |
2228 | };
2229 |
2230 | Node.prototype.getChildBySid = function ( sid, recursive ) {
2231 |
2232 | if ( this.sid === sid ) {
2233 |
2234 | return this;
2235 |
2236 | }
2237 |
2238 | if ( recursive ) {
2239 |
2240 | for ( var i = 0; i < this.nodes.length; i ++ ) {
2241 |
2242 | var n = this.nodes[ i ].getChildBySid( sid, recursive );
2243 |
2244 | if ( n ) {
2245 |
2246 | return n;
2247 |
2248 | }
2249 |
2250 | }
2251 | }
2252 |
2253 | return null;
2254 |
2255 | };
2256 |
2257 | Node.prototype.getTransformBySid = function ( sid ) {
2258 |
2259 | for ( var i = 0; i < this.transforms.length; i ++ ) {
2260 |
2261 | if ( this.transforms[ i ].sid === sid ) return this.transforms[ i ];
2262 |
2263 | }
2264 |
2265 | return null;
2266 |
2267 | };
2268 |
2269 | Node.prototype.parse = function( element ) {
2270 |
2271 | var url;
2272 |
2273 | this.id = element.getAttribute('id');
2274 | this.sid = element.getAttribute('sid');
2275 | this.name = element.getAttribute('name');
2276 | this.type = element.getAttribute('type');
2277 | this.layer = element.getAttribute('layer');
2278 |
2279 | this.type = this.type === 'JOINT' ? this.type : 'NODE';
2280 |
2281 | this.nodes = [];
2282 | this.transforms = [];
2283 | this.geometries = [];
2284 | this.cameras = [];
2285 | this.lights = [];
2286 | this.controllers = [];
2287 | this.matrix = new THREE.Matrix4();
2288 |
2289 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2290 |
2291 | var child = element.childNodes[ i ];
2292 | if ( child.nodeType != 1 ) continue;
2293 |
2294 | switch ( child.nodeName ) {
2295 |
2296 | case 'node':
2297 |
2298 | this.nodes.push( ( new Node() ).parse( child ) );
2299 | break;
2300 |
2301 | case 'instance_camera':
2302 |
2303 | this.cameras.push( ( new InstanceCamera() ).parse( child ) );
2304 | break;
2305 |
2306 | case 'instance_controller':
2307 |
2308 | this.controllers.push( ( new InstanceController() ).parse( child ) );
2309 | break;
2310 |
2311 | case 'instance_geometry':
2312 |
2313 | this.geometries.push( ( new InstanceGeometry() ).parse( child ) );
2314 | break;
2315 |
2316 | case 'instance_light':
2317 |
2318 | this.lights.push( ( new InstanceLight() ).parse( child ) );
2319 | break;
2320 |
2321 | case 'instance_node':
2322 |
2323 | url = child.getAttribute( 'url' ).replace( /^#/, '' );
2324 | var iNode = getLibraryNode( url );
2325 |
2326 | if ( iNode ) {
2327 |
2328 | this.nodes.push( ( new Node() ).parse( iNode )) ;
2329 |
2330 | }
2331 |
2332 | break;
2333 |
2334 | case 'rotate':
2335 | case 'translate':
2336 | case 'scale':
2337 | case 'matrix':
2338 | case 'lookat':
2339 | case 'skew':
2340 |
2341 | this.transforms.push( ( new Transform() ).parse( child ) );
2342 | break;
2343 |
2344 | case 'extra':
2345 | break;
2346 |
2347 | default:
2348 |
2349 | console.log( child.nodeName );
2350 | break;
2351 |
2352 | }
2353 |
2354 | }
2355 |
2356 | this.channels = getChannelsForNode( this );
2357 | bakeAnimations( this );
2358 |
2359 | this.updateMatrix();
2360 |
2361 | return this;
2362 |
2363 | };
2364 |
2365 | Node.prototype.updateMatrix = function () {
2366 |
2367 | this.matrix.identity();
2368 |
2369 | for ( var i = 0; i < this.transforms.length; i ++ ) {
2370 |
2371 | this.transforms[ i ].apply( this.matrix );
2372 |
2373 | }
2374 |
2375 | };
2376 |
2377 | function Transform () {
2378 |
2379 | this.sid = "";
2380 | this.type = "";
2381 | this.data = [];
2382 | this.obj = null;
2383 |
2384 | };
2385 |
2386 | Transform.prototype.parse = function ( element ) {
2387 |
2388 | this.sid = element.getAttribute( 'sid' );
2389 | this.type = element.nodeName;
2390 | this.data = _floats( element.textContent );
2391 | this.convert();
2392 |
2393 | return this;
2394 |
2395 | };
2396 |
2397 | Transform.prototype.convert = function () {
2398 |
2399 | switch ( this.type ) {
2400 |
2401 | case 'matrix':
2402 |
2403 | this.obj = getConvertedMat4( this.data );
2404 | break;
2405 |
2406 | case 'rotate':
2407 |
2408 | this.angle = THREE.Math.degToRad( this.data[3] );
2409 |
2410 | case 'translate':
2411 |
2412 | fixCoords( this.data, -1 );
2413 | this.obj = new THREE.Vector3( this.data[ 0 ], this.data[ 1 ], this.data[ 2 ] );
2414 | break;
2415 |
2416 | case 'scale':
2417 |
2418 | fixCoords( this.data, 1 );
2419 | this.obj = new THREE.Vector3( this.data[ 0 ], this.data[ 1 ], this.data[ 2 ] );
2420 | break;
2421 |
2422 | default:
2423 | console.log( 'Can not convert Transform of type ' + this.type );
2424 | break;
2425 |
2426 | }
2427 |
2428 | };
2429 |
2430 | Transform.prototype.apply = function () {
2431 |
2432 | var m1 = new THREE.Matrix4();
2433 |
2434 | return function ( matrix ) {
2435 |
2436 | switch ( this.type ) {
2437 |
2438 | case 'matrix':
2439 |
2440 | matrix.multiply( this.obj );
2441 |
2442 | break;
2443 |
2444 | case 'translate':
2445 |
2446 | matrix.multiply( m1.makeTranslation( this.obj.x, this.obj.y, this.obj.z ) );
2447 |
2448 | break;
2449 |
2450 | case 'rotate':
2451 |
2452 | matrix.multiply( m1.makeRotationAxis( this.obj, this.angle ) );
2453 |
2454 | break;
2455 |
2456 | case 'scale':
2457 |
2458 | matrix.scale( this.obj );
2459 |
2460 | break;
2461 |
2462 | }
2463 |
2464 | };
2465 |
2466 | }();
2467 |
2468 | Transform.prototype.update = function ( data, member ) {
2469 |
2470 | var members = [ 'X', 'Y', 'Z', 'ANGLE' ];
2471 |
2472 | switch ( this.type ) {
2473 |
2474 | case 'matrix':
2475 |
2476 | if ( ! member ) {
2477 |
2478 | this.obj.copy( data );
2479 |
2480 | } else if ( member.length === 1 ) {
2481 |
2482 | switch ( member[ 0 ] ) {
2483 |
2484 | case 0:
2485 |
2486 | this.obj.n11 = data[ 0 ];
2487 | this.obj.n21 = data[ 1 ];
2488 | this.obj.n31 = data[ 2 ];
2489 | this.obj.n41 = data[ 3 ];
2490 |
2491 | break;
2492 |
2493 | case 1:
2494 |
2495 | this.obj.n12 = data[ 0 ];
2496 | this.obj.n22 = data[ 1 ];
2497 | this.obj.n32 = data[ 2 ];
2498 | this.obj.n42 = data[ 3 ];
2499 |
2500 | break;
2501 |
2502 | case 2:
2503 |
2504 | this.obj.n13 = data[ 0 ];
2505 | this.obj.n23 = data[ 1 ];
2506 | this.obj.n33 = data[ 2 ];
2507 | this.obj.n43 = data[ 3 ];
2508 |
2509 | break;
2510 |
2511 | case 3:
2512 |
2513 | this.obj.n14 = data[ 0 ];
2514 | this.obj.n24 = data[ 1 ];
2515 | this.obj.n34 = data[ 2 ];
2516 | this.obj.n44 = data[ 3 ];
2517 |
2518 | break;
2519 |
2520 | }
2521 |
2522 | } else if ( member.length === 2 ) {
2523 |
2524 | var propName = 'n' + ( member[ 0 ] + 1 ) + ( member[ 1 ] + 1 );
2525 | this.obj[ propName ] = data;
2526 |
2527 | } else {
2528 |
2529 | console.log('Incorrect addressing of matrix in transform.');
2530 |
2531 | }
2532 |
2533 | break;
2534 |
2535 | case 'translate':
2536 | case 'scale':
2537 |
2538 | if ( Object.prototype.toString.call( member ) === '[object Array]' ) {
2539 |
2540 | member = members[ member[ 0 ] ];
2541 |
2542 | }
2543 |
2544 | switch ( member ) {
2545 |
2546 | case 'X':
2547 |
2548 | this.obj.x = data;
2549 | break;
2550 |
2551 | case 'Y':
2552 |
2553 | this.obj.y = data;
2554 | break;
2555 |
2556 | case 'Z':
2557 |
2558 | this.obj.z = data;
2559 | break;
2560 |
2561 | default:
2562 |
2563 | this.obj.x = data[ 0 ];
2564 | this.obj.y = data[ 1 ];
2565 | this.obj.z = data[ 2 ];
2566 | break;
2567 |
2568 | }
2569 |
2570 | break;
2571 |
2572 | case 'rotate':
2573 |
2574 | if ( Object.prototype.toString.call( member ) === '[object Array]' ) {
2575 |
2576 | member = members[ member[ 0 ] ];
2577 |
2578 | }
2579 |
2580 | switch ( member ) {
2581 |
2582 | case 'X':
2583 |
2584 | this.obj.x = data;
2585 | break;
2586 |
2587 | case 'Y':
2588 |
2589 | this.obj.y = data;
2590 | break;
2591 |
2592 | case 'Z':
2593 |
2594 | this.obj.z = data;
2595 | break;
2596 |
2597 | case 'ANGLE':
2598 |
2599 | this.angle = THREE.Math.degToRad( data );
2600 | break;
2601 |
2602 | default:
2603 |
2604 | this.obj.x = data[ 0 ];
2605 | this.obj.y = data[ 1 ];
2606 | this.obj.z = data[ 2 ];
2607 | this.angle = THREE.Math.degToRad( data[ 3 ] );
2608 | break;
2609 |
2610 | }
2611 | break;
2612 |
2613 | }
2614 |
2615 | };
2616 |
2617 | function InstanceController() {
2618 |
2619 | this.url = "";
2620 | this.skeleton = [];
2621 | this.instance_material = [];
2622 |
2623 | };
2624 |
2625 | InstanceController.prototype.parse = function ( element ) {
2626 |
2627 | this.url = element.getAttribute('url').replace(/^#/, '');
2628 | this.skeleton = [];
2629 | this.instance_material = [];
2630 |
2631 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2632 |
2633 | var child = element.childNodes[ i ];
2634 | if ( child.nodeType !== 1 ) continue;
2635 |
2636 | switch ( child.nodeName ) {
2637 |
2638 | case 'skeleton':
2639 |
2640 | this.skeleton.push( child.textContent.replace(/^#/, '') );
2641 | break;
2642 |
2643 | case 'bind_material':
2644 |
2645 | var instances = child.querySelectorAll('instance_material');
2646 |
2647 | for ( var j = 0; j < instances.length; j ++ ) {
2648 |
2649 | var instance = instances[j];
2650 | this.instance_material.push( (new InstanceMaterial()).parse(instance) );
2651 |
2652 | }
2653 |
2654 |
2655 | break;
2656 |
2657 | case 'extra':
2658 | break;
2659 |
2660 | default:
2661 | break;
2662 |
2663 | }
2664 | }
2665 |
2666 | return this;
2667 |
2668 | };
2669 |
2670 | function InstanceMaterial () {
2671 |
2672 | this.symbol = "";
2673 | this.target = "";
2674 |
2675 | };
2676 |
2677 | InstanceMaterial.prototype.parse = function ( element ) {
2678 |
2679 | this.symbol = element.getAttribute('symbol');
2680 | this.target = element.getAttribute('target').replace(/^#/, '');
2681 | return this;
2682 |
2683 | };
2684 |
2685 | function InstanceGeometry() {
2686 |
2687 | this.url = "";
2688 | this.instance_material = [];
2689 |
2690 | };
2691 |
2692 | InstanceGeometry.prototype.parse = function ( element ) {
2693 |
2694 | this.url = element.getAttribute('url').replace(/^#/, '');
2695 | this.instance_material = [];
2696 |
2697 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2698 |
2699 | var child = element.childNodes[i];
2700 | if ( child.nodeType != 1 ) continue;
2701 |
2702 | if ( child.nodeName === 'bind_material' ) {
2703 |
2704 | var instances = child.querySelectorAll('instance_material');
2705 |
2706 | for ( var j = 0; j < instances.length; j ++ ) {
2707 |
2708 | var instance = instances[j];
2709 | this.instance_material.push( (new InstanceMaterial()).parse(instance) );
2710 |
2711 | }
2712 |
2713 | break;
2714 |
2715 | }
2716 |
2717 | }
2718 |
2719 | return this;
2720 |
2721 | };
2722 |
2723 | function Geometry() {
2724 |
2725 | this.id = "";
2726 | this.mesh = null;
2727 |
2728 | };
2729 |
2730 | Geometry.prototype.parse = function ( element ) {
2731 |
2732 | this.id = element.getAttribute('id');
2733 |
2734 | extractDoubleSided( this, element );
2735 |
2736 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2737 |
2738 | var child = element.childNodes[i];
2739 |
2740 | switch ( child.nodeName ) {
2741 |
2742 | case 'mesh':
2743 |
2744 | this.mesh = (new Mesh(this)).parse(child);
2745 | break;
2746 |
2747 | case 'extra':
2748 |
2749 | // console.log( child );
2750 | break;
2751 |
2752 | default:
2753 | break;
2754 | }
2755 | }
2756 |
2757 | return this;
2758 |
2759 | };
2760 |
2761 | function Mesh( geometry ) {
2762 |
2763 | this.geometry = geometry.id;
2764 | this.primitives = [];
2765 | this.vertices = null;
2766 | this.geometry3js = null;
2767 |
2768 | };
2769 |
2770 | Mesh.prototype.parse = function ( element ) {
2771 |
2772 | this.primitives = [];
2773 |
2774 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
2775 |
2776 | var child = element.childNodes[ i ];
2777 |
2778 | switch ( child.nodeName ) {
2779 |
2780 | case 'source':
2781 |
2782 | _source( child );
2783 | break;
2784 |
2785 | case 'vertices':
2786 |
2787 | this.vertices = ( new Vertices() ).parse( child );
2788 | break;
2789 |
2790 | case 'linestrips':
2791 |
2792 | this.primitives.push( ( new LineStrips().parse( child ) ) );
2793 | break;
2794 |
2795 | case 'triangles':
2796 |
2797 | this.primitives.push( ( new Triangles().parse( child ) ) );
2798 | break;
2799 |
2800 | case 'polygons':
2801 |
2802 | this.primitives.push( ( new Polygons().parse( child ) ) );
2803 | break;
2804 |
2805 | case 'polylist':
2806 |
2807 | this.primitives.push( ( new Polylist().parse( child ) ) );
2808 | break;
2809 |
2810 | default:
2811 | break;
2812 |
2813 | }
2814 |
2815 | }
2816 |
2817 | this.geometry3js = new THREE.Geometry();
2818 |
2819 | if ( this.vertices === null ) {
2820 |
2821 | // TODO (mrdoob): Study case when this is null (carrier.dae)
2822 |
2823 | return this;
2824 |
2825 | }
2826 |
2827 | var vertexData = sources[ this.vertices.input['POSITION'].source ].data;
2828 |
2829 | for ( var i = 0; i < vertexData.length; i += 3 ) {
2830 |
2831 | this.geometry3js.vertices.push( getConvertedVec3( vertexData, i ).clone() );
2832 |
2833 | }
2834 |
2835 | for ( var i = 0; i < this.primitives.length; i ++ ) {
2836 |
2837 | var primitive = this.primitives[ i ];
2838 | primitive.setVertices( this.vertices );
2839 | this.handlePrimitive( primitive, this.geometry3js );
2840 |
2841 | }
2842 |
2843 | if ( this.geometry3js.calcNormals ) {
2844 |
2845 | this.geometry3js.computeVertexNormals();
2846 | delete this.geometry3js.calcNormals;
2847 |
2848 | }
2849 |
2850 | return this;
2851 |
2852 | };
2853 |
2854 | Mesh.prototype.handlePrimitive = function ( primitive, geom ) {
2855 |
2856 | if ( primitive instanceof LineStrips ) {
2857 |
2858 | // TODO: Handle indices. Maybe easier with BufferGeometry?
2859 |
2860 | geom.isLineStrip = true;
2861 | return;
2862 |
2863 | }
2864 |
2865 | var j, k, pList = primitive.p, inputs = primitive.inputs;
2866 | var input, index, idx32;
2867 | var source, numParams;
2868 | var vcIndex = 0, vcount = 3, maxOffset = 0;
2869 | var texture_sets = [];
2870 |
2871 | for ( j = 0; j < inputs.length; j ++ ) {
2872 |
2873 | input = inputs[ j ];
2874 |
2875 | var offset = input.offset + 1;
2876 | maxOffset = (maxOffset < offset) ? offset : maxOffset;
2877 |
2878 | switch ( input.semantic ) {
2879 |
2880 | case 'TEXCOORD':
2881 | texture_sets.push( input.set );
2882 | break;
2883 |
2884 | }
2885 |
2886 | }
2887 |
2888 | for ( var pCount = 0; pCount < pList.length; ++ pCount ) {
2889 |
2890 | var p = pList[ pCount ], i = 0;
2891 |
2892 | while ( i < p.length ) {
2893 |
2894 | var vs = [];
2895 | var ns = [];
2896 | var ts = null;
2897 | var cs = [];
2898 |
2899 | if ( primitive.vcount ) {
2900 |
2901 | vcount = primitive.vcount.length ? primitive.vcount[ vcIndex ++ ] : primitive.vcount;
2902 |
2903 | } else {
2904 |
2905 | vcount = p.length / maxOffset;
2906 |
2907 | }
2908 |
2909 |
2910 | for ( j = 0; j < vcount; j ++ ) {
2911 |
2912 | for ( k = 0; k < inputs.length; k ++ ) {
2913 |
2914 | input = inputs[ k ];
2915 | source = sources[ input.source ];
2916 |
2917 | index = p[ i + ( j * maxOffset ) + input.offset ];
2918 | numParams = source.accessor.params.length;
2919 | idx32 = index * numParams;
2920 |
2921 | switch ( input.semantic ) {
2922 |
2923 | case 'VERTEX':
2924 |
2925 | vs.push( index );
2926 |
2927 | break;
2928 |
2929 | case 'NORMAL':
2930 |
2931 | ns.push( getConvertedVec3( source.data, idx32 ) );
2932 |
2933 | break;
2934 |
2935 | case 'TEXCOORD':
2936 |
2937 | ts = ts || { };
2938 | if ( ts[ input.set ] === undefined ) ts[ input.set ] = [];
2939 | // invert the V
2940 | ts[ input.set ].push( new THREE.Vector2( source.data[ idx32 ], source.data[ idx32 + 1 ] ) );
2941 |
2942 | break;
2943 |
2944 | case 'COLOR':
2945 |
2946 | cs.push( new THREE.Color().setRGB( source.data[ idx32 ], source.data[ idx32 + 1 ], source.data[ idx32 + 2 ] ) );
2947 |
2948 | break;
2949 |
2950 | default:
2951 |
2952 | break;
2953 |
2954 | }
2955 |
2956 | }
2957 |
2958 | }
2959 |
2960 | if ( ns.length === 0 ) {
2961 |
2962 | // check the vertices inputs
2963 | input = this.vertices.input.NORMAL;
2964 |
2965 | if ( input ) {
2966 |
2967 | source = sources[ input.source ];
2968 | numParams = source.accessor.params.length;
2969 |
2970 | for ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) {
2971 |
2972 | ns.push( getConvertedVec3( source.data, vs[ ndx ] * numParams ) );
2973 |
2974 | }
2975 |
2976 | } else {
2977 |
2978 | geom.calcNormals = true;
2979 |
2980 | }
2981 |
2982 | }
2983 |
2984 | if ( !ts ) {
2985 |
2986 | ts = { };
2987 | // check the vertices inputs
2988 | input = this.vertices.input.TEXCOORD;
2989 |
2990 | if ( input ) {
2991 |
2992 | texture_sets.push( input.set );
2993 | source = sources[ input.source ];
2994 | numParams = source.accessor.params.length;
2995 |
2996 | for ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) {
2997 |
2998 | idx32 = vs[ ndx ] * numParams;
2999 | if ( ts[ input.set ] === undefined ) ts[ input.set ] = [ ];
3000 | // invert the V
3001 | ts[ input.set ].push( new THREE.Vector2( source.data[ idx32 ], 1.0 - source.data[ idx32 + 1 ] ) );
3002 |
3003 | }
3004 |
3005 | }
3006 |
3007 | }
3008 |
3009 | if ( cs.length === 0 ) {
3010 |
3011 | // check the vertices inputs
3012 | input = this.vertices.input.COLOR;
3013 |
3014 | if ( input ) {
3015 |
3016 | source = sources[ input.source ];
3017 | numParams = source.accessor.params.length;
3018 |
3019 | for ( var ndx = 0, len = vs.length; ndx < len; ndx ++ ) {
3020 |
3021 | idx32 = vs[ ndx ] * numParams;
3022 | cs.push( new THREE.Color().setRGB( source.data[ idx32 ], source.data[ idx32 + 1 ], source.data[ idx32 + 2 ] ) );
3023 |
3024 | }
3025 |
3026 | }
3027 |
3028 | }
3029 |
3030 | var face = null, faces = [], uv, uvArr;
3031 |
3032 | if ( vcount === 3 ) {
3033 |
3034 | faces.push( new THREE.Face3( vs[0], vs[1], vs[2], ns, cs.length ? cs : new THREE.Color() ) );
3035 |
3036 | } else if ( vcount === 4 ) {
3037 |
3038 | faces.push( new THREE.Face3( vs[0], vs[1], vs[3], [ ns[0].clone(), ns[1].clone(), ns[3].clone() ], cs.length ? [ cs[0], cs[1], cs[3] ] : new THREE.Color() ) );
3039 |
3040 | faces.push( new THREE.Face3( vs[1], vs[2], vs[3], [ ns[1].clone(), ns[2].clone(), ns[3].clone() ], cs.length ? [ cs[1], cs[2], cs[3] ] : new THREE.Color() ) );
3041 |
3042 | } else if ( vcount > 4 && options.subdivideFaces ) {
3043 |
3044 | var clr = cs.length ? cs : new THREE.Color(),
3045 | vec1, vec2, vec3, v1, v2, norm;
3046 |
3047 | // subdivide into multiple Face3s
3048 |
3049 | for ( k = 1; k < vcount - 1; ) {
3050 |
3051 | faces.push( new THREE.Face3( vs[0], vs[k], vs[k + 1], [ ns[0].clone(), ns[k ++].clone(), ns[k].clone() ], clr ) );
3052 |
3053 | }
3054 |
3055 | }
3056 |
3057 | if ( faces.length ) {
3058 |
3059 | for ( var ndx = 0, len = faces.length; ndx < len; ndx ++ ) {
3060 |
3061 | face = faces[ndx];
3062 | face.daeMaterial = primitive.material;
3063 | geom.faces.push( face );
3064 |
3065 | for ( k = 0; k < texture_sets.length; k ++ ) {
3066 |
3067 | uv = ts[ texture_sets[k] ];
3068 |
3069 | if ( vcount > 4 ) {
3070 |
3071 | // Grab the right UVs for the vertices in this face
3072 | uvArr = [ uv[0], uv[ndx + 1], uv[ndx + 2] ];
3073 |
3074 | } else if ( vcount === 4 ) {
3075 |
3076 | if ( ndx === 0 ) {
3077 |
3078 | uvArr = [ uv[0], uv[1], uv[3] ];
3079 |
3080 | } else {
3081 |
3082 | uvArr = [ uv[1].clone(), uv[2], uv[3].clone() ];
3083 |
3084 | }
3085 |
3086 | } else {
3087 |
3088 | uvArr = [ uv[0], uv[1], uv[2] ];
3089 |
3090 | }
3091 |
3092 | if ( geom.faceVertexUvs[k] === undefined ) {
3093 |
3094 | geom.faceVertexUvs[k] = [];
3095 |
3096 | }
3097 |
3098 | geom.faceVertexUvs[k].push( uvArr );
3099 |
3100 | }
3101 |
3102 | }
3103 |
3104 | } else {
3105 |
3106 | console.log( 'dropped face with vcount ' + vcount + ' for geometry with id: ' + geom.id );
3107 |
3108 | }
3109 |
3110 | i += maxOffset * vcount;
3111 |
3112 | }
3113 |
3114 | }
3115 |
3116 | };
3117 |
3118 | function Polygons () {
3119 |
3120 | this.material = "";
3121 | this.count = 0;
3122 | this.inputs = [];
3123 | this.vcount = null;
3124 | this.p = [];
3125 | this.geometry = new THREE.Geometry();
3126 |
3127 | };
3128 |
3129 | Polygons.prototype.setVertices = function ( vertices ) {
3130 |
3131 | for ( var i = 0; i < this.inputs.length; i ++ ) {
3132 |
3133 | if ( this.inputs[ i ].source === vertices.id ) {
3134 |
3135 | this.inputs[ i ].source = vertices.input[ 'POSITION' ].source;
3136 |
3137 | }
3138 |
3139 | }
3140 |
3141 | };
3142 |
3143 | Polygons.prototype.parse = function ( element ) {
3144 |
3145 | this.material = element.getAttribute( 'material' );
3146 | this.count = _attr_as_int( element, 'count', 0 );
3147 |
3148 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3149 |
3150 | var child = element.childNodes[ i ];
3151 |
3152 | switch ( child.nodeName ) {
3153 |
3154 | case 'input':
3155 |
3156 | this.inputs.push( ( new Input() ).parse( element.childNodes[ i ] ) );
3157 | break;
3158 |
3159 | case 'vcount':
3160 |
3161 | this.vcount = _ints( child.textContent );
3162 | break;
3163 |
3164 | case 'p':
3165 |
3166 | this.p.push( _ints( child.textContent ) );
3167 | break;
3168 |
3169 | case 'ph':
3170 |
3171 | console.warn( 'polygon holes not yet supported!' );
3172 | break;
3173 |
3174 | default:
3175 | break;
3176 |
3177 | }
3178 |
3179 | }
3180 |
3181 | return this;
3182 |
3183 | };
3184 |
3185 | function Polylist () {
3186 |
3187 | Polygons.call( this );
3188 |
3189 | this.vcount = [];
3190 |
3191 | };
3192 |
3193 | Polylist.prototype = Object.create( Polygons.prototype );
3194 | Polylist.prototype.constructor = Polylist;
3195 |
3196 | function LineStrips() {
3197 |
3198 | Polygons.call( this );
3199 |
3200 | this.vcount = 1;
3201 |
3202 | };
3203 |
3204 | LineStrips.prototype = Object.create( Polygons.prototype );
3205 | LineStrips.prototype.constructor = LineStrips;
3206 |
3207 | function Triangles () {
3208 |
3209 | Polygons.call( this );
3210 |
3211 | this.vcount = 3;
3212 |
3213 | };
3214 |
3215 | Triangles.prototype = Object.create( Polygons.prototype );
3216 | Triangles.prototype.constructor = Triangles;
3217 |
3218 | function Accessor() {
3219 |
3220 | this.source = "";
3221 | this.count = 0;
3222 | this.stride = 0;
3223 | this.params = [];
3224 |
3225 | };
3226 |
3227 | Accessor.prototype.parse = function ( element ) {
3228 |
3229 | this.params = [];
3230 | this.source = element.getAttribute( 'source' );
3231 | this.count = _attr_as_int( element, 'count', 0 );
3232 | this.stride = _attr_as_int( element, 'stride', 0 );
3233 |
3234 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3235 |
3236 | var child = element.childNodes[ i ];
3237 |
3238 | if ( child.nodeName === 'param' ) {
3239 |
3240 | var param = {};
3241 | param[ 'name' ] = child.getAttribute( 'name' );
3242 | param[ 'type' ] = child.getAttribute( 'type' );
3243 | this.params.push( param );
3244 |
3245 | }
3246 |
3247 | }
3248 |
3249 | return this;
3250 |
3251 | };
3252 |
3253 | function Vertices() {
3254 |
3255 | this.input = {};
3256 |
3257 | };
3258 |
3259 | Vertices.prototype.parse = function ( element ) {
3260 |
3261 | this.id = element.getAttribute('id');
3262 |
3263 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3264 |
3265 | if ( element.childNodes[i].nodeName === 'input' ) {
3266 |
3267 | var input = ( new Input() ).parse( element.childNodes[ i ] );
3268 | this.input[ input.semantic ] = input;
3269 |
3270 | }
3271 |
3272 | }
3273 |
3274 | return this;
3275 |
3276 | };
3277 |
3278 | function Input () {
3279 |
3280 | this.semantic = "";
3281 | this.offset = 0;
3282 | this.source = "";
3283 | this.set = 0;
3284 |
3285 | };
3286 |
3287 | Input.prototype.parse = function ( element ) {
3288 |
3289 | this.semantic = element.getAttribute('semantic');
3290 | this.source = element.getAttribute('source').replace(/^#/, '');
3291 | this.set = _attr_as_int(element, 'set', -1);
3292 | this.offset = _attr_as_int(element, 'offset', 0);
3293 |
3294 | if ( this.semantic === 'TEXCOORD' && this.set < 0 ) {
3295 |
3296 | this.set = 0;
3297 |
3298 | }
3299 |
3300 | return this;
3301 |
3302 | };
3303 |
3304 | function Source ( id ) {
3305 |
3306 | this.id = id;
3307 | this.type = null;
3308 |
3309 | };
3310 |
3311 | Source.prototype.parse = function ( element ) {
3312 |
3313 | this.id = element.getAttribute( 'id' );
3314 |
3315 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3316 |
3317 | var child = element.childNodes[i];
3318 |
3319 | switch ( child.nodeName ) {
3320 |
3321 | case 'bool_array':
3322 |
3323 | this.data = _bools( child.textContent );
3324 | this.type = child.nodeName;
3325 | break;
3326 |
3327 | case 'float_array':
3328 |
3329 | this.data = _floats( child.textContent );
3330 | this.type = child.nodeName;
3331 | break;
3332 |
3333 | case 'int_array':
3334 |
3335 | this.data = _ints( child.textContent );
3336 | this.type = child.nodeName;
3337 | break;
3338 |
3339 | case 'IDREF_array':
3340 | case 'Name_array':
3341 |
3342 | this.data = _strings( child.textContent );
3343 | this.type = child.nodeName;
3344 | break;
3345 |
3346 | case 'technique_common':
3347 |
3348 | for ( var j = 0; j < child.childNodes.length; j ++ ) {
3349 |
3350 | if ( child.childNodes[ j ].nodeName === 'accessor' ) {
3351 |
3352 | this.accessor = ( new Accessor() ).parse( child.childNodes[ j ] );
3353 | break;
3354 |
3355 | }
3356 | }
3357 | break;
3358 |
3359 | default:
3360 | // console.log(child.nodeName);
3361 | break;
3362 |
3363 | }
3364 |
3365 | }
3366 |
3367 | return this;
3368 |
3369 | };
3370 |
3371 | Source.prototype.read = function () {
3372 |
3373 | var result = [];
3374 |
3375 | //for (var i = 0; i < this.accessor.params.length; i++) {
3376 |
3377 | var param = this.accessor.params[ 0 ];
3378 |
3379 | //console.log(param.name + " " + param.type);
3380 |
3381 | switch ( param.type ) {
3382 |
3383 | case 'IDREF':
3384 | case 'Name': case 'name':
3385 | case 'float':
3386 |
3387 | return this.data;
3388 |
3389 | case 'float4x4':
3390 |
3391 | for ( var j = 0; j < this.data.length; j += 16 ) {
3392 |
3393 | var s = this.data.slice( j, j + 16 );
3394 | var m = getConvertedMat4( s );
3395 | result.push( m );
3396 | }
3397 |
3398 | break;
3399 |
3400 | default:
3401 |
3402 | console.log( 'ColladaLoader: Source: Read dont know how to read ' + param.type + '.' );
3403 | break;
3404 |
3405 | }
3406 |
3407 | //}
3408 |
3409 | return result;
3410 |
3411 | };
3412 |
3413 | function Material () {
3414 |
3415 | this.id = "";
3416 | this.name = "";
3417 | this.instance_effect = null;
3418 |
3419 | };
3420 |
3421 | Material.prototype.parse = function ( element ) {
3422 |
3423 | this.id = element.getAttribute( 'id' );
3424 | this.name = element.getAttribute( 'name' );
3425 |
3426 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3427 |
3428 | if ( element.childNodes[ i ].nodeName === 'instance_effect' ) {
3429 |
3430 | this.instance_effect = ( new InstanceEffect() ).parse( element.childNodes[ i ] );
3431 | break;
3432 |
3433 | }
3434 |
3435 | }
3436 |
3437 | return this;
3438 |
3439 | };
3440 |
3441 | function ColorOrTexture () {
3442 |
3443 | this.color = new THREE.Color();
3444 | this.color.setRGB( Math.random(), Math.random(), Math.random() );
3445 | this.color.a = 1.0;
3446 |
3447 | this.texture = null;
3448 | this.texcoord = null;
3449 | this.texOpts = null;
3450 |
3451 | };
3452 |
3453 | ColorOrTexture.prototype.isColor = function () {
3454 |
3455 | return ( this.texture === null );
3456 |
3457 | };
3458 |
3459 | ColorOrTexture.prototype.isTexture = function () {
3460 |
3461 | return ( this.texture != null );
3462 |
3463 | };
3464 |
3465 | ColorOrTexture.prototype.parse = function ( element ) {
3466 |
3467 | if (element.nodeName === 'transparent') {
3468 |
3469 | this.opaque = element.getAttribute('opaque');
3470 |
3471 | }
3472 |
3473 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3474 |
3475 | var child = element.childNodes[ i ];
3476 | if ( child.nodeType != 1 ) continue;
3477 |
3478 | switch ( child.nodeName ) {
3479 |
3480 | case 'color':
3481 |
3482 | var rgba = _floats( child.textContent );
3483 | this.color = new THREE.Color();
3484 | this.color.setRGB( rgba[0], rgba[1], rgba[2] );
3485 | this.color.a = rgba[3];
3486 | break;
3487 |
3488 | case 'texture':
3489 |
3490 | this.texture = child.getAttribute('texture');
3491 | this.texcoord = child.getAttribute('texcoord');
3492 | // Defaults from:
3493 | // https://collada.org/mediawiki/index.php/Maya_texture_placement_MAYA_extension
3494 | this.texOpts = {
3495 | offsetU: 0,
3496 | offsetV: 0,
3497 | repeatU: 1,
3498 | repeatV: 1,
3499 | wrapU: 1,
3500 | wrapV: 1
3501 | };
3502 | this.parseTexture( child );
3503 | break;
3504 |
3505 | default:
3506 | break;
3507 |
3508 | }
3509 |
3510 | }
3511 |
3512 | return this;
3513 |
3514 | };
3515 |
3516 | ColorOrTexture.prototype.parseTexture = function ( element ) {
3517 |
3518 | if ( ! element.childNodes ) return this;
3519 |
3520 | // This should be supported by Maya, 3dsMax, and MotionBuilder
3521 |
3522 | if ( element.childNodes[1] && element.childNodes[1].nodeName === 'extra' ) {
3523 |
3524 | element = element.childNodes[1];
3525 |
3526 | if ( element.childNodes[1] && element.childNodes[1].nodeName === 'technique' ) {
3527 |
3528 | element = element.childNodes[1];
3529 |
3530 | }
3531 |
3532 | }
3533 |
3534 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3535 |
3536 | var child = element.childNodes[ i ];
3537 |
3538 | switch ( child.nodeName ) {
3539 |
3540 | case 'offsetU':
3541 | case 'offsetV':
3542 | case 'repeatU':
3543 | case 'repeatV':
3544 |
3545 | this.texOpts[ child.nodeName ] = parseFloat( child.textContent );
3546 |
3547 | break;
3548 |
3549 | case 'wrapU':
3550 | case 'wrapV':
3551 |
3552 | // some dae have a value of true which becomes NaN via parseInt
3553 |
3554 | if ( child.textContent.toUpperCase() === 'TRUE' ) {
3555 |
3556 | this.texOpts[ child.nodeName ] = 1;
3557 |
3558 | } else {
3559 |
3560 | this.texOpts[ child.nodeName ] = parseInt( child.textContent );
3561 |
3562 | }
3563 | break;
3564 |
3565 | default:
3566 |
3567 | this.texOpts[ child.nodeName ] = child.textContent;
3568 |
3569 | break;
3570 |
3571 | }
3572 |
3573 | }
3574 |
3575 | return this;
3576 |
3577 | };
3578 |
3579 | function Shader ( type, effect ) {
3580 |
3581 | this.type = type;
3582 | this.effect = effect;
3583 | this.material = null;
3584 |
3585 | };
3586 |
3587 | Shader.prototype.parse = function ( element ) {
3588 |
3589 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3590 |
3591 | var child = element.childNodes[ i ];
3592 | if ( child.nodeType != 1 ) continue;
3593 |
3594 | switch ( child.nodeName ) {
3595 |
3596 | case 'emission':
3597 | case 'diffuse':
3598 | case 'specular':
3599 | case 'transparent':
3600 |
3601 | this[ child.nodeName ] = ( new ColorOrTexture() ).parse( child );
3602 | break;
3603 |
3604 | case 'bump':
3605 |
3606 | // If 'bumptype' is 'heightfield', create a 'bump' property
3607 | // Else if 'bumptype' is 'normalmap', create a 'normal' property
3608 | // (Default to 'bump')
3609 | var bumpType = child.getAttribute( 'bumptype' );
3610 | if ( bumpType ) {
3611 | if ( bumpType.toLowerCase() === "heightfield" ) {
3612 | this[ 'bump' ] = ( new ColorOrTexture() ).parse( child );
3613 | } else if ( bumpType.toLowerCase() === "normalmap" ) {
3614 | this[ 'normal' ] = ( new ColorOrTexture() ).parse( child );
3615 | } else {
3616 | console.error( "Shader.prototype.parse: Invalid value for attribute 'bumptype' (" + bumpType + ") - valid bumptypes are 'HEIGHTFIELD' and 'NORMALMAP' - defaulting to 'HEIGHTFIELD'" );
3617 | this[ 'bump' ] = ( new ColorOrTexture() ).parse( child );
3618 | }
3619 | } else {
3620 | console.warn( "Shader.prototype.parse: Attribute 'bumptype' missing from bump node - defaulting to 'HEIGHTFIELD'" );
3621 | this[ 'bump' ] = ( new ColorOrTexture() ).parse( child );
3622 | }
3623 |
3624 | break;
3625 |
3626 | case 'shininess':
3627 | case 'reflectivity':
3628 | case 'index_of_refraction':
3629 | case 'transparency':
3630 |
3631 | var f = child.querySelectorAll('float');
3632 |
3633 | if ( f.length > 0 )
3634 | this[ child.nodeName ] = parseFloat( f[ 0 ].textContent );
3635 |
3636 | break;
3637 |
3638 | default:
3639 | break;
3640 |
3641 | }
3642 |
3643 | }
3644 |
3645 | this.create();
3646 | return this;
3647 |
3648 | };
3649 |
3650 | Shader.prototype.create = function() {
3651 |
3652 | var props = {};
3653 |
3654 | var transparent = false;
3655 |
3656 | if (this['transparency'] !== undefined && this['transparent'] !== undefined) {
3657 | // convert transparent color RBG to average value
3658 | var transparentColor = this['transparent'];
3659 | var transparencyLevel = (this.transparent.color.r + this.transparent.color.g + this.transparent.color.b) / 3 * this.transparency;
3660 |
3661 | if (transparencyLevel > 0) {
3662 | transparent = true;
3663 | props[ 'transparent' ] = true;
3664 | props[ 'opacity' ] = 1 - transparencyLevel;
3665 |
3666 | }
3667 |
3668 | }
3669 |
3670 | var keys = {
3671 | 'diffuse':'map',
3672 | 'ambient':'lightMap',
3673 | 'specular':'specularMap',
3674 | 'emission':'emissionMap',
3675 | 'bump':'bumpMap',
3676 | 'normal':'normalMap'
3677 | };
3678 |
3679 | for ( var prop in this ) {
3680 |
3681 | switch ( prop ) {
3682 |
3683 | case 'ambient':
3684 | case 'emission':
3685 | case 'diffuse':
3686 | case 'specular':
3687 | case 'bump':
3688 | case 'normal':
3689 |
3690 | var cot = this[ prop ];
3691 |
3692 | if ( cot instanceof ColorOrTexture ) {
3693 |
3694 | if ( cot.isTexture() ) {
3695 |
3696 | var samplerId = cot.texture;
3697 | var surfaceId = this.effect.sampler[samplerId];
3698 |
3699 | if ( surfaceId !== undefined && surfaceId.source !== undefined ) {
3700 |
3701 | var surface = this.effect.surface[surfaceId.source];
3702 |
3703 | if ( surface !== undefined ) {
3704 |
3705 | var image = images[ surface.init_from ];
3706 |
3707 | if ( image ) {
3708 |
3709 | var url = baseUrl + image.init_from;
3710 |
3711 | var texture;
3712 | var loader = THREE.Loader.Handlers.get( url );
3713 |
3714 | if ( loader !== null ) {
3715 |
3716 | texture = loader.load( url );
3717 |
3718 | } else {
3719 |
3720 | texture = new THREE.Texture();
3721 |
3722 | loadTextureImage( texture, url );
3723 |
3724 | }
3725 |
3726 | texture.wrapS = cot.texOpts.wrapU ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
3727 | texture.wrapT = cot.texOpts.wrapV ? THREE.RepeatWrapping : THREE.ClampToEdgeWrapping;
3728 | texture.offset.x = cot.texOpts.offsetU;
3729 | texture.offset.y = cot.texOpts.offsetV;
3730 | texture.repeat.x = cot.texOpts.repeatU;
3731 | texture.repeat.y = cot.texOpts.repeatV;
3732 | props[keys[prop]] = texture;
3733 |
3734 | // Texture with baked lighting?
3735 | if (prop === 'emission') props['emissive'] = 0xffffff;
3736 |
3737 | }
3738 |
3739 | }
3740 |
3741 | }
3742 |
3743 | } else if ( prop === 'diffuse' || !transparent ) {
3744 |
3745 | if ( prop === 'emission' ) {
3746 |
3747 | props[ 'emissive' ] = cot.color.getHex();
3748 |
3749 | } else {
3750 |
3751 | props[ prop ] = cot.color.getHex();
3752 |
3753 | }
3754 |
3755 | }
3756 |
3757 | }
3758 |
3759 | break;
3760 |
3761 | case 'shininess':
3762 |
3763 | props[ prop ] = this[ prop ];
3764 | break;
3765 |
3766 | case 'reflectivity':
3767 |
3768 | props[ prop ] = this[ prop ];
3769 | if ( props[ prop ] > 0.0 ) props['envMap'] = options.defaultEnvMap;
3770 | props['combine'] = THREE.MixOperation; //mix regular shading with reflective component
3771 | break;
3772 |
3773 | case 'index_of_refraction':
3774 |
3775 | props[ 'refractionRatio' ] = this[ prop ]; //TODO: "index_of_refraction" becomes "refractionRatio" in shader, but I'm not sure if the two are actually comparable
3776 | if ( this[ prop ] !== 1.0 ) props['envMap'] = options.defaultEnvMap;
3777 | break;
3778 |
3779 | case 'transparency':
3780 | // gets figured out up top
3781 | break;
3782 |
3783 | default:
3784 | break;
3785 |
3786 | }
3787 |
3788 | }
3789 |
3790 | props[ 'shading' ] = preferredShading;
3791 | props[ 'side' ] = this.effect.doubleSided ? THREE.DoubleSide : THREE.FrontSide;
3792 |
3793 | switch ( this.type ) {
3794 |
3795 | case 'constant':
3796 |
3797 | if (props.emissive != undefined) props.color = props.emissive;
3798 | this.material = new THREE.MeshBasicMaterial( props );
3799 | break;
3800 |
3801 | case 'phong':
3802 | case 'blinn':
3803 |
3804 | if (props.diffuse != undefined) props.color = props.diffuse;
3805 | this.material = new THREE.MeshPhongMaterial( props );
3806 | break;
3807 |
3808 | case 'lambert':
3809 | default:
3810 |
3811 | if (props.diffuse != undefined) props.color = props.diffuse;
3812 | this.material = new THREE.MeshLambertMaterial( props );
3813 | break;
3814 |
3815 | }
3816 |
3817 | return this.material;
3818 |
3819 | };
3820 |
3821 | function Surface ( effect ) {
3822 |
3823 | this.effect = effect;
3824 | this.init_from = null;
3825 | this.format = null;
3826 |
3827 | };
3828 |
3829 | Surface.prototype.parse = function ( element ) {
3830 |
3831 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3832 |
3833 | var child = element.childNodes[ i ];
3834 | if ( child.nodeType != 1 ) continue;
3835 |
3836 | switch ( child.nodeName ) {
3837 |
3838 | case 'init_from':
3839 |
3840 | this.init_from = child.textContent;
3841 | break;
3842 |
3843 | case 'format':
3844 |
3845 | this.format = child.textContent;
3846 | break;
3847 |
3848 | default:
3849 |
3850 | console.log( "unhandled Surface prop: " + child.nodeName );
3851 | break;
3852 |
3853 | }
3854 |
3855 | }
3856 |
3857 | return this;
3858 |
3859 | };
3860 |
3861 | function Sampler2D ( effect ) {
3862 |
3863 | this.effect = effect;
3864 | this.source = null;
3865 | this.wrap_s = null;
3866 | this.wrap_t = null;
3867 | this.minfilter = null;
3868 | this.magfilter = null;
3869 | this.mipfilter = null;
3870 |
3871 | };
3872 |
3873 | Sampler2D.prototype.parse = function ( element ) {
3874 |
3875 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3876 |
3877 | var child = element.childNodes[ i ];
3878 | if ( child.nodeType != 1 ) continue;
3879 |
3880 | switch ( child.nodeName ) {
3881 |
3882 | case 'source':
3883 |
3884 | this.source = child.textContent;
3885 | break;
3886 |
3887 | case 'minfilter':
3888 |
3889 | this.minfilter = child.textContent;
3890 | break;
3891 |
3892 | case 'magfilter':
3893 |
3894 | this.magfilter = child.textContent;
3895 | break;
3896 |
3897 | case 'mipfilter':
3898 |
3899 | this.mipfilter = child.textContent;
3900 | break;
3901 |
3902 | case 'wrap_s':
3903 |
3904 | this.wrap_s = child.textContent;
3905 | break;
3906 |
3907 | case 'wrap_t':
3908 |
3909 | this.wrap_t = child.textContent;
3910 | break;
3911 |
3912 | default:
3913 |
3914 | console.log( "unhandled Sampler2D prop: " + child.nodeName );
3915 | break;
3916 |
3917 | }
3918 |
3919 | }
3920 |
3921 | return this;
3922 |
3923 | };
3924 |
3925 | function Effect () {
3926 |
3927 | this.id = "";
3928 | this.name = "";
3929 | this.shader = null;
3930 | this.surface = {};
3931 | this.sampler = {};
3932 |
3933 | };
3934 |
3935 | Effect.prototype.create = function () {
3936 |
3937 | if ( this.shader === null ) {
3938 |
3939 | return null;
3940 |
3941 | }
3942 |
3943 | };
3944 |
3945 | Effect.prototype.parse = function ( element ) {
3946 |
3947 | this.id = element.getAttribute( 'id' );
3948 | this.name = element.getAttribute( 'name' );
3949 |
3950 | extractDoubleSided( this, element );
3951 |
3952 | this.shader = null;
3953 |
3954 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3955 |
3956 | var child = element.childNodes[ i ];
3957 | if ( child.nodeType != 1 ) continue;
3958 |
3959 | switch ( child.nodeName ) {
3960 |
3961 | case 'profile_COMMON':
3962 |
3963 | this.parseTechnique( this.parseProfileCOMMON( child ) );
3964 | break;
3965 |
3966 | default:
3967 | break;
3968 |
3969 | }
3970 |
3971 | }
3972 |
3973 | return this;
3974 |
3975 | };
3976 |
3977 | Effect.prototype.parseNewparam = function ( element ) {
3978 |
3979 | var sid = element.getAttribute( 'sid' );
3980 |
3981 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
3982 |
3983 | var child = element.childNodes[ i ];
3984 | if ( child.nodeType != 1 ) continue;
3985 |
3986 | switch ( child.nodeName ) {
3987 |
3988 | case 'surface':
3989 |
3990 | this.surface[sid] = ( new Surface( this ) ).parse( child );
3991 | break;
3992 |
3993 | case 'sampler2D':
3994 |
3995 | this.sampler[sid] = ( new Sampler2D( this ) ).parse( child );
3996 | break;
3997 |
3998 | case 'extra':
3999 |
4000 | break;
4001 |
4002 | default:
4003 |
4004 | console.log( child.nodeName );
4005 | break;
4006 |
4007 | }
4008 |
4009 | }
4010 |
4011 | };
4012 |
4013 | Effect.prototype.parseProfileCOMMON = function ( element ) {
4014 |
4015 | var technique;
4016 |
4017 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4018 |
4019 | var child = element.childNodes[ i ];
4020 |
4021 | if ( child.nodeType != 1 ) continue;
4022 |
4023 | switch ( child.nodeName ) {
4024 |
4025 | case 'profile_COMMON':
4026 |
4027 | this.parseProfileCOMMON( child );
4028 | break;
4029 |
4030 | case 'technique':
4031 |
4032 | technique = child;
4033 | break;
4034 |
4035 | case 'newparam':
4036 |
4037 | this.parseNewparam( child );
4038 | break;
4039 |
4040 | case 'image':
4041 |
4042 | var _image = ( new _Image() ).parse( child );
4043 | images[ _image.id ] = _image;
4044 | break;
4045 |
4046 | case 'extra':
4047 | break;
4048 |
4049 | default:
4050 |
4051 | console.log( child.nodeName );
4052 | break;
4053 |
4054 | }
4055 |
4056 | }
4057 |
4058 | return technique;
4059 |
4060 | };
4061 |
4062 | Effect.prototype.parseTechnique = function ( element ) {
4063 |
4064 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4065 |
4066 | var child = element.childNodes[i];
4067 | if ( child.nodeType != 1 ) continue;
4068 |
4069 | switch ( child.nodeName ) {
4070 |
4071 | case 'constant':
4072 | case 'lambert':
4073 | case 'blinn':
4074 | case 'phong':
4075 |
4076 | this.shader = ( new Shader( child.nodeName, this ) ).parse( child );
4077 | break;
4078 | case 'extra':
4079 | this.parseExtra(child);
4080 | break;
4081 | default:
4082 | break;
4083 |
4084 | }
4085 |
4086 | }
4087 |
4088 | };
4089 |
4090 | Effect.prototype.parseExtra = function ( element ) {
4091 |
4092 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4093 |
4094 | var child = element.childNodes[i];
4095 | if ( child.nodeType != 1 ) continue;
4096 |
4097 | switch ( child.nodeName ) {
4098 |
4099 | case 'technique':
4100 | this.parseExtraTechnique( child );
4101 | break;
4102 | default:
4103 | break;
4104 |
4105 | }
4106 |
4107 | }
4108 |
4109 | };
4110 |
4111 | Effect.prototype.parseExtraTechnique = function ( element ) {
4112 |
4113 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4114 |
4115 | var child = element.childNodes[i];
4116 | if ( child.nodeType != 1 ) continue;
4117 |
4118 | switch ( child.nodeName ) {
4119 |
4120 | case 'bump':
4121 | this.shader.parse( element );
4122 | break;
4123 | default:
4124 | break;
4125 |
4126 | }
4127 |
4128 | }
4129 |
4130 | };
4131 |
4132 | function InstanceEffect () {
4133 |
4134 | this.url = "";
4135 |
4136 | };
4137 |
4138 | InstanceEffect.prototype.parse = function ( element ) {
4139 |
4140 | this.url = element.getAttribute( 'url' ).replace( /^#/, '' );
4141 | return this;
4142 |
4143 | };
4144 |
4145 | function Animation() {
4146 |
4147 | this.id = "";
4148 | this.name = "";
4149 | this.source = {};
4150 | this.sampler = [];
4151 | this.channel = [];
4152 |
4153 | };
4154 |
4155 | Animation.prototype.parse = function ( element ) {
4156 |
4157 | this.id = element.getAttribute( 'id' );
4158 | this.name = element.getAttribute( 'name' );
4159 | this.source = {};
4160 |
4161 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4162 |
4163 | var child = element.childNodes[ i ];
4164 |
4165 | if ( child.nodeType != 1 ) continue;
4166 |
4167 | switch ( child.nodeName ) {
4168 |
4169 | case 'animation':
4170 |
4171 | var anim = ( new Animation() ).parse( child );
4172 |
4173 | for ( var src in anim.source ) {
4174 |
4175 | this.source[ src ] = anim.source[ src ];
4176 |
4177 | }
4178 |
4179 | for ( var j = 0; j < anim.channel.length; j ++ ) {
4180 |
4181 | this.channel.push( anim.channel[ j ] );
4182 | this.sampler.push( anim.sampler[ j ] );
4183 |
4184 | }
4185 |
4186 | break;
4187 |
4188 | case 'source':
4189 |
4190 | var src = ( new Source() ).parse( child );
4191 | this.source[ src.id ] = src;
4192 | break;
4193 |
4194 | case 'sampler':
4195 |
4196 | this.sampler.push( ( new Sampler( this ) ).parse( child ) );
4197 | break;
4198 |
4199 | case 'channel':
4200 |
4201 | this.channel.push( ( new Channel( this ) ).parse( child ) );
4202 | break;
4203 |
4204 | default:
4205 | break;
4206 |
4207 | }
4208 |
4209 | }
4210 |
4211 | return this;
4212 |
4213 | };
4214 |
4215 | function Channel( animation ) {
4216 |
4217 | this.animation = animation;
4218 | this.source = "";
4219 | this.target = "";
4220 | this.fullSid = null;
4221 | this.sid = null;
4222 | this.dotSyntax = null;
4223 | this.arrSyntax = null;
4224 | this.arrIndices = null;
4225 | this.member = null;
4226 |
4227 | };
4228 |
4229 | Channel.prototype.parse = function ( element ) {
4230 |
4231 | this.source = element.getAttribute( 'source' ).replace( /^#/, '' );
4232 | this.target = element.getAttribute( 'target' );
4233 |
4234 | var parts = this.target.split( '/' );
4235 |
4236 | var id = parts.shift();
4237 | var sid = parts.shift();
4238 |
4239 | var dotSyntax = ( sid.indexOf(".") >= 0 );
4240 | var arrSyntax = ( sid.indexOf("(") >= 0 );
4241 |
4242 | if ( dotSyntax ) {
4243 |
4244 | parts = sid.split(".");
4245 | this.sid = parts.shift();
4246 | this.member = parts.shift();
4247 |
4248 | } else if ( arrSyntax ) {
4249 |
4250 | var arrIndices = sid.split("(");
4251 | this.sid = arrIndices.shift();
4252 |
4253 | for (var j = 0; j < arrIndices.length; j ++ ) {
4254 |
4255 | arrIndices[j] = parseInt( arrIndices[j].replace(/\)/, '') );
4256 |
4257 | }
4258 |
4259 | this.arrIndices = arrIndices;
4260 |
4261 | } else {
4262 |
4263 | this.sid = sid;
4264 |
4265 | }
4266 |
4267 | this.fullSid = sid;
4268 | this.dotSyntax = dotSyntax;
4269 | this.arrSyntax = arrSyntax;
4270 |
4271 | return this;
4272 |
4273 | };
4274 |
4275 | function Sampler ( animation ) {
4276 |
4277 | this.id = "";
4278 | this.animation = animation;
4279 | this.inputs = [];
4280 | this.input = null;
4281 | this.output = null;
4282 | this.strideOut = null;
4283 | this.interpolation = null;
4284 | this.startTime = null;
4285 | this.endTime = null;
4286 | this.duration = 0;
4287 |
4288 | };
4289 |
4290 | Sampler.prototype.parse = function ( element ) {
4291 |
4292 | this.id = element.getAttribute( 'id' );
4293 | this.inputs = [];
4294 |
4295 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4296 |
4297 | var child = element.childNodes[ i ];
4298 | if ( child.nodeType != 1 ) continue;
4299 |
4300 | switch ( child.nodeName ) {
4301 |
4302 | case 'input':
4303 |
4304 | this.inputs.push( (new Input()).parse( child ) );
4305 | break;
4306 |
4307 | default:
4308 | break;
4309 |
4310 | }
4311 |
4312 | }
4313 |
4314 | return this;
4315 |
4316 | };
4317 |
4318 | Sampler.prototype.create = function () {
4319 |
4320 | for ( var i = 0; i < this.inputs.length; i ++ ) {
4321 |
4322 | var input = this.inputs[ i ];
4323 | var source = this.animation.source[ input.source ];
4324 |
4325 | switch ( input.semantic ) {
4326 |
4327 | case 'INPUT':
4328 |
4329 | this.input = source.read();
4330 | break;
4331 |
4332 | case 'OUTPUT':
4333 |
4334 | this.output = source.read();
4335 | this.strideOut = source.accessor.stride;
4336 | break;
4337 |
4338 | case 'INTERPOLATION':
4339 |
4340 | this.interpolation = source.read();
4341 | break;
4342 |
4343 | case 'IN_TANGENT':
4344 |
4345 | break;
4346 |
4347 | case 'OUT_TANGENT':
4348 |
4349 | break;
4350 |
4351 | default:
4352 |
4353 | console.log(input.semantic);
4354 | break;
4355 |
4356 | }
4357 |
4358 | }
4359 |
4360 | this.startTime = 0;
4361 | this.endTime = 0;
4362 | this.duration = 0;
4363 |
4364 | if ( this.input.length ) {
4365 |
4366 | this.startTime = 100000000;
4367 | this.endTime = -100000000;
4368 |
4369 | for ( var i = 0; i < this.input.length; i ++ ) {
4370 |
4371 | this.startTime = Math.min( this.startTime, this.input[ i ] );
4372 | this.endTime = Math.max( this.endTime, this.input[ i ] );
4373 |
4374 | }
4375 |
4376 | this.duration = this.endTime - this.startTime;
4377 |
4378 | }
4379 |
4380 | };
4381 |
4382 | Sampler.prototype.getData = function ( type, ndx, member ) {
4383 |
4384 | var data;
4385 |
4386 | if ( type === 'matrix' && this.strideOut === 16 ) {
4387 |
4388 | data = this.output[ ndx ];
4389 |
4390 | } else if ( this.strideOut > 1 ) {
4391 |
4392 | data = [];
4393 | ndx *= this.strideOut;
4394 |
4395 | for ( var i = 0; i < this.strideOut; ++ i ) {
4396 |
4397 | data[ i ] = this.output[ ndx + i ];
4398 |
4399 | }
4400 |
4401 | if ( this.strideOut === 3 ) {
4402 |
4403 | switch ( type ) {
4404 |
4405 | case 'rotate':
4406 | case 'translate':
4407 |
4408 | fixCoords( data, -1 );
4409 | break;
4410 |
4411 | case 'scale':
4412 |
4413 | fixCoords( data, 1 );
4414 | break;
4415 |
4416 | }
4417 |
4418 | } else if ( this.strideOut === 4 && type === 'matrix' ) {
4419 |
4420 | fixCoords( data, -1 );
4421 |
4422 | }
4423 |
4424 | } else {
4425 |
4426 | data = this.output[ ndx ];
4427 |
4428 | if ( member && type === 'translate' ) {
4429 | data = getConvertedTranslation( member, data );
4430 | }
4431 |
4432 | }
4433 |
4434 | return data;
4435 |
4436 | };
4437 |
4438 | function Key ( time ) {
4439 |
4440 | this.targets = [];
4441 | this.time = time;
4442 |
4443 | };
4444 |
4445 | Key.prototype.addTarget = function ( fullSid, transform, member, data ) {
4446 |
4447 | this.targets.push( {
4448 | sid: fullSid,
4449 | member: member,
4450 | transform: transform,
4451 | data: data
4452 | } );
4453 |
4454 | };
4455 |
4456 | Key.prototype.apply = function ( opt_sid ) {
4457 |
4458 | for ( var i = 0; i < this.targets.length; ++ i ) {
4459 |
4460 | var target = this.targets[ i ];
4461 |
4462 | if ( !opt_sid || target.sid === opt_sid ) {
4463 |
4464 | target.transform.update( target.data, target.member );
4465 |
4466 | }
4467 |
4468 | }
4469 |
4470 | };
4471 |
4472 | Key.prototype.getTarget = function ( fullSid ) {
4473 |
4474 | for ( var i = 0; i < this.targets.length; ++ i ) {
4475 |
4476 | if ( this.targets[ i ].sid === fullSid ) {
4477 |
4478 | return this.targets[ i ];
4479 |
4480 | }
4481 |
4482 | }
4483 |
4484 | return null;
4485 |
4486 | };
4487 |
4488 | Key.prototype.hasTarget = function ( fullSid ) {
4489 |
4490 | for ( var i = 0; i < this.targets.length; ++ i ) {
4491 |
4492 | if ( this.targets[ i ].sid === fullSid ) {
4493 |
4494 | return true;
4495 |
4496 | }
4497 |
4498 | }
4499 |
4500 | return false;
4501 |
4502 | };
4503 |
4504 | // TODO: Currently only doing linear interpolation. Should support full COLLADA spec.
4505 | Key.prototype.interpolate = function ( nextKey, time ) {
4506 |
4507 | for ( var i = 0, l = this.targets.length; i < l; i ++ ) {
4508 |
4509 | var target = this.targets[ i ],
4510 | nextTarget = nextKey.getTarget( target.sid ),
4511 | data;
4512 |
4513 | if ( target.transform.type !== 'matrix' && nextTarget ) {
4514 |
4515 | var scale = ( time - this.time ) / ( nextKey.time - this.time ),
4516 | nextData = nextTarget.data,
4517 | prevData = target.data;
4518 |
4519 | if ( scale < 0 ) scale = 0;
4520 | if ( scale > 1 ) scale = 1;
4521 |
4522 | if ( prevData.length ) {
4523 |
4524 | data = [];
4525 |
4526 | for ( var j = 0; j < prevData.length; ++ j ) {
4527 |
4528 | data[ j ] = prevData[ j ] + ( nextData[ j ] - prevData[ j ] ) * scale;
4529 |
4530 | }
4531 |
4532 | } else {
4533 |
4534 | data = prevData + ( nextData - prevData ) * scale;
4535 |
4536 | }
4537 |
4538 | } else {
4539 |
4540 | data = target.data;
4541 |
4542 | }
4543 |
4544 | target.transform.update( data, target.member );
4545 |
4546 | }
4547 |
4548 | };
4549 |
4550 | // Camera
4551 | function Camera() {
4552 |
4553 | this.id = "";
4554 | this.name = "";
4555 | this.technique = "";
4556 |
4557 | };
4558 |
4559 | Camera.prototype.parse = function ( element ) {
4560 |
4561 | this.id = element.getAttribute( 'id' );
4562 | this.name = element.getAttribute( 'name' );
4563 |
4564 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4565 |
4566 | var child = element.childNodes[ i ];
4567 | if ( child.nodeType != 1 ) continue;
4568 |
4569 | switch ( child.nodeName ) {
4570 |
4571 | case 'optics':
4572 |
4573 | this.parseOptics( child );
4574 | break;
4575 |
4576 | default:
4577 | break;
4578 |
4579 | }
4580 |
4581 | }
4582 |
4583 | return this;
4584 |
4585 | };
4586 |
4587 | Camera.prototype.parseOptics = function ( element ) {
4588 |
4589 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4590 |
4591 | if ( element.childNodes[ i ].nodeName === 'technique_common' ) {
4592 |
4593 | var technique = element.childNodes[ i ];
4594 |
4595 | for ( var j = 0; j < technique.childNodes.length; j ++ ) {
4596 |
4597 | this.technique = technique.childNodes[ j ].nodeName;
4598 |
4599 | if ( this.technique === 'perspective' ) {
4600 |
4601 | var perspective = technique.childNodes[ j ];
4602 |
4603 | for ( var k = 0; k < perspective.childNodes.length; k ++ ) {
4604 |
4605 | var param = perspective.childNodes[ k ];
4606 |
4607 | switch ( param.nodeName ) {
4608 |
4609 | case 'yfov':
4610 | this.yfov = param.textContent;
4611 | break;
4612 | case 'xfov':
4613 | this.xfov = param.textContent;
4614 | break;
4615 | case 'znear':
4616 | this.znear = param.textContent;
4617 | break;
4618 | case 'zfar':
4619 | this.zfar = param.textContent;
4620 | break;
4621 | case 'aspect_ratio':
4622 | this.aspect_ratio = param.textContent;
4623 | break;
4624 |
4625 | }
4626 |
4627 | }
4628 |
4629 | } else if ( this.technique === 'orthographic' ) {
4630 |
4631 | var orthographic = technique.childNodes[ j ];
4632 |
4633 | for ( var k = 0; k < orthographic.childNodes.length; k ++ ) {
4634 |
4635 | var param = orthographic.childNodes[ k ];
4636 |
4637 | switch ( param.nodeName ) {
4638 |
4639 | case 'xmag':
4640 | this.xmag = param.textContent;
4641 | break;
4642 | case 'ymag':
4643 | this.ymag = param.textContent;
4644 | break;
4645 | case 'znear':
4646 | this.znear = param.textContent;
4647 | break;
4648 | case 'zfar':
4649 | this.zfar = param.textContent;
4650 | break;
4651 | case 'aspect_ratio':
4652 | this.aspect_ratio = param.textContent;
4653 | break;
4654 |
4655 | }
4656 |
4657 | }
4658 |
4659 | }
4660 |
4661 | }
4662 |
4663 | }
4664 |
4665 | }
4666 |
4667 | return this;
4668 |
4669 | };
4670 |
4671 | function InstanceCamera() {
4672 |
4673 | this.url = "";
4674 |
4675 | };
4676 |
4677 | InstanceCamera.prototype.parse = function ( element ) {
4678 |
4679 | this.url = element.getAttribute('url').replace(/^#/, '');
4680 |
4681 | return this;
4682 |
4683 | };
4684 |
4685 | // Light
4686 |
4687 | function Light() {
4688 |
4689 | this.id = "";
4690 | this.name = "";
4691 | this.technique = "";
4692 |
4693 | };
4694 |
4695 | Light.prototype.parse = function ( element ) {
4696 |
4697 | this.id = element.getAttribute( 'id' );
4698 | this.name = element.getAttribute( 'name' );
4699 |
4700 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4701 |
4702 | var child = element.childNodes[ i ];
4703 | if ( child.nodeType != 1 ) continue;
4704 |
4705 | switch ( child.nodeName ) {
4706 |
4707 | case 'technique_common':
4708 |
4709 | this.parseCommon( child );
4710 | break;
4711 |
4712 | case 'technique':
4713 |
4714 | this.parseTechnique( child );
4715 | break;
4716 |
4717 | default:
4718 | break;
4719 |
4720 | }
4721 |
4722 | }
4723 |
4724 | return this;
4725 |
4726 | };
4727 |
4728 | Light.prototype.parseCommon = function ( element ) {
4729 |
4730 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4731 |
4732 | switch ( element.childNodes[ i ].nodeName ) {
4733 |
4734 | case 'directional':
4735 | case 'point':
4736 | case 'spot':
4737 | case 'ambient':
4738 |
4739 | this.technique = element.childNodes[ i ].nodeName;
4740 |
4741 | var light = element.childNodes[ i ];
4742 |
4743 | for ( var j = 0; j < light.childNodes.length; j ++ ) {
4744 |
4745 | var child = light.childNodes[j];
4746 |
4747 | switch ( child.nodeName ) {
4748 |
4749 | case 'color':
4750 |
4751 | var rgba = _floats( child.textContent );
4752 | this.color = new THREE.Color(0);
4753 | this.color.setRGB( rgba[0], rgba[1], rgba[2] );
4754 | this.color.a = rgba[3];
4755 | break;
4756 |
4757 | case 'falloff_angle':
4758 |
4759 | this.falloff_angle = parseFloat( child.textContent );
4760 | break;
4761 |
4762 | case 'quadratic_attenuation':
4763 | var f = parseFloat( child.textContent );
4764 | this.distance = f ? Math.sqrt( 1 / f ) : 0;
4765 | }
4766 |
4767 | }
4768 |
4769 | }
4770 |
4771 | }
4772 |
4773 | return this;
4774 |
4775 | };
4776 |
4777 | Light.prototype.parseTechnique = function ( element ) {
4778 |
4779 | this.profile = element.getAttribute( 'profile' );
4780 |
4781 | for ( var i = 0; i < element.childNodes.length; i ++ ) {
4782 |
4783 | var child = element.childNodes[ i ];
4784 |
4785 | switch ( child.nodeName ) {
4786 |
4787 | case 'intensity':
4788 |
4789 | this.intensity = parseFloat(child.textContent);
4790 | break;
4791 |
4792 | }
4793 |
4794 | }
4795 |
4796 | return this;
4797 |
4798 | };
4799 |
4800 | function InstanceLight() {
4801 |
4802 | this.url = "";
4803 |
4804 | };
4805 |
4806 | InstanceLight.prototype.parse = function ( element ) {
4807 |
4808 | this.url = element.getAttribute('url').replace(/^#/, '');
4809 |
4810 | return this;
4811 |
4812 | };
4813 |
4814 | function KinematicsModel( ) {
4815 |
4816 | this.id = '';
4817 | this.name = '';
4818 | this.joints = [];
4819 | this.links = [];
4820 |
4821 | }
4822 |
4823 | KinematicsModel.prototype.parse = function( element ) {
4824 |
4825 | this.id = element.getAttribute('id');
4826 | this.name = element.getAttribute('name');
4827 | this.joints = [];
4828 | this.links = [];
4829 |
4830 | for (var i = 0; i < element.childNodes.length; i ++ ) {
4831 |
4832 | var child = element.childNodes[ i ];
4833 | if ( child.nodeType != 1 ) continue;
4834 |
4835 | switch ( child.nodeName ) {
4836 |
4837 | case 'technique_common':
4838 |
4839 | this.parseCommon(child);
4840 | break;
4841 |
4842 | default:
4843 | break;
4844 |
4845 | }
4846 |
4847 | }
4848 |
4849 | return this;
4850 |
4851 | };
4852 |
4853 | KinematicsModel.prototype.parseCommon = function( element ) {
4854 |
4855 | for (var i = 0; i < element.childNodes.length; i ++ ) {
4856 |
4857 | var child = element.childNodes[ i ];
4858 | if ( child.nodeType != 1 ) continue;
4859 |
4860 | switch ( element.childNodes[ i ].nodeName ) {
4861 |
4862 | case 'joint':
4863 | this.joints.push( (new Joint()).parse(child) );
4864 | break;
4865 |
4866 | case 'link':
4867 | this.links.push( (new Link()).parse(child) );
4868 | break;
4869 |
4870 | default:
4871 | break;
4872 |
4873 | }
4874 |
4875 | }
4876 |
4877 | return this;
4878 |
4879 | };
4880 |
4881 | function Joint( ) {
4882 |
4883 | this.sid = '';
4884 | this.name = '';
4885 | this.axis = new THREE.Vector3();
4886 | this.limits = {
4887 | min: 0,
4888 | max: 0
4889 | };
4890 | this.type = '';
4891 | this.static = false;
4892 | this.zeroPosition = 0.0;
4893 | this.middlePosition = 0.0;
4894 |
4895 | }
4896 |
4897 | Joint.prototype.parse = function( element ) {
4898 |
4899 | this.sid = element.getAttribute('sid');
4900 | this.name = element.getAttribute('name');
4901 | this.axis = new THREE.Vector3();
4902 | this.limits = {
4903 | min: 0,
4904 | max: 0
4905 | };
4906 | this.type = '';
4907 | this.static = false;
4908 | this.zeroPosition = 0.0;
4909 | this.middlePosition = 0.0;
4910 |
4911 | var axisElement = element.querySelector('axis');
4912 | var _axis = _floats(axisElement.textContent);
4913 | this.axis = getConvertedVec3(_axis, 0);
4914 |
4915 | var min = element.querySelector('limits min') ? parseFloat(element.querySelector('limits min').textContent) : -360;
4916 | var max = element.querySelector('limits max') ? parseFloat(element.querySelector('limits max').textContent) : 360;
4917 |
4918 | this.limits = {
4919 | min: min,
4920 | max: max
4921 | };
4922 |
4923 | var jointTypes = [ 'prismatic', 'revolute' ];
4924 | for (var i = 0; i < jointTypes.length; i ++ ) {
4925 |
4926 | var type = jointTypes[ i ];
4927 |
4928 | var jointElement = element.querySelector(type);
4929 |
4930 | if ( jointElement ) {
4931 |
4932 | this.type = type;
4933 |
4934 | }
4935 |
4936 | }
4937 |
4938 | // if the min is equal to or somehow greater than the max, consider the joint static
4939 | if ( this.limits.min >= this.limits.max ) {
4940 |
4941 | this.static = true;
4942 |
4943 | }
4944 |
4945 | this.middlePosition = (this.limits.min + this.limits.max) / 2.0;
4946 | return this;
4947 |
4948 | };
4949 |
4950 | function Link( ) {
4951 |
4952 | this.sid = '';
4953 | this.name = '';
4954 | this.transforms = [];
4955 | this.attachments = [];
4956 |
4957 | }
4958 |
4959 | Link.prototype.parse = function( element ) {
4960 |
4961 | this.sid = element.getAttribute('sid');
4962 | this.name = element.getAttribute('name');
4963 | this.transforms = [];
4964 | this.attachments = [];
4965 |
4966 | for (var i = 0; i < element.childNodes.length; i ++ ) {
4967 |
4968 | var child = element.childNodes[ i ];
4969 | if ( child.nodeType != 1 ) continue;
4970 |
4971 | switch ( child.nodeName ) {
4972 |
4973 | case 'attachment_full':
4974 | this.attachments.push( (new Attachment()).parse(child) );
4975 | break;
4976 |
4977 | case 'rotate':
4978 | case 'translate':
4979 | case 'matrix':
4980 |
4981 | this.transforms.push( (new Transform()).parse(child) );
4982 | break;
4983 |
4984 | default:
4985 |
4986 | break;
4987 |
4988 | }
4989 |
4990 | }
4991 |
4992 | return this;
4993 |
4994 | };
4995 |
4996 | function Attachment( ) {
4997 |
4998 | this.joint = '';
4999 | this.transforms = [];
5000 | this.links = [];
5001 |
5002 | }
5003 |
5004 | Attachment.prototype.parse = function( element ) {
5005 |
5006 | this.joint = element.getAttribute('joint').split('/').pop();
5007 | this.links = [];
5008 |
5009 | for (var i = 0; i < element.childNodes.length; i ++ ) {
5010 |
5011 | var child = element.childNodes[ i ];
5012 | if ( child.nodeType != 1 ) continue;
5013 |
5014 | switch ( child.nodeName ) {
5015 |
5016 | case 'link':
5017 | this.links.push( (new Link()).parse(child) );
5018 | break;
5019 |
5020 | case 'rotate':
5021 | case 'translate':
5022 | case 'matrix':
5023 |
5024 | this.transforms.push( (new Transform()).parse(child) );
5025 | break;
5026 |
5027 | default:
5028 |
5029 | break;
5030 |
5031 | }
5032 |
5033 | }
5034 |
5035 | return this;
5036 |
5037 | };
5038 |
5039 | function _source( element ) {
5040 |
5041 | var id = element.getAttribute( 'id' );
5042 |
5043 | if ( sources[ id ] != undefined ) {
5044 |
5045 | return sources[ id ];
5046 |
5047 | }
5048 |
5049 | sources[ id ] = ( new Source(id )).parse( element );
5050 | return sources[ id ];
5051 |
5052 | };
5053 |
5054 | function _nsResolver( nsPrefix ) {
5055 |
5056 | if ( nsPrefix === "dae" ) {
5057 |
5058 | return "http://www.collada.org/2005/11/COLLADASchema";
5059 |
5060 | }
5061 |
5062 | return null;
5063 |
5064 | };
5065 |
5066 | function _bools( str ) {
5067 |
5068 | var raw = _strings( str );
5069 | var data = [];
5070 |
5071 | for ( var i = 0, l = raw.length; i < l; i ++ ) {
5072 |
5073 | data.push( (raw[i] === 'true' || raw[i] === '1') ? true : false );
5074 |
5075 | }
5076 |
5077 | return data;
5078 |
5079 | };
5080 |
5081 | function _floats( str ) {
5082 |
5083 | var raw = _strings(str);
5084 | var data = [];
5085 |
5086 | for ( var i = 0, l = raw.length; i < l; i ++ ) {
5087 |
5088 | data.push( parseFloat( raw[ i ] ) );
5089 |
5090 | }
5091 |
5092 | return data;
5093 |
5094 | };
5095 |
5096 | function _ints( str ) {
5097 |
5098 | var raw = _strings( str );
5099 | var data = [];
5100 |
5101 | for ( var i = 0, l = raw.length; i < l; i ++ ) {
5102 |
5103 | data.push( parseInt( raw[ i ], 10 ) );
5104 |
5105 | }
5106 |
5107 | return data;
5108 |
5109 | };
5110 |
5111 | function _strings( str ) {
5112 |
5113 | return ( str.length > 0 ) ? _trimString( str ).split( /\s+/ ) : [];
5114 |
5115 | };
5116 |
5117 | function _trimString( str ) {
5118 |
5119 | return str.replace( /^\s+/, "" ).replace( /\s+$/, "" );
5120 |
5121 | };
5122 |
5123 | function _attr_as_float( element, name, defaultValue ) {
5124 |
5125 | if ( element.hasAttribute( name ) ) {
5126 |
5127 | return parseFloat( element.getAttribute( name ) );
5128 |
5129 | } else {
5130 |
5131 | return defaultValue;
5132 |
5133 | }
5134 |
5135 | };
5136 |
5137 | function _attr_as_int( element, name, defaultValue ) {
5138 |
5139 | if ( element.hasAttribute( name ) ) {
5140 |
5141 | return parseInt( element.getAttribute( name ), 10) ;
5142 |
5143 | } else {
5144 |
5145 | return defaultValue;
5146 |
5147 | }
5148 |
5149 | };
5150 |
5151 | function _attr_as_string( element, name, defaultValue ) {
5152 |
5153 | if ( element.hasAttribute( name ) ) {
5154 |
5155 | return element.getAttribute( name );
5156 |
5157 | } else {
5158 |
5159 | return defaultValue;
5160 |
5161 | }
5162 |
5163 | };
5164 |
5165 | function _format_float( f, num ) {
5166 |
5167 | if ( f === undefined ) {
5168 |
5169 | var s = '0.';
5170 |
5171 | while ( s.length < num + 2 ) {
5172 |
5173 | s += '0';
5174 |
5175 | }
5176 |
5177 | return s;
5178 |
5179 | }
5180 |
5181 | num = num || 2;
5182 |
5183 | var parts = f.toString().split( '.' );
5184 | parts[ 1 ] = parts.length > 1 ? parts[ 1 ].substr( 0, num ) : "0";
5185 |
5186 | while ( parts[ 1 ].length < num ) {
5187 |
5188 | parts[ 1 ] += '0';
5189 |
5190 | }
5191 |
5192 | return parts.join( '.' );
5193 |
5194 | };
5195 |
5196 | function loadTextureImage ( texture, url ) {
5197 |
5198 | loader = new THREE.ImageLoader();
5199 |
5200 | loader.load( url, function ( image ) {
5201 |
5202 | texture.image = image;
5203 | texture.needsUpdate = true;
5204 |
5205 | } );
5206 |
5207 | };
5208 |
5209 | function extractDoubleSided( obj, element ) {
5210 |
5211 | obj.doubleSided = false;
5212 |
5213 | var node = element.querySelectorAll('extra double_sided')[0];
5214 |
5215 | if ( node ) {
5216 |
5217 | if ( node && parseInt( node.textContent, 10 ) === 1 ) {
5218 |
5219 | obj.doubleSided = true;
5220 |
5221 | }
5222 |
5223 | }
5224 |
5225 | };
5226 |
5227 | // Up axis conversion
5228 |
5229 | function setUpConversion() {
5230 |
5231 | if ( options.convertUpAxis !== true || colladaUp === options.upAxis ) {
5232 |
5233 | upConversion = null;
5234 |
5235 | } else {
5236 |
5237 | switch ( colladaUp ) {
5238 |
5239 | case 'X':
5240 |
5241 | upConversion = options.upAxis === 'Y' ? 'XtoY' : 'XtoZ';
5242 | break;
5243 |
5244 | case 'Y':
5245 |
5246 | upConversion = options.upAxis === 'X' ? 'YtoX' : 'YtoZ';
5247 | break;
5248 |
5249 | case 'Z':
5250 |
5251 | upConversion = options.upAxis === 'X' ? 'ZtoX' : 'ZtoY';
5252 | break;
5253 |
5254 | }
5255 |
5256 | }
5257 |
5258 | };
5259 |
5260 | function fixCoords( data, sign ) {
5261 |
5262 | if ( options.convertUpAxis !== true || colladaUp === options.upAxis ) {
5263 |
5264 | return;
5265 |
5266 | }
5267 |
5268 | switch ( upConversion ) {
5269 |
5270 | case 'XtoY':
5271 |
5272 | var tmp = data[ 0 ];
5273 | data[ 0 ] = sign * data[ 1 ];
5274 | data[ 1 ] = tmp;
5275 | break;
5276 |
5277 | case 'XtoZ':
5278 |
5279 | var tmp = data[ 2 ];
5280 | data[ 2 ] = data[ 1 ];
5281 | data[ 1 ] = data[ 0 ];
5282 | data[ 0 ] = tmp;
5283 | break;
5284 |
5285 | case 'YtoX':
5286 |
5287 | var tmp = data[ 0 ];
5288 | data[ 0 ] = data[ 1 ];
5289 | data[ 1 ] = sign * tmp;
5290 | break;
5291 |
5292 | case 'YtoZ':
5293 |
5294 | var tmp = data[ 1 ];
5295 | data[ 1 ] = sign * data[ 2 ];
5296 | data[ 2 ] = tmp;
5297 | break;
5298 |
5299 | case 'ZtoX':
5300 |
5301 | var tmp = data[ 0 ];
5302 | data[ 0 ] = data[ 1 ];
5303 | data[ 1 ] = data[ 2 ];
5304 | data[ 2 ] = tmp;
5305 | break;
5306 |
5307 | case 'ZtoY':
5308 |
5309 | var tmp = data[ 1 ];
5310 | data[ 1 ] = data[ 2 ];
5311 | data[ 2 ] = sign * tmp;
5312 | break;
5313 |
5314 | }
5315 |
5316 | };
5317 |
5318 | function getConvertedTranslation( axis, data ) {
5319 |
5320 | if ( options.convertUpAxis !== true || colladaUp === options.upAxis ) {
5321 |
5322 | return data;
5323 |
5324 | }
5325 |
5326 | switch ( axis ) {
5327 | case 'X':
5328 | data = upConversion === 'XtoY' ? data * -1 : data;
5329 | break;
5330 | case 'Y':
5331 | data = upConversion === 'YtoZ' || upConversion === 'YtoX' ? data * -1 : data;
5332 | break;
5333 | case 'Z':
5334 | data = upConversion === 'ZtoY' ? data * -1 : data ;
5335 | break;
5336 | default:
5337 | break;
5338 | }
5339 |
5340 | return data;
5341 | };
5342 |
5343 | function getConvertedVec3( data, offset ) {
5344 |
5345 | var arr = [ data[ offset ], data[ offset + 1 ], data[ offset + 2 ] ];
5346 | fixCoords( arr, -1 );
5347 | return new THREE.Vector3( arr[ 0 ], arr[ 1 ], arr[ 2 ] );
5348 |
5349 | };
5350 |
5351 | function getConvertedMat4( data ) {
5352 |
5353 | if ( options.convertUpAxis ) {
5354 |
5355 | // First fix rotation and scale
5356 |
5357 | // Columns first
5358 | var arr = [ data[ 0 ], data[ 4 ], data[ 8 ] ];
5359 | fixCoords( arr, -1 );
5360 | data[ 0 ] = arr[ 0 ];
5361 | data[ 4 ] = arr[ 1 ];
5362 | data[ 8 ] = arr[ 2 ];
5363 | arr = [ data[ 1 ], data[ 5 ], data[ 9 ] ];
5364 | fixCoords( arr, -1 );
5365 | data[ 1 ] = arr[ 0 ];
5366 | data[ 5 ] = arr[ 1 ];
5367 | data[ 9 ] = arr[ 2 ];
5368 | arr = [ data[ 2 ], data[ 6 ], data[ 10 ] ];
5369 | fixCoords( arr, -1 );
5370 | data[ 2 ] = arr[ 0 ];
5371 | data[ 6 ] = arr[ 1 ];
5372 | data[ 10 ] = arr[ 2 ];
5373 | // Rows second
5374 | arr = [ data[ 0 ], data[ 1 ], data[ 2 ] ];
5375 | fixCoords( arr, -1 );
5376 | data[ 0 ] = arr[ 0 ];
5377 | data[ 1 ] = arr[ 1 ];
5378 | data[ 2 ] = arr[ 2 ];
5379 | arr = [ data[ 4 ], data[ 5 ], data[ 6 ] ];
5380 | fixCoords( arr, -1 );
5381 | data[ 4 ] = arr[ 0 ];
5382 | data[ 5 ] = arr[ 1 ];
5383 | data[ 6 ] = arr[ 2 ];
5384 | arr = [ data[ 8 ], data[ 9 ], data[ 10 ] ];
5385 | fixCoords( arr, -1 );
5386 | data[ 8 ] = arr[ 0 ];
5387 | data[ 9 ] = arr[ 1 ];
5388 | data[ 10 ] = arr[ 2 ];
5389 |
5390 | // Now fix translation
5391 | arr = [ data[ 3 ], data[ 7 ], data[ 11 ] ];
5392 | fixCoords( arr, -1 );
5393 | data[ 3 ] = arr[ 0 ];
5394 | data[ 7 ] = arr[ 1 ];
5395 | data[ 11 ] = arr[ 2 ];
5396 |
5397 | }
5398 |
5399 | return new THREE.Matrix4().set(
5400 | data[0], data[1], data[2], data[3],
5401 | data[4], data[5], data[6], data[7],
5402 | data[8], data[9], data[10], data[11],
5403 | data[12], data[13], data[14], data[15]
5404 | );
5405 |
5406 | };
5407 |
5408 | function getConvertedIndex( index ) {
5409 |
5410 | if ( index > -1 && index < 3 ) {
5411 |
5412 | var members = [ 'X', 'Y', 'Z' ],
5413 | indices = { X: 0, Y: 1, Z: 2 };
5414 |
5415 | index = getConvertedMember( members[ index ] );
5416 | index = indices[ index ];
5417 |
5418 | }
5419 |
5420 | return index;
5421 |
5422 | };
5423 |
5424 | function getConvertedMember( member ) {
5425 |
5426 | if ( options.convertUpAxis ) {
5427 |
5428 | switch ( member ) {
5429 |
5430 | case 'X':
5431 |
5432 | switch ( upConversion ) {
5433 |
5434 | case 'XtoY':
5435 | case 'XtoZ':
5436 | case 'YtoX':
5437 |
5438 | member = 'Y';
5439 | break;
5440 |
5441 | case 'ZtoX':
5442 |
5443 | member = 'Z';
5444 | break;
5445 |
5446 | }
5447 |
5448 | break;
5449 |
5450 | case 'Y':
5451 |
5452 | switch ( upConversion ) {
5453 |
5454 | case 'XtoY':
5455 | case 'YtoX':
5456 | case 'ZtoX':
5457 |
5458 | member = 'X';
5459 | break;
5460 |
5461 | case 'XtoZ':
5462 | case 'YtoZ':
5463 | case 'ZtoY':
5464 |
5465 | member = 'Z';
5466 | break;
5467 |
5468 | }
5469 |
5470 | break;
5471 |
5472 | case 'Z':
5473 |
5474 | switch ( upConversion ) {
5475 |
5476 | case 'XtoZ':
5477 |
5478 | member = 'X';
5479 | break;
5480 |
5481 | case 'YtoZ':
5482 | case 'ZtoX':
5483 | case 'ZtoY':
5484 |
5485 | member = 'Y';
5486 | break;
5487 |
5488 | }
5489 |
5490 | break;
5491 |
5492 | }
5493 |
5494 | }
5495 |
5496 | return member;
5497 |
5498 | };
5499 |
5500 | return {
5501 |
5502 | load: load,
5503 | parse: parse,
5504 | setPreferredShading: setPreferredShading,
5505 | applySkin: applySkin,
5506 | geometries : geometries,
5507 | options: options
5508 |
5509 | };
5510 |
5511 | };
5512 |
--------------------------------------------------------------------------------