diff --git a/ShaderPlayground/build/debug/main.js b/ShaderPlayground/build/debug/main.js index ccb86ca..420eb97 100644 --- a/ShaderPlayground/build/debug/main.js +++ b/ShaderPlayground/build/debug/main.js @@ -1 +1,626 @@ -var OS;!function(e){let t,i;!function(e){let t;!function(e){class t extends e.ListViewItemTag{itemlayout(){return{el:"div",children:[{el:"img",ref:"img"},{el:"p",ref:"name"}]}}ondatachange(){const e=this.data,t=this.refs.img,i=e.path.asFileHandle().getlink();t.src=i,$(this.refs.name).text(e.name)}init(){this.closable=!0}reload(e){}}e.define("afx-shader-texture-item",t)}(t=e.tag||(e.tag={}))}(t=e.GUI||(e.GUI={})),function(e){class i extends t.BasicDialog{constructor(){super("AddTextureDialog",i.scheme)}main(){super.main();const e=$("input",this.scheme);this.find("btnOk").onbtclick=t=>{let i={};for(const t of e){let e=t;if(""==e.value.trim())return this.notify(__("All fields should be filled"));i[e.name]=e.value.trim()}this.handle&&this.handle(i),this.quit()},this.find("btnFile").onbtclick=e=>{this.openDialog("FileDialog",{title:__("Select image file"),type:"file",mimes:["image/.*"]}).then(e=>{this.find("txtPath").value=e.file.path})}}}i.scheme='\n \n
\n \n
\n \n \n
\n \n \n \n \n \n
\n
\n \n
\n
\n
\n
\n
\n
';class s{constructor(e,t){this.glsl_values=[s.frg_template,""],this.renderer=t,this.ums=[new ace.UndoManager,new ace.UndoManager],this.current_idx=-1,this.tmp_canvas=$("")[0],this.gl_compiling_ctx=this.tmp_canvas.getContext("webgl"),this._filehandle=void 0,this.editormux=!1,ace.require("ace/ext/language_tools"),this._onfilechange=e=>{},this._ontextureadded=e=>{},this.editor=ace.edit(e),this.editor.setOptions({enableBasicAutocompletion:!0,enableLiveAutocompletion:!0,enableSnippets:!0,highlightActiveLine:!0}),this.editor.getSession().setUseWrapMode(!0),this.editor.session.setMode("ace/mode/glsl"),this.editor.setTheme("ace/theme/monokai"),this.cursors=[this.editor.getCursorPosition(),this.editor.getCursorPosition()],this.editor.on("input",e=>{const t=this.editor.getValue(),i=0==this.current_idx?this.gl_compiling_ctx.FRAGMENT_SHADER:this.gl_compiling_ctx.VERTEX_SHADER,s=this.compile(t,i);if(!1!==this.filehandle.dirty||this.editormux||(this.filehandle.dirty=!0,this._onfilechange(this.filehandle.path+"*")),this.editormux&&(this.editormux=!1),s){const e="ERROR:\\s*([0-9]+):([0-9]+):\\s*(.*)\\n",t=s.match(new RegExp(e,"g"));t&&this.editor.getSession().setAnnotations(t.map(t=>{const i=t.match(new RegExp(e));let s={};return i&&(s={row:parseInt(i[2])-1,column:0,text:i[3],type:"error"}),s}))}else this.editor.getSession().setAnnotations([]),this.glsl_values[this.current_idx]=t,this.renderer.apply_mat(this.glsl_values[0],this.glsl_values[1])})}set onfilechange(e){this._onfilechange=e}set ontextureadded(e){this._ontextureadded=e}set filehandle(e){this._filehandle=e,this.read()}get filehandle(){return this._filehandle}read(){return new Promise(async(e,t)=>{if(void 0===this._filehandle)return this.renderer.textures.length=0,this._filehandle="Untitled".asFileHandle(),this._onfilechange(this._filehandle.path),this.glsl_values=[s.frg_template,""],2!=this.current_idx&&-1!=this.current_idx&&(this.editormux=!0,this.editor.setValue(this.glsl_values[this.current_idx])),this._ontextureadded(void 0),e(void 0);try{const t=await this._filehandle.read("json");this.glsl_values[0]=t.source[0],this.glsl_values[1]=t.source[1],2!=this.current_idx&&-1!=this.current_idx&&(this.editormux=!0,this.editor.setValue(this.glsl_values[this.current_idx])),this._ontextureadded(void 0);for(const e of t.textures)this._ontextureadded(e);this._onfilechange(this._filehandle.path),e(void 0)}catch(e){t(e)}})}write(e){return new Promise(async(t,i)=>{let s=e;const n=__("Unknown save path");if(!s){if(void 0===this._filehandle)return i(n);s=this._filehandle.path}if("Untitled"===s)return i(n);try{this._filehandle.setPath(s);const e={};2!=this.current_idx&&(this.glsl_values[this.current_idx]=this.editor.getValue()),e.source=this.glsl_values,e.textures=this.renderer.textures.map(e=>({name:e.name,path:e.path})),this.filehandle.cache=e,await this.filehandle.write("object"),this._filehandle.dirty=!1,this._onfilechange(""+this.filehandle.path),t(void 0)}catch(e){i(e)}})}compile(e,t){let i=this.gl_compiling_ctx.createShader(t);this.gl_compiling_ctx.shaderSource(i,e),this.gl_compiling_ctx.compileShader(i);let s=void 0;return this.gl_compiling_ctx.getShaderParameter(i,this.gl_compiling_ctx.COMPILE_STATUS)||(s=this.gl_compiling_ctx.getShaderInfoLog(i)),this.gl_compiling_ctx.deleteShader(i),s}edit(e){if(e<0)return;if(2!=e&&2!=this.current_idx)0===e?(this.glsl_values[1]=this.editor.getValue(),this.cursors[1]=this.editor.getCursorPosition()):1===e&&(this.glsl_values[0]=this.editor.getValue(),this.cursors[0]=this.editor.getCursorPosition());else if(2==e)return this.glsl_values[this.current_idx]=this.editor.getValue(),this.cursors[this.current_idx]=this.editor.getCursorPosition(),void(this.current_idx=e);this.current_idx=e,this.editormux=!0,this.editor.getSession().setUndoManager(new ace.UndoManager),this.editor.setValue(this.glsl_values[e]),this.editor.getSession().setUndoManager(this.ums[e]);const t=this.cursors[e];this.editor.renderer.scrollCursorIntoView({row:t.row,column:t.column},.5),this.editor.selection.moveTo(t.row,t.column),this.editor.focus()}cleanup(){this.renderer.cleanup(),$(this.tmp_canvas).remove()}resize(){this.editor.resize(),this.renderer.viewport_resize()}}class n{constructor(e){this.textures=[],this.renderer=new THREE.WebGLRenderer({canvas:e,alpha:!0}),this.renderer.autoClearColor=!1,this.clock=new THREE.Clock,this.camera=new THREE.OrthographicCamera(-1,1,1,-1,-1,1),this.needupdateTexture=!1,this.scene=new THREE.Scene;const t=new THREE.MeshBasicMaterial({color:"white"}),i=new THREE.PlaneGeometry(2,2);this.mesh=new THREE.Mesh(i,t),this.scene.add(this.mesh),this.uniforms={u_resolution:{value:{x:0,y:0}},u_time:{value:0},u_mouse:{value:{x:0,y:0}}},this.viewport_resize(),this.ani_request_id=requestAnimationFrame(()=>this.viewport_render())}viewport_render(){this.needupdateTexture&&(this.update_textures(),this.needupdateTexture=!1),this.uniforms.u_time.value=this.clock.getElapsedTime();try{this.renderer.render(this.scene,this.camera)}catch(e){console.error(e)}this.ani_request_id=requestAnimationFrame(()=>this.viewport_render())}viewport_resize(){const e=this.renderer.domElement,t=e.clientWidth,i=e.clientHeight;this.uniforms.u_resolution.value.x=t,this.uniforms.u_resolution.value.y=i,(e.width!==t||e.height!==i)&&this.renderer.setSize(t,i,!1)}cleanup(){console.log("Stop the animation before quitting..."),window.cancelAnimationFrame(this.ani_request_id)}update_textures(){for(const e in this.uniforms)-1===["u_resolution","u_time","u_mouse"].indexOf(e)&&(this.uniforms[e]=new THREE.MeshBasicMaterial({color:"black"}));for(const e of this.textures)this.uniforms[e.name]={value:e.texture};console.log(this.uniforms)}apply_mat(e,t){const i={fragmentShader:""===e.trim()?"void main(){}":e,uniforms:this.uniforms,vertexShader:void 0};""!=t.trim()&&(i.vertexShader=t);const s=new THREE.ShaderMaterial(i);this.mesh.material=s,console.log(this.uniforms)}}s.frg_template="#ifdef GL_ES\nprecision mediump float;\n#endif\n// uniform vec2 u_resolution;\n// uniform vec2 u_mouse;\nuniform float u_time;\n\nvoid main() {\n gl_FragColor = vec4(abs(sin(u_time)),0.0,0.0,1.0);\n} ";class r extends e.BaseApplication{constructor(e){super("ShaderPlayground",e)}main(){this.init_editor(),this.init_textures_list(),this.bindKey("ALT-N",()=>this.newFile()),this.bindKey("ALT-O",()=>this.openFile()),this.bindKey("CTRL-S",()=>this.saveFile())}init_editor(){this.tabbar=this.find("tabbar"),this.tabbar.items=[{text:__("Fragment"),iconclass:"bi bi-palette"},{text:__("Vertex"),iconclass:"bi bi-intersect"},{text:__("Textures"),iconclass:"bi bi-image-alt"}],this.tabbar.ontabselect=e=>{this.selectTab()},this.editor=new s(this.find("editor-container"),new n(this.find("viewport"))),this.on("resize",e=>{this.editor.resize()}),this.editor.onfilechange=e=>{this.scheme.apptitle=e},this.editor.ontextureadded=e=>{this.add_texture(e)},this.editor.filehandle=void 0,this.tabbar.selected=0}add_texture(e){{const t=this.find("texture-list");if(!e)return this.editor.renderer.textures=[],t.data=this.editor.renderer.textures,void(this.editor.renderer.needupdateTexture=!0);const i=(new THREE.TextureLoader).load(e.path.asFileHandle().getlink());i.minFilter=THREE.NearestFilter,i.magFilter=THREE.NearestFilter,i.wrapS=THREE.RepeatWrapping,i.wrapT=THREE.RepeatWrapping,e.texture=i,t.push(e),this.editor.renderer.needupdateTexture=!0}}init_textures_list(){const e=this.find("texture-list");e.buttons=[{text:"__(Add texture)",iconclass:"bi bi-plus",onbtclick:e=>{this.openDialog(new i).then(e=>this.add_texture(e))}}],e.itemtag="afx-shader-texture-item",e.onitemclose=e=>(this.editor.renderer.needupdateTexture=!0,!0),this.add_texture(void 0)}selectTab(){const e=this.tabbar.selected;2===e?($(this.find("editor-container")).hide(),$(this.find("texture-list")).show()):($(this.find("editor-container")).show(),$(this.find("texture-list")).hide()),this.editor.edit(e)}menu(){return[{text:"__(File)",nodes:[{text:"__(New)",dataid:"new",shortcut:"A-N"},{text:"__(Open)",dataid:"open",shortcut:"A-O"},{text:"__(Save)",dataid:"save",shortcut:"C-S"}],onchildselect:e=>{switch(e.data.item.data.dataid){case"new":return this.newFile();case"open":return this.openFile();case"save":return this.saveFile()}}}]}ignore_unsaved(){return new Promise(async(e,t)=>!0===this.editor.filehandle.dirty?e(!!await this.ask({title:__("Unsaved shader"),text:__("Ignore unsaved file?")})):e(!0))}async newFile(){await this.ignore_unsaved()&&(this.editor.filehandle=void 0)}async openFile(){try{if(!await this.ignore_unsaved())return;const e=await this.openDialog("FileDialog",{title:__("Open file"),mimes:this.meta().mimes});this.editor.filehandle.setPath(e.file.path),await this.editor.read()}catch(e){this.error(__(e.toString()),e)}}async saveFile(){if("Untitled"!==this.editor.filehandle.path)return this.editor.write(void 0);const e=await this.openDialog("FileDialog",{title:__("Save as"),file:this.editor.filehandle});let t=e.file.path.asFileHandle();"file"===e.file.type&&(t=t.parent());try{await this.editor.write(`${t.path}/${e.name}`)}catch(e){this.error(__(e.toString()),e)}}cleanup(e){if(this.editor.filehandle.dirty)return this.ignore_unsaved().then(e=>{e&&(this.editor.filehandle.dirty=!1,this.quit(!0))}),void e.preventDefault();this.editor.cleanup()}}e.ShaderPlayground=r,r.dependencies=["pkg://libthreejs/main.js","pkg://ACECore/core/ace.js","pkg://ACECore/path.js","pkg://ACECore/core/ext-language_tools.js","pkg://ShaderPlayground/glslx.js"]}(i=e.application||(e.application={}))}(OS||(OS={})); \ No newline at end of file + +var OS; +(function (OS) { + let GUI; + (function (GUI) { + let tag; + (function (tag) { + class TextureListItem extends tag.ListViewItemTag { + itemlayout() { + return { + el: "div", + children: [ + { + el: "img", + ref: "img" + }, + { + el: "p", + ref: "name" + } + ] + }; + } + ondatachange() { + const v = this.data; + const img = this.refs.img; + const uri = v.path.asFileHandle().getlink(); + img.src = uri; + $(this.refs.name).text(v.name); + } + init() { + this.closable = true; + } + reload(d) { + } + } + tag.define("afx-shader-texture-item", TextureListItem); + })(tag = GUI.tag || (GUI.tag = {})); + })(GUI = OS.GUI || (OS.GUI = {})); + let application; + (function (application) { + class AddTextureDialog extends GUI.BasicDialog { + constructor() { + super("AddTextureDialog", AddTextureDialog.scheme); + } + main() { + super.main(); + const inputs = $("input", this.scheme); + this.find("btnOk").onbtclick = (e) => { + let cdata = {}; + for (const el of inputs) { + let input = el; + if (input.value.trim() == "") { + return this.notify(__("All fields should be filled")); + } + cdata[input.name] = input.value.trim(); + } + if (this.handle) + this.handle(cdata); + this.quit(); + }; + this.find("btnFile").onbtclick = (e) => { + this.openDialog("FileDialog", { + title: __("Select image file"), + type: "file", + mimes: ["image/.*"] + }) + .then((d) => { + this.find("txtPath").value = d.file.path; + }); + }; + } + } + AddTextureDialog.scheme = `\ + + +
+ +
+ + +
+ + + + + +
+
+ +
+
+
+
+
+
\ +`; + class ShaderEditor { + constructor(domel, renderer) { + this.glsl_values = [ShaderEditor.frg_template, ""]; + this.renderer = renderer; + this.ums = [new ace.UndoManager(), new ace.UndoManager()]; + this.current_idx = -1; + this.tmp_canvas = $("")[0]; + this.gl_compiling_ctx = this.tmp_canvas.getContext("webgl"); + this._filehandle = undefined; + this.editormux = false; + ace.require("ace/ext/language_tools"); + this._onfilechange = (v) => { }; + this._ontextureadded = (t) => { }; + this.editor = ace.edit(domel); + this.editor.setOptions({ + enableBasicAutocompletion: true, + enableLiveAutocompletion: true, + enableSnippets: true, + highlightActiveLine: true, + //fontSize: "9pt" + }); + this.editor.getSession().setUseWrapMode(true); + this.editor.session.setMode("ace/mode/glsl"); + this.editor.setTheme("ace/theme/monokai"); + this.cursors = [ + this.editor.getCursorPosition(), + this.editor.getCursorPosition() + ]; + this.editor.on("input", (e) => { + const value = this.editor.getValue(); + const stype = this.current_idx == 0 ? this.gl_compiling_ctx.FRAGMENT_SHADER : this.gl_compiling_ctx.VERTEX_SHADER; + const errors = this.compile(value, stype); + if (this.filehandle.dirty === false && !this.editormux) { + this.filehandle.dirty = true; + this._onfilechange(`${this.filehandle.path}*`); + } + if (this.editormux) { + this.editormux = false; + } + if (errors) { + const reg_str = "ERROR:\\s*([0-9]+):([0-9]+):\\s*(.*)\\n"; + const matches = errors.match(new RegExp(reg_str, "g")); + if (matches) { + this.editor.getSession().setAnnotations(matches.map((match) => { + const err_data = match.match(new RegExp(reg_str)); + let ret = {}; + if (err_data) { + ret = { + row: parseInt(err_data[2]) - 1, + column: 0, + text: err_data[3], + type: "error" + }; + } + return ret; + })); + } + } + else { + this.editor.getSession().setAnnotations([]); + this.glsl_values[this.current_idx] = value; + this.renderer.apply_mat(this.glsl_values[0], this.glsl_values[1]); + } + }); + } + set onfilechange(fn) { + this._onfilechange = fn; + } + set ontextureadded(fn) { + this._ontextureadded = fn; + } + set filehandle(v) { + this._filehandle = v; + this.read(); + } + get filehandle() { + return this._filehandle; + } + read() { + return new Promise(async (resolve, reject) => { + if (this._filehandle === undefined) { + this.renderer.textures.length = 0; + this._filehandle = "Untitled".asFileHandle(); + this._onfilechange(this._filehandle.path); + this.glsl_values = [ShaderEditor.frg_template, ""]; + if (this.current_idx != 2 && this.current_idx != -1) { + this.editormux = true; + this.editor.setValue(this.glsl_values[this.current_idx]); + } + this._ontextureadded(undefined); + return resolve(undefined); + } + try { + const data = await this._filehandle.read("json"); + this.glsl_values[0] = data.source[0]; + this.glsl_values[1] = data.source[1]; + if (this.current_idx != 2 && this.current_idx != -1) { + this.editormux = true; + this.editor.setValue(this.glsl_values[this.current_idx]); + } + this._ontextureadded(undefined); + for (const v of data.textures) { + this._ontextureadded(v); + } + this._onfilechange(this._filehandle.path); + resolve(undefined); + } + catch (e) { + reject(e); + } + }); + } + write(p) { + return new Promise(async (resolve, reject) => { + let path = p; + const error = __("Unknown save path"); + if (!path) { + if (this._filehandle === undefined) + return reject(error); + path = this._filehandle.path; + } + if (path === "Untitled") { + return reject(error); + } + try { + this._filehandle.setPath(path); + const data = {}; + if (this.current_idx != 2) { + this.glsl_values[this.current_idx] = this.editor.getValue(); + } + data.source = this.glsl_values; + data.textures = this.renderer.textures.map((v) => { + return { + name: v.name, + path: v.path + }; + }); + this.filehandle.cache = data; + const ret = await this.filehandle.write("object"); + this._filehandle.dirty = false; + this._onfilechange(`${this.filehandle.path}`); + resolve(undefined); + } + catch (e) { + reject(e); + } + }); + } + compile(code, type) { + // Compiles either a shader of type gl.VERTEX_SHADER or gl.FRAGMENT_SHADER + let shader = this.gl_compiling_ctx.createShader(type); + this.gl_compiling_ctx.shaderSource(shader, code); + this.gl_compiling_ctx.compileShader(shader); + let errors = undefined; + if (!this.gl_compiling_ctx.getShaderParameter(shader, this.gl_compiling_ctx.COMPILE_STATUS)) { + errors = this.gl_compiling_ctx.getShaderInfoLog(shader); + } + this.gl_compiling_ctx.deleteShader(shader); + return errors; + } + edit(index) { + if (index < 0) { + return; + } + if (index != 2 && this.current_idx != 2) { + if (index === 0) { + this.glsl_values[1] = this.editor.getValue(); + this.cursors[1] = this.editor.getCursorPosition(); + } + else if (index === 1) { + this.glsl_values[0] = this.editor.getValue(); + this.cursors[0] = this.editor.getCursorPosition(); + } + } + else if (index == 2) { + this.glsl_values[this.current_idx] = this.editor.getValue(); + this.cursors[this.current_idx] = this.editor.getCursorPosition(); + this.current_idx = index; + return; + } + this.current_idx = index; + this.editormux = true; + this.editor.getSession().setUndoManager(new ace.UndoManager()); + this.editor.setValue(this.glsl_values[index]); + this.editor.getSession().setUndoManager(this.ums[index]); + const c = this.cursors[index]; + this.editor.renderer.scrollCursorIntoView({ + row: c.row, + column: c.column, + }, 0.5); + this.editor.selection.moveTo(c.row, c.column); + this.editor.focus(); + } + cleanup() { + this.renderer.cleanup(); + $(this.tmp_canvas).remove(); + } + resize() { + this.editor.resize(); + this.renderer.viewport_resize(); + } + } + ; + class ShaderRenderer { + constructor(canvas) { + this.textures = []; + this.renderer = new THREE.WebGLRenderer({ + canvas: canvas, + alpha: true + }); + this.renderer.autoClearColor = false; + this.clock = new THREE.Clock(); + this.camera = new THREE.OrthographicCamera(-1, // left + 1, // right + 1, // top + -1, // bottom + -1, // near, + 1); + this.needupdateTexture = false; + this.scene = new THREE.Scene(); + const material = new THREE.MeshBasicMaterial({ + color: 'white', + }); + const plane = new THREE.PlaneGeometry(2, 2); + this.mesh = new THREE.Mesh(plane, material); + this.scene.add(this.mesh); + this.uniforms = { + u_resolution: { value: { x: 0, y: 0 } }, + u_time: { value: 0.0 }, + u_mouse: { value: { x: 0, y: 0 } }, + }; + this.viewport_resize(); + this.ani_request_id = requestAnimationFrame(() => this.viewport_render()); + } + viewport_render() { + if (this.needupdateTexture) { + this.update_textures(); + this.needupdateTexture = false; + } + this.uniforms.u_time.value = this.clock.getElapsedTime(); + try { + this.renderer.render(this.scene, this.camera); + } + catch (e) { + console.error(e); + } + this.ani_request_id = requestAnimationFrame(() => this.viewport_render()); + } + viewport_resize() { + const canvas = this.renderer.domElement; + const width = canvas.clientWidth; + const height = canvas.clientHeight; + this.uniforms.u_resolution.value.x = width; + this.uniforms.u_resolution.value.y = height; + const needResize = canvas.width !== width || canvas.height !== height; + if (needResize) { + this.renderer.setSize(width, height, false); + } + } + cleanup() { + console.log("Stop the animation before quitting..."); + window.cancelAnimationFrame(this.ani_request_id); + } + update_textures() { + for (const key in this.uniforms) { + if (["u_resolution", "u_time", "u_mouse"].indexOf(key) === -1) { + this.uniforms[key] = new THREE.MeshBasicMaterial({ + color: 'black', + }); + } + } + for (const v of this.textures) { + this.uniforms[v.name] = { value: v.texture }; + } + console.log(this.uniforms); + } + apply_mat(fragment_shader, vertex_shader) { + const empty_main = "void main(){}"; + const opts = { + fragmentShader: fragment_shader.trim() === "" ? empty_main : fragment_shader, + uniforms: this.uniforms, + vertexShader: undefined + }; + if (vertex_shader.trim() != "") + opts.vertexShader = vertex_shader; + const mat = new THREE.ShaderMaterial(opts); + this.mesh.material = mat; + console.log(this.uniforms); + } + } + ShaderEditor.frg_template = `\ +#ifdef GL_ES +precision mediump float; +#endif +// uniform vec2 u_resolution; +// uniform vec2 u_mouse; +uniform float u_time; + +void main() { + gl_FragColor = vec4(abs(sin(u_time)),0.0,0.0,1.0); +}\ + `; + /** + * + * @class ShaderPlayground + * @extends {BaseApplication} + */ + class ShaderPlayground extends application.BaseApplication { + constructor(args) { + super("ShaderPlayground", args); + } + main() { + this.init_editor(); + this.init_textures_list(); + this.bindKey("ALT-N", () => { + return this.newFile(); + }); + this.bindKey("ALT-O", () => { + return this.openFile(); + }); + this.bindKey("CTRL-S", () => { + return this.saveFile(); + }); + } + /** + * Init the editor for fragment and + * vertex shader + */ + init_editor() { + this.tabbar = this.find("tabbar"); + this.tabbar.items = [ + { + text: __("Fragment"), + iconclass: "bi bi-palette" + }, + { + text: __("Vertex"), + iconclass: "bi bi-intersect" + }, + { + text: __("Textures"), + iconclass: "bi bi-image-alt" + } + ]; + this.tabbar.ontabselect = (_e) => { + this.selectTab(); + }; + this.editor = new ShaderEditor(this.find("editor-container"), new ShaderRenderer(this.find("viewport"))); + this.on("resize", (e) => { + this.editor.resize(); + }); + this.editor.onfilechange = (v) => { + this.scheme.apptitle = v; + }; + this.editor.ontextureadded = (v) => { + this.add_texture(v); + }; + this.editor.filehandle = undefined; + this.tabbar.selected = 0; + } + add_texture(data) { + { + const listview = this.find("texture-list"); + if (!data) { + this.editor.renderer.textures = []; + listview.data = this.editor.renderer.textures; + this.editor.renderer.needupdateTexture = true; + return; + } + const loader = new THREE.TextureLoader(); + const texture = loader.load(data.path.asFileHandle().getlink()); + texture.minFilter = THREE.NearestFilter; + texture.magFilter = THREE.NearestFilter; + texture.wrapS = THREE.RepeatWrapping; + texture.wrapT = THREE.RepeatWrapping; + data.texture = texture; + listview.push(data); + this.editor.renderer.needupdateTexture = true; + } + } + init_textures_list() { + const listview = this.find("texture-list"); + listview.buttons = [ + { + text: "__(Add texture)", + iconclass: "bi bi-plus", + onbtclick: (_e) => { + this + .openDialog(new AddTextureDialog()) + .then((data) => this.add_texture(data)); + } + } + ]; + listview.itemtag = "afx-shader-texture-item"; + listview.onitemclose = (e) => { + this.editor.renderer.needupdateTexture = true; + return true; + }; + this.add_texture(undefined); + } + selectTab() { + const index = this.tabbar.selected; + if (index === 2) { + $(this.find("editor-container")).hide(); + $(this.find("texture-list")).show(); + } + else { + $(this.find("editor-container")).show(); + $(this.find("texture-list")).hide(); + } + this.editor.edit(index); + } + menu() { + return [ + { + text: "__(File)", + nodes: [ + { + text: "__(New)", + dataid: "new", + shortcut: 'A-N' + }, + { + text: "__(Open)", + dataid: "open", + shortcut: 'A-O' + }, + { + text: "__(Save)", + dataid: "save", + shortcut: 'C-S' + } + ], + onchildselect: (e) => { + switch (e.data.item.data.dataid) { + case "new": + return this.newFile(); + case "open": + return this.openFile(); + case "save": + return this.saveFile(); + } + } + } + ]; + } + ignore_unsaved() { + return new Promise(async (resolve, reject) => { + if (this.editor.filehandle.dirty === true) { + const r = await this.ask({ + title: __("Unsaved shader"), + text: __("Ignore unsaved file?") + }); + if (!r) { + return resolve(false); + } + return resolve(true); + } + return resolve(true); + }); + } + async newFile() { + const ignore = await this.ignore_unsaved(); + if (!ignore) + return; + this.editor.filehandle = undefined; + } + async openFile() { + try { + const ignore = await this.ignore_unsaved(); + if (!ignore) + return; + const d = await this.openDialog("FileDialog", { + title: __("Open file"), + mimes: this.meta().mimes + }); + this.editor.filehandle.setPath(d.file.path); + await this.editor.read(); + } + catch (e) { + this.error(__(e.toString()), e); + } + } + async saveFile() { + if (this.editor.filehandle.path !== "Untitled") { + return this.editor.write(undefined); + } + const f = await this.openDialog("FileDialog", { + title: __("Save as"), + file: this.editor.filehandle + }); + let handle = f.file.path.asFileHandle(); + if (f.file.type === "file") { + handle = handle.parent(); + } + try { + await this.editor.write(`${handle.path}/${f.name}`); + } + catch (e) { + this.error(__(e.toString()), e); + } + } + cleanup(e) { + if (this.editor.filehandle.dirty) { + this.ignore_unsaved() + .then((d) => { + if (d) { + this.editor.filehandle.dirty = false; + this.quit(true); + } + }); + e.preventDefault(); + return; + } + this.editor.cleanup(); + } + } + application.ShaderPlayground = ShaderPlayground; + /** + * Application dependenicies preload + */ + ShaderPlayground.dependencies = [ + "pkg://libthreejs/main.js", + "pkg://ACECore/core/ace.js", + "pkg://ACECore/path.js", + "pkg://ACECore/core/ext-language_tools.js" + ]; + })(application = OS.application || (OS.application = {})); +})(OS || (OS = {})); diff --git a/ShaderPlayground/build/release/ShaderPlayground.zip b/ShaderPlayground/build/release/ShaderPlayground.zip deleted file mode 100644 index 214df13..0000000 Binary files a/ShaderPlayground/build/release/ShaderPlayground.zip and /dev/null differ diff --git a/ShaderPlayground/main.ts b/ShaderPlayground/main.ts index 053a4ac..71afec2 100644 --- a/ShaderPlayground/main.ts +++ b/ShaderPlayground/main.ts @@ -753,8 +753,7 @@ void main() { "pkg://libthreejs/main.js", "pkg://ACECore/core/ace.js", "pkg://ACECore/path.js", - "pkg://ACECore/core/ext-language_tools.js", - "pkg://ShaderPlayground/glslx.js" + "pkg://ACECore/core/ext-language_tools.js" ]; } } \ No newline at end of file