├── README.md
├── LICENSE
├── examples
├── deps
│ ├── styles.css
│ ├── glsl.js
│ ├── CodeMirror.css
│ └── ShaderEditor.js
└── index.html
└── src
└── ShaderEditor.js
/README.md:
--------------------------------------------------------------------------------
1 | # Live WebGL Shader Editor
2 | This is a JavaScript library that aims to provide the same functionality as *Firefox DevTools Shader Editor*: modify the source of shaders in real-time, in the browser, without reloading, easy to include and totally implementation-agnostic. Using function hooks to modify the relevant methods of *WebGLRenderingContext*, it's possible to add this features with JavaScript only.
3 |
4 | The main idea is to create a *Chrome DevTools extension*. And I have really no idea how to get that done, so if anyone is willing to help, let's do it!
5 |
6 | [](http://www.clicktorelease.com/tmp/shader-editor)
7 |
8 | You can read more about this in [Creating a Plug'n Play Live WebGL Shader Editor](http://www.clicktorelease.com/blog/live-webgl-shader-editor)
9 |
10 | As always: forks, pull requests and code critiques are welcome!
11 |
12 | #### License ####
13 |
14 | MIT licensed
15 |
16 | Copyright (C) 2015 Jaume Sanchez Elias, http://www.clicktorelease.com
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Jaume Sanchez
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/examples/deps/styles.css:
--------------------------------------------------------------------------------
1 | #shaderEditor *{ font-family: 'Droid Sans Mono', monospace; font-size: 12px;}
2 | #shaderEditor{ box-sizing: border-box; position: absolute; left: 0; top: 0; right: 0; bottom: 0; display: none; opacity: 1;}
3 | #shaderEditor:hover{ opacity: 1 ;}
4 | #shaderEditor #programList{ position: absolute; left: 0; top: 30px; width: 200px; bottom: 0; border-right: 1px solid #dedede;}
5 | #shaderEditor #programList li{ padding: 10px; border-top: 1px solid #dedede; border-bottom: 1px solid #404040; width: 100%; cursor: pointer;}
6 | #shaderEditor #editorContainer{ position: absolute; left: 200px; top: 0; right: 0; bottom: 0 ;}
7 | #shaderEditor .cm-s-default{ position: absolute; top: 30px; bottom: 0; height: calc(100% - 30px); width: 50% ;}
8 | #shaderEditor #vsEditor, #shaderEditor #fsEditor{ border-top: 1px solid #dedede; border-right: 1px solid #dedede;}
9 | #shaderEditor #vsEditor{ left: 0; }
10 | #shaderEditor #fsEditor{ left: 50%; }
11 |
12 | #shaderEditor .programs-title, #shaderEditor .vs-title, #shaderEditor .fs-title{ left: 0; position: absolute; padding: 10px 10px 10px 35px }
13 | #shaderEditor .vs-title{ left: 0;}
14 | #shaderEditor .fs-title{ left: 50%;}
15 |
16 | .cm-s-default{ background-color: rgba( 0,0,0,.5); color: white;}
17 | .cm-s-default *{ color: white; background-color: transparent;}
18 |
19 | .cm-s-default span.cm-keyword {color: #bbf;}
20 | .cm-s-default span.cm-number {color: #fbb;}
21 | .cm-s-default span.cm-def {color: #55f;}
22 | .cm-s-default span.cm-comment {color: #8ff;}
23 | .cm-s-default span.cm-operator {color: #5b5;}
24 | .cm-s-default span.cm-meta {color: #8f8;}
25 | .cm-s-default span.cm-qualifier {color: #888;}
26 | .cm-s-default span.cm-builtin {color: #fbf;}
27 | .cm-s-default span.cm-bracket {color: #bbb;}
28 |
29 | .errorMessage{ background-color: red;}
--------------------------------------------------------------------------------
/examples/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Shader Editor
6 |
7 |
8 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
85 |
--------------------------------------------------------------------------------
/examples/deps/glsl.js:
--------------------------------------------------------------------------------
1 | CodeMirror.defineMode("glsl", function(config, parserConfig) {
2 | var indentUnit = config.indentUnit,
3 | keywords = parserConfig.keywords || {},
4 | builtins = parserConfig.builtins || {},
5 | blockKeywords = parserConfig.blockKeywords || {},
6 | atoms = parserConfig.atoms || {},
7 | hooks = parserConfig.hooks || {},
8 | multiLineStrings = parserConfig.multiLineStrings;
9 | var isOperatorChar = /[+\-*&%=<>!?|\/]/;
10 |
11 | var curPunc;
12 |
13 | function tokenBase(stream, state) {
14 | var ch = stream.next();
15 | if (hooks[ch]) {
16 | var result = hooks[ch](stream, state);
17 | if (result !== false) return result;
18 | }
19 | if (ch == '"' || ch == "'") {
20 | state.tokenize = tokenString(ch);
21 | return state.tokenize(stream, state);
22 | }
23 | if (/[\[\]{}\(\),;\:\.]/.test(ch)) {
24 | curPunc = ch;
25 | return "bracket";
26 | }
27 | if (/\d/.test(ch)) {
28 | stream.eatWhile(/[\w\.]/);
29 | return "number";
30 | }
31 | if (ch == "/") {
32 | if (stream.eat("*")) {
33 | state.tokenize = tokenComment;
34 | return tokenComment(stream, state);
35 | }
36 | if (stream.eat("/")) {
37 | stream.skipToEnd();
38 | return "comment";
39 | }
40 | }
41 | if (isOperatorChar.test(ch)) {
42 | stream.eatWhile(isOperatorChar);
43 | return "operator";
44 | }
45 | stream.eatWhile(/[\w\$_]/);
46 | var cur = stream.current();
47 | if (keywords.propertyIsEnumerable(cur)) {
48 | if (blockKeywords.propertyIsEnumerable(cur)) curPunc = "newstatement";
49 | return "keyword";
50 | }
51 | if (builtins.propertyIsEnumerable(cur)) {
52 | return "builtin";
53 | }
54 | if (atoms.propertyIsEnumerable(cur)) return "atom";
55 | return "word";
56 | }
57 |
58 | function tokenString(quote) {
59 | return function(stream, state) {
60 | var escaped = false, next, end = false;
61 | while ((next = stream.next()) != null) {
62 | if (next == quote && !escaped) {end = true; break;}
63 | escaped = !escaped && next == "\\";
64 | }
65 | if (end || !(escaped || multiLineStrings))
66 | state.tokenize = tokenBase;
67 | return "string";
68 | };
69 | }
70 |
71 | function tokenComment(stream, state) {
72 | var maybeEnd = false, ch;
73 | while (ch = stream.next()) {
74 | if (ch == "/" && maybeEnd) {
75 | state.tokenize = tokenBase;
76 | break;
77 | }
78 | maybeEnd = (ch == "*");
79 | }
80 | return "comment";
81 | }
82 |
83 | function Context(indented, column, type, align, prev) {
84 | this.indented = indented;
85 | this.column = column;
86 | this.type = type;
87 | this.align = align;
88 | this.prev = prev;
89 | }
90 | function pushContext(state, col, type) {
91 | return state.context = new Context(state.indented, col, type, null, state.context);
92 | }
93 | function popContext(state) {
94 | var t = state.context.type;
95 | if (t == ")" || t == "]" || t == "}")
96 | state.indented = state.context.indented;
97 | return state.context = state.context.prev;
98 | }
99 |
100 | // Interface
101 |
102 | return {
103 | startState: function(basecolumn) {
104 | return {
105 | tokenize: null,
106 | context: new Context((basecolumn || 0) - indentUnit, 0, "top", false),
107 | indented: 0,
108 | startOfLine: true
109 | };
110 | },
111 |
112 | token: function(stream, state) {
113 | var ctx = state.context;
114 | if (stream.sol()) {
115 | if (ctx.align == null) ctx.align = false;
116 | state.indented = stream.indentation();
117 | state.startOfLine = true;
118 | }
119 | if (stream.eatSpace()) return null;
120 | curPunc = null;
121 | var style = (state.tokenize || tokenBase)(stream, state);
122 | if (style == "comment" || style == "meta") return style;
123 | if (ctx.align == null) ctx.align = true;
124 |
125 | if ((curPunc == ";" || curPunc == ":") && ctx.type == "statement") popContext(state);
126 | else if (curPunc == "{") pushContext(state, stream.column(), "}");
127 | else if (curPunc == "[") pushContext(state, stream.column(), "]");
128 | else if (curPunc == "(") pushContext(state, stream.column(), ")");
129 | else if (curPunc == "}") {
130 | while (ctx.type == "statement") ctx = popContext(state);
131 | if (ctx.type == "}") ctx = popContext(state);
132 | while (ctx.type == "statement") ctx = popContext(state);
133 | }
134 | else if (curPunc == ctx.type) popContext(state);
135 | else if (ctx.type == "}" || ctx.type == "top" || (ctx.type == "statement" && curPunc == "newstatement"))
136 | pushContext(state, stream.column(), "statement");
137 | state.startOfLine = false;
138 | return style;
139 | },
140 |
141 | indent: function(state, textAfter) {
142 | if (state.tokenize != tokenBase && state.tokenize != null) return 0;
143 | var firstChar = textAfter && textAfter.charAt(0), ctx = state.context, closing = firstChar == ctx.type;
144 | if (ctx.type == "statement") return ctx.indented + (firstChar == "{" ? 0 : indentUnit);
145 | else if (ctx.align) return ctx.column + (closing ? 0 : 1);
146 | else return ctx.indented + (closing ? 0 : indentUnit);
147 | },
148 |
149 | electricChars: "{}"
150 | };
151 | });
152 |
153 | (function() {
154 | function words(str) {
155 | var obj = {}, words = str.split(" ");
156 | for (var i = 0; i < words.length; ++i) obj[words[i]] = true;
157 | return obj;
158 | }
159 | var glslKeywords = "attribute const uniform varying break continue " +
160 | "do for while if else in out inout float int void bool true false " +
161 | "lowp mediump highp precision invariant discard return mat2 mat3 " +
162 | "mat4 vec2 vec3 vec4 ivec2 ivec3 ivec4 bvec2 bvec3 bvec4 sampler2D " +
163 | "samplerCube struct gl_FragCoord gl_FragColor";
164 | var glslBuiltins = "radians degrees sin cos tan asin acos atan pow " +
165 | "exp log exp2 log2 sqrt inversesqrt abs sign floor ceil fract mod " +
166 | "min max clamp mix step smoothstep length distance dot cross " +
167 | "normalize faceforward reflect refract matrixCompMult lessThan " +
168 | "lessThanEqual greaterThan greaterThanEqual equal notEqual any all " +
169 | "not dFdx dFdy fwidth texture2D texture2DProj texture2DLod " +
170 | "texture2DProjLod textureCube textureCubeLod";
171 |
172 | function cppHook(stream, state) {
173 | if (!state.startOfLine) return false;
174 | stream.skipToEnd();
175 | return "meta";
176 | }
177 |
178 | // C#-style strings where "" escapes a quote.
179 | function tokenAtString(stream, state) {
180 | var next;
181 | while ((next = stream.next()) != null) {
182 | if (next == '"' && !stream.eat('"')) {
183 | state.tokenize = null;
184 | break;
185 | }
186 | }
187 | return "string";
188 | }
189 |
190 | CodeMirror.defineMIME("text/x-glsl", {
191 | name: "glsl",
192 | keywords: words(glslKeywords),
193 | builtins: words(glslBuiltins),
194 | blockKeywords: words("case do else for if switch while struct"),
195 | atoms: words("null"),
196 | hooks: {"#": cppHook}
197 | });
198 | }());
--------------------------------------------------------------------------------
/examples/deps/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 | }
67 | @-moz-keyframes blink {
68 | 0% { background: #7e7; }
69 | 50% { background: none; }
70 | 100% { background: #7e7; }
71 | }
72 | @-webkit-keyframes blink {
73 | 0% { background: #7e7; }
74 | 50% { background: none; }
75 | 100% { background: #7e7; }
76 | }
77 | @keyframes blink {
78 | 0% { background: #7e7; }
79 | 50% { background: none; }
80 | 100% { background: #7e7; }
81 | }
82 |
83 | /* Can style cursor different in overwrite (non-insert) mode */
84 | div.CodeMirror-overwrite div.CodeMirror-cursor {}
85 |
86 | .cm-tab { display: inline-block; text-decoration: inherit; }
87 |
88 | .CodeMirror-ruler {
89 | border-left: 1px solid #ccc;
90 | position: absolute;
91 | }
92 |
93 | /* DEFAULT THEME */
94 |
95 | .cm-s-default .cm-keyword {color: #708;}
96 | .cm-s-default .cm-atom {color: #219;}
97 | .cm-s-default .cm-number {color: #164;}
98 | .cm-s-default .cm-def {color: #00f;}
99 | .cm-s-default .cm-variable,
100 | .cm-s-default .cm-punctuation,
101 | .cm-s-default .cm-property,
102 | .cm-s-default .cm-operator {}
103 | .cm-s-default .cm-variable-2 {color: #05a;}
104 | .cm-s-default .cm-variable-3 {color: #085;}
105 | .cm-s-default .cm-comment {color: #a50;}
106 | .cm-s-default .cm-string {color: #a11;}
107 | .cm-s-default .cm-string-2 {color: #f50;}
108 | .cm-s-default .cm-meta {color: #555;}
109 | .cm-s-default .cm-qualifier {color: #555;}
110 | .cm-s-default .cm-builtin {color: #30a;}
111 | .cm-s-default .cm-bracket {color: #997;}
112 | .cm-s-default .cm-tag {color: #170;}
113 | .cm-s-default .cm-attribute {color: #00c;}
114 | .cm-s-default .cm-header {color: blue;}
115 | .cm-s-default .cm-quote {color: #090;}
116 | .cm-s-default .cm-hr {color: #999;}
117 | .cm-s-default .cm-link {color: #00c;}
118 |
119 | .cm-negative {color: #d44;}
120 | .cm-positive {color: #292;}
121 | .cm-header, .cm-strong {font-weight: bold;}
122 | .cm-em {font-style: italic;}
123 | .cm-link {text-decoration: underline;}
124 | .cm-strikethrough {text-decoration: line-through;}
125 |
126 | .cm-s-default .cm-error {color: #f00;}
127 | .cm-invalidchar {color: #f00;}
128 |
129 | /* Default styles for common addons */
130 |
131 | div.CodeMirror span.CodeMirror-matchingbracket {color: #0f0;}
132 | div.CodeMirror span.CodeMirror-nonmatchingbracket {color: #f22;}
133 | .CodeMirror-matchingtag { background: rgba(255, 150, 0, .3); }
134 | .CodeMirror-activeline-background {background: #e8f2ff;}
135 |
136 | /* STOP */
137 |
138 | /* The rest of this file contains styles related to the mechanics of
139 | the editor. You probably shouldn't touch them. */
140 |
141 | .CodeMirror {
142 | position: relative;
143 | overflow: hidden;
144 | background: white;
145 | }
146 |
147 | .CodeMirror-scroll {
148 | overflow: scroll !important; /* Things will break if this is overridden */
149 | /* 30px is the magic margin used to hide the element's real scrollbars */
150 | /* See overflow: hidden in .CodeMirror */
151 | margin-bottom: -30px; margin-right: -30px;
152 | padding-bottom: 30px;
153 | height: 100%;
154 | outline: none; /* Prevent dragging from highlighting the element */
155 | position: relative;
156 | }
157 | .CodeMirror-sizer {
158 | position: relative;
159 | border-right: 30px solid transparent;
160 | }
161 |
162 | /* The fake, visible scrollbars. Used to force redraw during scrolling
163 | before actuall scrolling happens, thus preventing shaking and
164 | flickering artifacts. */
165 | .CodeMirror-vscrollbar, .CodeMirror-hscrollbar, .CodeMirror-scrollbar-filler, .CodeMirror-gutter-filler {
166 | position: absolute;
167 | z-index: 6;
168 | display: none;
169 | }
170 | .CodeMirror-vscrollbar {
171 | right: 0; top: 0;
172 | overflow-x: hidden;
173 | overflow-y: scroll;
174 | }
175 | .CodeMirror-hscrollbar {
176 | bottom: 0; left: 0;
177 | overflow-y: hidden;
178 | overflow-x: scroll;
179 | }
180 | .CodeMirror-scrollbar-filler {
181 | right: 0; bottom: 0;
182 | }
183 | .CodeMirror-gutter-filler {
184 | left: 0; bottom: 0;
185 | }
186 |
187 | .CodeMirror-gutters {
188 | position: absolute; left: 0; top: 0;
189 | z-index: 3;
190 | }
191 | .CodeMirror-gutter {
192 | white-space: normal;
193 | height: 100%;
194 | display: inline-block;
195 | margin-bottom: -30px;
196 | /* Hack to make IE7 behave */
197 | *zoom:1;
198 | *display:inline;
199 | }
200 | .CodeMirror-gutter-wrapper {
201 | position: absolute;
202 | z-index: 4;
203 | height: 100%;
204 | }
205 | .CodeMirror-gutter-elt {
206 | position: absolute;
207 | cursor: default;
208 | z-index: 4;
209 | }
210 | .CodeMirror-gutter-wrapper {
211 | -webkit-user-select: none;
212 | -moz-user-select: none;
213 | user-select: none;
214 | }
215 |
216 | .CodeMirror-lines {
217 | cursor: text;
218 | min-height: 1px; /* prevents collapsing before first draw */
219 | }
220 | .CodeMirror pre {
221 | /* Reset some styles that the rest of the page might have set */
222 | -moz-border-radius: 0; -webkit-border-radius: 0; border-radius: 0;
223 | border-width: 0;
224 | background: transparent;
225 | font-family: inherit;
226 | font-size: inherit;
227 | margin: 0;
228 | white-space: pre;
229 | word-wrap: normal;
230 | line-height: inherit;
231 | color: inherit;
232 | z-index: 2;
233 | position: relative;
234 | overflow: visible;
235 | -webkit-tap-highlight-color: transparent;
236 | }
237 | .CodeMirror-wrap pre {
238 | word-wrap: break-word;
239 | white-space: pre-wrap;
240 | word-break: normal;
241 | }
242 |
243 | .CodeMirror-linebackground {
244 | position: absolute;
245 | left: 0; right: 0; top: 0; bottom: 0;
246 | z-index: 0;
247 | }
248 |
249 | .CodeMirror-linewidget {
250 | position: relative;
251 | z-index: 2;
252 | overflow: auto;
253 | }
254 |
255 | .CodeMirror-widget {}
256 |
257 | .CodeMirror-code {
258 | outline: none;
259 | }
260 |
261 | /* Force content-box sizing for the elements where we expect it */
262 | .CodeMirror-scroll,
263 | .CodeMirror-sizer,
264 | .CodeMirror-gutter,
265 | .CodeMirror-gutters,
266 | .CodeMirror-linenumber {
267 | -moz-box-sizing: content-box;
268 | box-sizing: content-box;
269 | }
270 |
271 | .CodeMirror-measure {
272 | position: absolute;
273 | width: 100%;
274 | height: 0;
275 | overflow: hidden;
276 | visibility: hidden;
277 | }
278 | .CodeMirror-measure pre { position: static; }
279 |
280 | .CodeMirror div.CodeMirror-cursor {
281 | position: absolute;
282 | border-right: none;
283 | width: 0;
284 | }
285 |
286 | div.CodeMirror-cursors {
287 | visibility: hidden;
288 | position: relative;
289 | z-index: 3;
290 | }
291 | .CodeMirror-focused div.CodeMirror-cursors {
292 | visibility: visible;
293 | }
294 |
295 | .CodeMirror-selected { background: #d9d9d9; }
296 | .CodeMirror-focused .CodeMirror-selected { background: #d7d4f0; }
297 | .CodeMirror-crosshair { cursor: crosshair; }
298 | .CodeMirror ::selection { background: #d7d4f0; }
299 | .CodeMirror ::-moz-selection { background: #d7d4f0; }
300 |
301 | .cm-searching {
302 | background: #ffa;
303 | background: rgba(255, 255, 0, .4);
304 | }
305 |
306 | /* IE7 hack to prevent it from returning funny offsetTops on the spans */
307 | .CodeMirror span { *vertical-align: text-bottom; }
308 |
309 | /* Used to force a border model for a node */
310 | .cm-force-border { padding-right: .1px; }
311 |
312 | @media print {
313 | /* Hide the cursor when printing */
314 | .CodeMirror div.CodeMirror-cursors {
315 | visibility: hidden;
316 | }
317 | }
318 |
319 | /* See issue #2901 */
320 | .cm-tab-wrap-hack:after { content: ''; }
321 |
322 | /* Help users use markselection to safely style text background */
323 |
--------------------------------------------------------------------------------
/src/ShaderEditor.js:
--------------------------------------------------------------------------------
1 | ( function() {
2 |
3 | function _h( f, c ) {
4 | return function() {
5 | var res = f.apply( this, arguments );
6 | res = c.apply( this, [ res, arguments ] ) || res;
7 | return res;
8 | }
9 | }
10 |
11 | function _h2( f, c ) {
12 | return function() {
13 | return c.apply( this, arguments );
14 | }
15 | }
16 |
17 | var references = {};
18 | function keepReference( f ) {
19 |
20 | references[ f ] = WebGLRenderingContext.prototype[ f ];
21 |
22 | }
23 |
24 | var _gl = document.createElement( 'canvas' ).getContext( 'webgl' );
25 |
26 | keepReference( 'getUniformLocation' );
27 |
28 | function init() {
29 |
30 | var css = document.createElement( 'link' );
31 | css.rel = 'stylesheet'
32 | css.type = 'text/css';
33 | css.href = 'deps/CodeMirror.css';
34 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( css );
35 |
36 | var css = document.createElement( 'link' );
37 | css.rel = 'stylesheet'
38 | css.type = 'text/css';
39 | css.href = 'deps/styles.css';
40 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( css );
41 |
42 | var css = document.createElement( 'link' );
43 | css.rel = 'stylesheet'
44 | css.type = 'text/css';
45 | css.href = 'http://fonts.googleapis.com/css?family=Droid+Sans+Mono';
46 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( css );
47 |
48 | var editor = document.createElement( 'div' );
49 | editor.setAttribute( 'id', 'shaderEditor' );
50 | document.body.appendChild( editor );
51 | this.shaderEditor = editor;
52 |
53 | var p = document.createElement( 'p' );
54 | p.textContent = 'Programs';
55 | p.className = 'programs-title';
56 | editor.appendChild( p );
57 |
58 | var programList = document.createElement( 'ul' );
59 | programList.setAttribute( 'id', 'programList' );
60 | editor.appendChild( programList );
61 |
62 | var editorContainer = document.createElement( 'ul' );
63 | editorContainer.setAttribute( 'id', 'editorContainer' );
64 | editor.appendChild( editorContainer );
65 |
66 | var p = document.createElement( 'p' );
67 | p.textContent = 'Vertex Shader';
68 | p.className = 'vs-title';
69 | editorContainer.appendChild( p );
70 |
71 | var p = document.createElement( 'p' );
72 | p.textContent = 'Fragment Shader';
73 | p.className = 'fs-title';
74 | editorContainer.appendChild( p );
75 |
76 | var js = document.createElement( 'script' );
77 | js.src = 'deps/CodeMirror.js';
78 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( js );
79 | js.addEventListener( 'load', function() {
80 |
81 | var js = document.createElement( 'script' );
82 | js.src = 'deps/glsl.js';
83 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( js );
84 | js.addEventListener( 'load', function() {
85 |
86 | var el = document.createElement( 'style' );
87 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( el );
88 | el.textContent = css;
89 |
90 | this.programList = programList;
91 |
92 | var options = {
93 | lineNumbers: true,
94 | matchBrackets: true,
95 | indentWithTabs: false,
96 | tabSize: 4,
97 | indentUnit: 4,
98 | mode: "text/x-glsl",
99 | foldGutter: true,
100 | gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
101 | };
102 |
103 | this.vsEditor = CodeMirror( editorContainer, options ),
104 | this.fsEditor = CodeMirror( editorContainer, options );
105 | this.vsEditor._errors = [];
106 | this.fsEditor._errors = [];
107 |
108 | this.vsEditor.getWrapperElement().setAttribute( 'id', 'vsEditor' );
109 | this.fsEditor.getWrapperElement().setAttribute( 'id', 'fsEditor' );
110 |
111 | var keyTimeout = 500;
112 | var vSTimeout;
113 | function scheduleUpdateVS() {
114 |
115 | if( vSTimeout ) vSTimeout = clearTimeout( vSTimeout );
116 | vSTimeout = setTimeout( update, keyTimeout );
117 |
118 | }
119 |
120 | var fSTimeout;
121 | function scheduleUpdateFS() {
122 |
123 | if( fSTimeout ) fSTimeout = clearTimeout( fSTimeout );
124 | fSTimeout = setTimeout( update, keyTimeout );
125 |
126 | }
127 |
128 | this.vsEditor.on( 'change', scheduleUpdateVS );
129 | this.fsEditor.on( 'change', scheduleUpdateFS );
130 |
131 | this.vsEditor.on( 'keyup', scheduleUpdateVS );
132 | this.fsEditor.on( 'keyup', scheduleUpdateFS );
133 |
134 | }.bind( this ) );
135 |
136 | }.bind( this ) );
137 |
138 | }
139 |
140 | function htmlEncode(str){
141 |
142 | return String(str)
143 | .replace(/&/g, '&')
144 | .replace(/"/g, '"')
145 | .replace(/'/g, ''')
146 | .replace(//g, '>');
148 |
149 | }
150 |
151 | function testShader( type, source, code ) {
152 |
153 | if( source === '' ) return;
154 |
155 | var s = _gl.createShader( type );
156 | _gl.shaderSource( s, source );
157 | _gl.compileShader( s );
158 |
159 | while( code._errors.length > 0 ) {
160 |
161 | var mark = code._errors.pop();
162 | code.removeLineWidget( mark );
163 |
164 | }
165 |
166 | if ( _gl.getShaderParameter( s, _gl.COMPILE_STATUS ) === false ) {
167 |
168 | var error = _gl.getShaderInfoLog( s );
169 |
170 | if( error==null )
171 | {
172 | /*this.mForceFrame = true;
173 | if( fromScript==false )
174 | {
175 | eleWrapper.className = "errorNo";
176 | setTimeout(function () { eleWrapper.className = ""; }, 500 );
177 | }*/
178 | }
179 | else
180 | {
181 | //eleWrapper.className = "errorYes";
182 |
183 | var lineOffset = 0;//this.mEffect.GetHeaderSize( this.mActiveDoc );
184 | var lines = error.match(/^.*((\r\n|\n|\r)|$)/gm);
185 | for( var i=0; i1 && parts[0]!="Warning")
199 | {
200 | console.log( parts.length + " **" + lines[i] );
201 |
202 | var txt = "";
203 | if( parts.length==4 )
204 | txt = parts[2] + " : " + parts[3];
205 | else
206 | txt = "Unknown error";
207 |
208 | var msg = document.createElement("div");
209 | msg.appendChild(document.createTextNode( txt ));
210 | msg.className = "errorMessage";
211 | var mark = code.addLineWidget( 0, msg, {coverGutter: false, noHScroll: true, above: true} );
212 | code._errors.push( mark );
213 |
214 | }
215 | }
216 | }
217 | // console.error( 'Shader couldn\'t compile.' );
218 | return false;
219 |
220 | }
221 |
222 | if ( _gl.getShaderInfoLog( s ) !== '' ) {
223 |
224 | console.error( '_gl.getShaderInfoLog()', _gl.getShaderInfoLog( s ) );
225 | return false;
226 |
227 | }
228 |
229 | return true;
230 |
231 | }
232 |
233 | init();
234 |
235 | this.programs = [];
236 | this.shaders = [];
237 | var uniforms = [];
238 | var currentProgram = null;
239 |
240 | function findProgram( p ) {
241 |
242 | var f = null;
243 | programs.forEach( function( e ) {
244 | if( e.program === p ) f = e;
245 | } );
246 | return f;
247 |
248 | }
249 |
250 | function findShader( s ) {
251 |
252 | var f = null;
253 |
254 | shaders.forEach( function( e ) {
255 | if( e.shader === s ) {
256 | f = e;
257 | }
258 | } );
259 |
260 | return f;
261 |
262 | }
263 |
264 | function addProgram( gl, p ) {
265 |
266 | this.shaderEditor.style.display = 'block';
267 |
268 | var li = document.createElement( 'li' );
269 | li.textContent = 'Program';
270 |
271 | var el = { gl: gl, program: p, shaders: [], li: li };
272 |
273 | li.addEventListener( 'click', function( e ) {
274 | selectProgram( el );
275 | e.preventDefault();
276 | } );
277 |
278 | programs.push( el );
279 |
280 | this.programList.appendChild( li );
281 |
282 | }
283 |
284 | function selectProgram( p ) {
285 |
286 | currentProgram = p;
287 | this.vsEditor.setValue( p.shaders[ 0 ].source );
288 | this.vsEditor.refresh();
289 |
290 | this.fsEditor.setValue( p.shaders[ 1 ].source );
291 | this.fsEditor.refresh();
292 |
293 | }
294 |
295 | function update() {
296 |
297 | if( !currentProgram ) return;
298 |
299 | var gl = currentProgram.gl,
300 | program = currentProgram.program,
301 | vertexShader = currentProgram.shaders[ 0 ].shader,
302 | fragmentShader = currentProgram.shaders[ 1 ].shader;
303 |
304 | if( currentProgram.shaders[ 0 ].type === gl.VERTEX_SHADER ) vertexShader = currentProgram.shaders[ 0 ].shader;
305 | if( currentProgram.shaders[ 0 ].type === gl.FRAGMENT_SHADER ) fragmentShader = currentProgram.shaders[ 0 ].shader;
306 | if( currentProgram.shaders[ 1 ].type === gl.VERTEX_SHADER ) vertexShader = currentProgram.shaders[ 1 ].shader;
307 | if( currentProgram.shaders[ 1 ].type === gl.FRAGMENT_SHADER ) fragmentShader = currentProgram.shaders[ 1 ].shader;
308 |
309 | //gl.detachShader( program, vertexShader );
310 | //gl.detachShader( program, fragmentShader );
311 |
312 | //vertexShader = gl.createShader( gl.VERTEX_SHADER );
313 | //fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
314 |
315 | if( !testShader( gl.VERTEX_SHADER, this.vsEditor.getValue(), this.vsEditor ) ) return false;
316 | if( !testShader( gl.FRAGMENT_SHADER, this.fsEditor.getValue(), this.fsEditor ) ) return false;
317 |
318 | gl.shaderSource( vertexShader, this.vsEditor.getValue() );
319 | gl.shaderSource( fragmentShader, this.fsEditor.getValue() );
320 |
321 | gl.compileShader( vertexShader );
322 |
323 | if ( gl.getShaderParameter( vertexShader, gl.COMPILE_STATUS ) === false ) {
324 |
325 | console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
326 |
327 | }
328 |
329 | if ( gl.getShaderInfoLog( vertexShader ) !== '' ) {
330 |
331 | console.error( 'THREE.WebGLShader:', 'gl.getShaderInfoLog()', gl.getShaderInfoLog( vertexShader ) );
332 |
333 | }
334 |
335 | gl.compileShader( fragmentShader );
336 |
337 |
338 | if ( gl.getShaderParameter( fragmentShader, gl.COMPILE_STATUS ) === false ) {
339 |
340 | console.error( 'Shader couldn\'t compile.' );
341 |
342 | }
343 |
344 | if ( gl.getShaderInfoLog( fragmentShader ) !== '' ) {
345 |
346 | console.error( 'gl.getShaderInfoLog()', gl.getShaderInfoLog( fragmentShader ) );
347 |
348 | }
349 |
350 | gl.attachShader( program, vertexShader );
351 | gl.attachShader( program, fragmentShader );
352 |
353 | gl.linkProgram( program );
354 |
355 | if( !gl.getProgramParameter(program,gl.LINK_STATUS) ) {
356 | var infoLog = gl.getProgramInfoLog(program);
357 | //gl.deleteProgram( program );
358 | console.log( infoLog );
359 | }
360 |
361 | console.log( 'update' );
362 |
363 | }
364 |
365 | WebGLRenderingContext.prototype.createShader = _h(
366 | WebGLRenderingContext.prototype.createShader,
367 | function( res, args ) {
368 |
369 | console.log( 'createShader', args );
370 | shaders.push( { shader: res, type: args[ 0 ] } );
371 |
372 | }
373 | );
374 |
375 |
376 | WebGLRenderingContext.prototype.shaderSource = _h(
377 | WebGLRenderingContext.prototype.shaderSource,
378 | function( res, args ) {
379 |
380 | console.log( 'shaderSource', args );
381 | var s = findShader( args[ 0 ] );
382 | s.source = args[ 1 ];
383 |
384 | }
385 | );
386 |
387 | WebGLRenderingContext.prototype.compileShader = _h(
388 | WebGLRenderingContext.prototype.compileShader,
389 | function( res, args ) {
390 |
391 | console.log( 'compileShader', args );
392 |
393 | }
394 | );
395 |
396 | WebGLRenderingContext.prototype.createProgram = _h(
397 | WebGLRenderingContext.prototype.createProgram,
398 | function( res, args ) {
399 |
400 | console.log( 'createProgram', res, args );
401 | addProgram( this, res );
402 |
403 | }
404 | );
405 |
406 | WebGLRenderingContext.prototype.attachShader = _h(
407 | WebGLRenderingContext.prototype.attachShader,
408 | function( res, args ) {
409 |
410 | console.log( 'attachShader', args );
411 | var p = findProgram( args[ 0 ] );
412 | var s = findShader( args[ 1 ] );
413 | p.shaders.push( s );
414 |
415 | }
416 | );
417 |
418 | WebGLRenderingContext.prototype.linkProgram = _h(
419 | WebGLRenderingContext.prototype.linkProgram,
420 | function( res, args ) {
421 |
422 | console.log( 'linkProgram', args );
423 |
424 | }
425 | );
426 |
427 | WebGLRenderingContext.prototype.getUniformLocation = _h(
428 | WebGLRenderingContext.prototype.getUniformLocation,
429 | function( res, args ) {
430 |
431 | uniforms.push( {
432 | program: args[ 0 ],
433 | uniform: args[ 1 ],
434 | location: res,
435 | gl: this
436 | } );
437 | console.log( 'getUniformLocation', res, args );
438 |
439 | }
440 | );
441 |
442 | function findProgramByLocation( location ) {
443 |
444 | var f = null;
445 |
446 | uniforms.forEach( function( e ) {
447 | if( e.location === location ) {
448 | f = e;
449 | }
450 | } );
451 |
452 | return f;
453 |
454 | }
455 |
456 | var methods = [
457 | 'uniform1f', 'uniform1fv', 'uniform1i', 'uniform1iv',
458 | 'uniform2f', 'uniform2fv', 'uniform2i', 'uniform2iv',
459 | 'uniform3f', 'uniform3fv', 'uniform3i', 'uniform3iv',
460 | 'uniform4f', 'uniform4fv', 'uniform4i', 'uniform4iv',
461 | 'uniformMatrix2fv', 'uniformMatrix3fv', 'uniformMatrix4fv'
462 | ];
463 |
464 | methods.forEach( function( f ) {
465 |
466 | keepReference( f );
467 |
468 | WebGLRenderingContext.prototype[ f ] = function() {
469 |
470 | var args = arguments;
471 | var p = findProgramByLocation( args[ 0 ] );
472 | if( p ) {
473 | var l = references.getUniformLocation.apply( p.gl, [ p.program, p.uniform ] );
474 | var a = [];
475 | a.push( l );
476 | for( var j = 1; j < args.length; j++ ) {
477 | a.push( args[ j ] );
478 | }
479 | references[ f ].apply( p.gl, a );
480 | }
481 |
482 | }
483 |
484 | } );
485 |
486 | /*WebGLRenderingContext.prototype.useProgram = _h(
487 | WebGLRenderingContext.prototype.useProgram,
488 | function( res, args ) {
489 |
490 | console.log( 'useProgram', args );
491 |
492 | }
493 | );*/
494 |
495 | } )();
--------------------------------------------------------------------------------
/examples/deps/ShaderEditor.js:
--------------------------------------------------------------------------------
1 | ( function() {
2 |
3 | function _h( f, c ) {
4 | return function() {
5 | var res = f.apply( this, arguments );
6 | res = c.apply( this, [ res, arguments ] ) || res;
7 | return res;
8 | }
9 | }
10 |
11 | function _h2( f, c ) {
12 | return function() {
13 | return c.apply( this, arguments );
14 | }
15 | }
16 |
17 | var references = {};
18 | function keepReference( f ) {
19 |
20 | references[ f ] = WebGLRenderingContext.prototype[ f ];
21 |
22 | }
23 |
24 | var _gl = document.createElement( 'canvas' ).getContext( 'webgl' );
25 |
26 | keepReference( 'getUniformLocation' );
27 |
28 | function init() {
29 |
30 | var css = document.createElement( 'link' );
31 | css.rel = 'stylesheet'
32 | css.type = 'text/css';
33 | css.href = 'deps/CodeMirror.css';
34 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( css );
35 |
36 | var css = document.createElement( 'link' );
37 | css.rel = 'stylesheet'
38 | css.type = 'text/css';
39 | css.href = 'deps/styles.css';
40 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( css );
41 |
42 | var css = document.createElement( 'link' );
43 | css.rel = 'stylesheet'
44 | css.type = 'text/css';
45 | css.href = 'http://fonts.googleapis.com/css?family=Droid+Sans+Mono';
46 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( css );
47 |
48 | var editor = document.createElement( 'div' );
49 | editor.setAttribute( 'id', 'shaderEditor' );
50 | document.body.appendChild( editor );
51 | this.shaderEditor = editor;
52 |
53 | var p = document.createElement( 'p' );
54 | p.textContent = 'Programs';
55 | p.className = 'programs-title';
56 | editor.appendChild( p );
57 |
58 | var programList = document.createElement( 'ul' );
59 | programList.setAttribute( 'id', 'programList' );
60 | editor.appendChild( programList );
61 |
62 | var editorContainer = document.createElement( 'ul' );
63 | editorContainer.setAttribute( 'id', 'editorContainer' );
64 | editor.appendChild( editorContainer );
65 |
66 | var p = document.createElement( 'p' );
67 | p.textContent = 'Vertex Shader';
68 | p.className = 'vs-title';
69 | editorContainer.appendChild( p );
70 |
71 | var p = document.createElement( 'p' );
72 | p.textContent = 'Fragment Shader';
73 | p.className = 'fs-title';
74 | editorContainer.appendChild( p );
75 |
76 | var js = document.createElement( 'script' );
77 | js.src = 'deps/CodeMirror.js';
78 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( js );
79 | js.addEventListener( 'load', function() {
80 |
81 | var js = document.createElement( 'script' );
82 | js.src = 'deps/glsl.js';
83 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( js );
84 | js.addEventListener( 'load', function() {
85 |
86 | var el = document.createElement( 'style' );
87 | document.getElementsByTagName( 'head' )[ 0 ].appendChild( el );
88 | el.textContent = css;
89 |
90 | this.programList = programList;
91 |
92 | var options = {
93 | lineNumbers: true,
94 | matchBrackets: true,
95 | indentWithTabs: false,
96 | tabSize: 4,
97 | indentUnit: 4,
98 | mode: "text/x-glsl",
99 | foldGutter: true,
100 | gutters: ["CodeMirror-linenumbers", "CodeMirror-foldgutter"],
101 | };
102 |
103 | this.vsEditor = CodeMirror( editorContainer, options ),
104 | this.fsEditor = CodeMirror( editorContainer, options );
105 | this.vsEditor._errors = [];
106 | this.fsEditor._errors = [];
107 |
108 | this.vsEditor.getWrapperElement().setAttribute( 'id', 'vsEditor' );
109 | this.fsEditor.getWrapperElement().setAttribute( 'id', 'fsEditor' );
110 |
111 | var keyTimeout = 500;
112 | var vSTimeout;
113 | function scheduleUpdateVS() {
114 |
115 | if( vSTimeout ) vSTimeout = clearTimeout( vSTimeout );
116 | vSTimeout = setTimeout( update, keyTimeout );
117 |
118 | }
119 |
120 | var fSTimeout;
121 | function scheduleUpdateFS() {
122 |
123 | if( fSTimeout ) fSTimeout = clearTimeout( fSTimeout );
124 | fSTimeout = setTimeout( update, keyTimeout );
125 |
126 | }
127 |
128 | this.vsEditor.on( 'change', scheduleUpdateVS );
129 | this.fsEditor.on( 'change', scheduleUpdateFS );
130 |
131 | this.vsEditor.on( 'keyup', scheduleUpdateVS );
132 | this.fsEditor.on( 'keyup', scheduleUpdateFS );
133 |
134 | }.bind( this ) );
135 |
136 | }.bind( this ) );
137 |
138 | }
139 |
140 | function htmlEncode(str){
141 |
142 | return String(str)
143 | .replace(/&/g, '&')
144 | .replace(/"/g, '"')
145 | .replace(/'/g, ''')
146 | .replace(//g, '>');
148 |
149 | }
150 |
151 | function testShader( type, source, code ) {
152 |
153 | if( source === '' ) return;
154 |
155 | var s = _gl.createShader( type );
156 | _gl.shaderSource( s, source );
157 | _gl.compileShader( s );
158 |
159 | while( code._errors.length > 0 ) {
160 |
161 | var mark = code._errors.pop();
162 | code.removeLineWidget( mark );
163 |
164 | }
165 |
166 | if ( _gl.getShaderParameter( s, _gl.COMPILE_STATUS ) === false ) {
167 |
168 | var error = _gl.getShaderInfoLog( s );
169 |
170 | if( error==null )
171 | {
172 | /*this.mForceFrame = true;
173 | if( fromScript==false )
174 | {
175 | eleWrapper.className = "errorNo";
176 | setTimeout(function () { eleWrapper.className = ""; }, 500 );
177 | }*/
178 | }
179 | else
180 | {
181 | //eleWrapper.className = "errorYes";
182 |
183 | var lineOffset = 0;//this.mEffect.GetHeaderSize( this.mActiveDoc );
184 | var lines = error.match(/^.*((\r\n|\n|\r)|$)/gm);
185 | for( var i=0; i1 && parts[0]!="Warning")
199 | {
200 | console.log( parts.length + " **" + lines[i] );
201 |
202 | var txt = "";
203 | if( parts.length==4 )
204 | txt = parts[2] + " : " + parts[3];
205 | else
206 | txt = "Unknown error";
207 |
208 | var msg = document.createElement("div");
209 | msg.appendChild(document.createTextNode( txt ));
210 | msg.className = "errorMessage";
211 | var mark = code.addLineWidget( 0, msg, {coverGutter: false, noHScroll: true, above: true} );
212 | code._errors.push( mark );
213 |
214 | }
215 | }
216 | }
217 | // console.error( 'Shader couldn\'t compile.' );
218 | return false;
219 |
220 | }
221 |
222 | if ( _gl.getShaderInfoLog( s ) !== '' ) {
223 |
224 | console.error( '_gl.getShaderInfoLog()', _gl.getShaderInfoLog( s ) );
225 | return false;
226 |
227 | }
228 |
229 | return true;
230 |
231 | }
232 |
233 | init();
234 |
235 | this.programs = [];
236 | this.shaders = [];
237 | var uniforms = [];
238 | var currentProgram = null;
239 |
240 | function findProgram( p ) {
241 |
242 | var f = null;
243 | programs.forEach( function( e ) {
244 | if( e.program === p ) f = e;
245 | } );
246 | return f;
247 |
248 | }
249 |
250 | function findShader( s ) {
251 |
252 | var f = null;
253 |
254 | shaders.forEach( function( e ) {
255 | if( e.shader === s ) {
256 | f = e;
257 | }
258 | } );
259 |
260 | return f;
261 |
262 | }
263 |
264 | function addProgram( gl, p ) {
265 |
266 | this.shaderEditor.style.display = 'block';
267 |
268 | var li = document.createElement( 'li' );
269 | li.textContent = 'Program';
270 |
271 | var el = { gl: gl, program: p, shaders: [], li: li };
272 |
273 | li.addEventListener( 'click', function( e ) {
274 | selectProgram( el );
275 | e.preventDefault();
276 | } );
277 |
278 | programs.push( el );
279 |
280 | this.programList.appendChild( li );
281 |
282 | }
283 |
284 | function selectProgram( p ) {
285 |
286 | currentProgram = p;
287 | this.vsEditor.setValue( p.shaders[ 0 ].source );
288 | this.vsEditor.refresh();
289 |
290 | this.fsEditor.setValue( p.shaders[ 1 ].source );
291 | this.fsEditor.refresh();
292 |
293 | }
294 |
295 | function update() {
296 |
297 | if( !currentProgram ) return;
298 |
299 | var gl = currentProgram.gl,
300 | program = currentProgram.program,
301 | vertexShader = currentProgram.shaders[ 0 ].shader,
302 | fragmentShader = currentProgram.shaders[ 1 ].shader;
303 |
304 | if( currentProgram.shaders[ 0 ].type === gl.VERTEX_SHADER ) vertexShader = currentProgram.shaders[ 0 ].shader;
305 | if( currentProgram.shaders[ 0 ].type === gl.FRAGMENT_SHADER ) fragmentShader = currentProgram.shaders[ 0 ].shader;
306 | if( currentProgram.shaders[ 1 ].type === gl.VERTEX_SHADER ) vertexShader = currentProgram.shaders[ 1 ].shader;
307 | if( currentProgram.shaders[ 1 ].type === gl.FRAGMENT_SHADER ) fragmentShader = currentProgram.shaders[ 1 ].shader;
308 |
309 | //gl.detachShader( program, vertexShader );
310 | //gl.detachShader( program, fragmentShader );
311 |
312 | //vertexShader = gl.createShader( gl.VERTEX_SHADER );
313 | //fragmentShader = gl.createShader( gl.FRAGMENT_SHADER );
314 |
315 | if( !testShader( gl.VERTEX_SHADER, this.vsEditor.getValue(), this.vsEditor ) ) return false;
316 | if( !testShader( gl.FRAGMENT_SHADER, this.fsEditor.getValue(), this.fsEditor ) ) return false;
317 |
318 | gl.shaderSource( vertexShader, this.vsEditor.getValue() );
319 | gl.shaderSource( fragmentShader, this.fsEditor.getValue() );
320 |
321 | gl.compileShader( vertexShader );
322 |
323 | if ( gl.getShaderParameter( vertexShader, gl.COMPILE_STATUS ) === false ) {
324 |
325 | console.error( 'THREE.WebGLShader: Shader couldn\'t compile.' );
326 |
327 | }
328 |
329 | if ( gl.getShaderInfoLog( vertexShader ) !== '' ) {
330 |
331 | console.error( 'THREE.WebGLShader:', 'gl.getShaderInfoLog()', gl.getShaderInfoLog( vertexShader ) );
332 |
333 | }
334 |
335 | gl.compileShader( fragmentShader );
336 |
337 |
338 | if ( gl.getShaderParameter( fragmentShader, gl.COMPILE_STATUS ) === false ) {
339 |
340 | console.error( 'Shader couldn\'t compile.' );
341 |
342 | }
343 |
344 | if ( gl.getShaderInfoLog( fragmentShader ) !== '' ) {
345 |
346 | console.error( 'gl.getShaderInfoLog()', gl.getShaderInfoLog( fragmentShader ) );
347 |
348 | }
349 |
350 | gl.attachShader( program, vertexShader );
351 | gl.attachShader( program, fragmentShader );
352 |
353 | gl.linkProgram( program );
354 |
355 | if( !gl.getProgramParameter(program,gl.LINK_STATUS) ) {
356 | var infoLog = gl.getProgramInfoLog(program);
357 | //gl.deleteProgram( program );
358 | console.log( infoLog );
359 | }
360 |
361 | console.log( 'update' );
362 |
363 | }
364 |
365 | WebGLRenderingContext.prototype.createShader = _h(
366 | WebGLRenderingContext.prototype.createShader,
367 | function( res, args ) {
368 |
369 | console.log( 'createShader', args );
370 | shaders.push( { shader: res, type: args[ 0 ] } );
371 |
372 | }
373 | );
374 |
375 |
376 | WebGLRenderingContext.prototype.shaderSource = _h(
377 | WebGLRenderingContext.prototype.shaderSource,
378 | function( res, args ) {
379 |
380 | console.log( 'shaderSource', args );
381 | var s = findShader( args[ 0 ] );
382 | s.source = args[ 1 ];
383 |
384 | }
385 | );
386 |
387 | WebGLRenderingContext.prototype.compileShader = _h(
388 | WebGLRenderingContext.prototype.compileShader,
389 | function( res, args ) {
390 |
391 | console.log( 'compileShader', args );
392 |
393 | }
394 | );
395 |
396 | WebGLRenderingContext.prototype.createProgram = _h(
397 | WebGLRenderingContext.prototype.createProgram,
398 | function( res, args ) {
399 |
400 | console.log( 'createProgram', res, args );
401 | addProgram( this, res );
402 |
403 | }
404 | );
405 |
406 | WebGLRenderingContext.prototype.attachShader = _h(
407 | WebGLRenderingContext.prototype.attachShader,
408 | function( res, args ) {
409 |
410 | console.log( 'attachShader', args );
411 | var p = findProgram( args[ 0 ] );
412 | var s = findShader( args[ 1 ] );
413 | p.shaders.push( s );
414 |
415 | }
416 | );
417 |
418 | WebGLRenderingContext.prototype.linkProgram = _h(
419 | WebGLRenderingContext.prototype.linkProgram,
420 | function( res, args ) {
421 |
422 | console.log( 'linkProgram', args );
423 |
424 | }
425 | );
426 |
427 | WebGLRenderingContext.prototype.getUniformLocation = _h(
428 | WebGLRenderingContext.prototype.getUniformLocation,
429 | function( res, args ) {
430 |
431 | uniforms.push( {
432 | program: args[ 0 ],
433 | uniform: args[ 1 ],
434 | location: res,
435 | gl: this
436 | } );
437 | console.log( 'getUniformLocation', res, args );
438 |
439 | }
440 | );
441 |
442 | function findProgramByLocation( location ) {
443 |
444 | var f = null;
445 |
446 | uniforms.forEach( function( e ) {
447 | if( e.location === location ) {
448 | f = e;
449 | }
450 | } );
451 |
452 | return f;
453 |
454 | }
455 |
456 | var methods = [
457 | 'uniform1f', 'uniform1fv', 'uniform1i', 'uniform1iv',
458 | 'uniform2f', 'uniform2fv', 'uniform2i', 'uniform2iv',
459 | 'uniform3f', 'uniform3fv', 'uniform3i', 'uniform3iv',
460 | 'uniform4f', 'uniform4fv', 'uniform4i', 'uniform4iv',
461 | 'uniformMatrix2fv', 'uniformMatrix3fv', 'uniformMatrix4fv'
462 | ];
463 |
464 | methods.forEach( function( f ) {
465 |
466 | keepReference( f );
467 |
468 | WebGLRenderingContext.prototype[ f ] = function() {
469 |
470 | var args = arguments;
471 | var p = findProgramByLocation( args[ 0 ] );
472 | if( p ) {
473 | var l = references.getUniformLocation.apply( p.gl, [ p.program, p.uniform ] );
474 | var a = [];
475 | a.push( l );
476 | for( var j = 1; j < args.length; j++ ) {
477 | a.push( args[ j ] );
478 | }
479 | references[ f ].apply( p.gl, a );
480 | }
481 |
482 | }
483 |
484 | } );
485 |
486 | /*WebGLRenderingContext.prototype.useProgram = _h(
487 | WebGLRenderingContext.prototype.useProgram,
488 | function( res, args ) {
489 |
490 | console.log( 'useProgram', args );
491 |
492 | }
493 | );*/
494 |
495 | } )();
--------------------------------------------------------------------------------