├── .gitignore
├── README.md
├── index.html
├── js
├── compiler.js
└── editor.js
└── style.css
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | *.swp
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | `Ctrl + Enter` or `Command + Enter` to run your code.
2 |
3 | # Qiita
4 | https://qiita.com/JPNYKW/items/7096fe59d1edf3ef3aa3
5 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | WebGL Shader Editor
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/js/compiler.js:
--------------------------------------------------------------------------------
1 | const vertexShader = `
2 | attribute vec3 position;
3 | void main(void) {
4 | gl_Position = vec4(position, 1.0);
5 | }
6 | `;
7 |
8 | const render = input => {
9 | errorLog.value = '';
10 |
11 | const fragmentShader = input;
12 | const createProgram = (vs, fs) => {
13 | let stack = ctx.createProgram();
14 |
15 | ctx.attachShader(stack, vs);
16 | ctx.attachShader(stack, fs);
17 | ctx.linkProgram(stack);
18 |
19 | if (ctx.getProgramParameter(stack, ctx.LINK_STATUS)) {
20 | console.log('Success ');
21 | ctx.useProgram(stack);
22 | return stack;
23 | } else {
24 | return null;
25 | }
26 | };
27 |
28 | const createShader = (script, type) => {
29 | let shader = null;
30 | if (type == 'v') shader = ctx.createShader(ctx.VERTEX_SHADER);
31 | if (type == 'f') shader = ctx.createShader(ctx.FRAGMENT_SHADER);
32 |
33 | ctx.shaderSource(shader, script);
34 | ctx.compileShader(shader);
35 |
36 | if (ctx.getShaderParameter(shader, ctx.COMPILE_STATUS)) {
37 | console.log('Success ');
38 | return shader;
39 | } else {
40 | const error = ctx.getShaderInfoLog(shader);
41 | // console.log('Error', error);
42 | errorLog.value = error.toString();
43 | }
44 | };
45 |
46 | const createVbo = data => {
47 | let vbo = ctx.createBuffer();
48 | ctx.bindBuffer(ctx.ARRAY_BUFFER, vbo);
49 | ctx.bufferData(ctx.ARRAY_BUFFER, new Float32Array(data), ctx.STATIC_DRAW);
50 | ctx.bindBuffer(ctx.ARRAY_BUFFER, null);
51 |
52 | return vbo;
53 | };
54 |
55 | const createIbo = data => {
56 | let ibo = ctx.createBuffer();
57 | ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, ibo);
58 | ctx.bufferData(ctx.ELEMENT_ARRAY_BUFFER, new Int16Array(data), ctx.STATIC_DRAW);
59 | ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, null);
60 |
61 | return ibo;
62 | };
63 |
64 | const program = createProgram(createShader(vertexShader, 'v'), createShader(fragmentShader, 'f'));
65 |
66 | const uniform = [];
67 | uniform[0] = ctx.getUniformLocation(program, 'time');
68 | uniform[1] = ctx.getUniformLocation(program, 'resolution');
69 |
70 | const position = [
71 | -1.0, 1.0, 0.0,
72 | 1.0, 1.0, 0.0,
73 | -1.0, -1.0, 0.0,
74 | 1.0, -1.0, 0.0
75 | ];
76 |
77 | const index = [
78 | 0, 2, 1,
79 | 1, 2, 3
80 | ];
81 |
82 | const vbo_Index = createIbo(index);
83 | const vbo_Position = createVbo(position);
84 | const vbo_AttLocation = ctx.getAttribLocation(program, 'position');
85 |
86 | ctx.bindBuffer(ctx.ARRAY_BUFFER, vbo_Position);
87 | ctx.enableVertexAttribArray(vbo_AttLocation);
88 | ctx.vertexAttribPointer(vbo_AttLocation, 3, ctx.FLOAT, false, 0, 0);
89 | ctx.bindBuffer(ctx.ELEMENT_ARRAY_BUFFER, vbo_Index);
90 | ctx.clearColor(0.0, 0.0, 0.0, 1.0);
91 |
92 | const tick = () => {
93 | const sec = (new Date().getTime() - time) / 1000;
94 | ctx.clear(ctx.COLOR_BUFFER_BIT);
95 |
96 | ctx.uniform1f(uniform[0], sec);
97 | ctx.uniform2fv(uniform[1], [width, height]);
98 | ctx.drawElements(ctx.TRIANGLES, 6, ctx.UNSIGNED_SHORT, 0);
99 | ctx.flush();
100 |
101 | time++;
102 | requestAnimationFrame(tick);
103 | }
104 |
105 | let time = new Date().getTime();
106 | tick();
107 | }
108 |
109 | const errorLog = document.getElementById('error');
110 |
111 | const canvas = document.getElementById('canvas');
112 | const height = innerHeight * 0.8;
113 | const width = innerWidth * 0.5;
114 | canvas.height = height;
115 | canvas.width = width;
116 |
117 | const ctx = canvas.getContext('webgl') || canvas.getContext('experimental-webgl');
118 |
--------------------------------------------------------------------------------
/js/editor.js:
--------------------------------------------------------------------------------
1 | (() => {
2 | const keyBuffer = [];
3 |
4 | window.onload = () => {
5 | const editor = ace.edit('editor');
6 | editor.$blockScrolling = Infinity;
7 |
8 | editor.setFontSize(13);
9 | editor.getSession().setMode("ace/mode/glsl");
10 | editor.setTheme('ace/theme/tomorrow_night_eighties');
11 |
12 | editor.setOptions({
13 | enableBasicAutocompletion: true,
14 | enableSnippets: true,
15 | enableLiveAutocompletion: true
16 | });
17 |
18 | // editor.setValue('// write your cool shader in here.');
19 | editor.setValue('precision mediump float;\nuniform vec2 resolution;\n\nvoid main() {\n\t// write your cool shader in here ...\n\tvec2 position = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);\n\tvec3 color = vec3(position.x, position.y, 0.0);\n\tgl_FragColor = vec4(color, 1.0);\n}');
20 |
21 | const editorElement = document.getElementById('editor');
22 |
23 | editorElement.addEventListener('keydown', (event) => {
24 | keyBuffer[event.keyCode] = true;
25 |
26 | if (keyBuffer[13] && (keyBuffer[17] || keyBuffer[91])) {
27 | keyBuffer[13] = false;
28 | keyBuffer[17] = false;
29 | keyBuffer[91] = false;
30 | render(editor.getValue());
31 | }
32 | });
33 |
34 | editorElement.addEventListener('keyup', (event) => {
35 | keyBuffer[event.keyCode] = false;
36 | });
37 | };
38 | })();
39 |
--------------------------------------------------------------------------------
/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | background: #171717;
3 |
4 | height: 100%;
5 | width: 100%;
6 | }
7 |
8 | #editor {
9 | position: absolute;
10 | left: 0;
11 | top: 0;
12 |
13 | padding: 0;
14 | margin: 0;
15 |
16 | height: 80% !important;
17 | width: 50%;
18 | }
19 |
20 | #canvas {
21 | position: absolute;
22 | right: 0;
23 | top: 0;
24 | }
25 |
26 | #error {
27 | position: absolute;
28 | bottom: 0;
29 | left: 0;
30 |
31 | height: 20%;
32 | width: 100%;
33 |
34 | background: none;
35 | border: none;
36 | resize: none;
37 |
38 | font-size: 18px;
39 | color: #d8d8d8;
40 | }
41 |
--------------------------------------------------------------------------------