diff --git a/ShaderPlayground/build/debug/main.js b/ShaderPlayground/build/debug/main.js index 420eb97..8a044b5 100644 --- a/ShaderPlayground/build/debug/main.js +++ b/ShaderPlayground/build/debug/main.js @@ -1,626 +1 @@ - -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 = {})); +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"]}(i=e.application||(e.application={}))}(OS||(OS={})); \ No newline at end of file