// WebGL Sandbox // Copyright (c) Leo C. Singleton IV // See LICENSE in the project root for license information. import { IPerformanceResults, fim, opSelectChannel, perfTestAsync } from './Common'; import { createSampleShaders } from './SampleShaders'; import { Shader } from './Shader'; import { Texture } from './Texture'; import { DisposableSet, usingAsync } from '@leosingleton/commonlibs'; import { FimDimensions, FimImageOptions, FimTextureSampling } from '@leosingleton/fim'; import { FimBrowserImage } from '@leosingleton/fim-browser'; import { saveAs } from 'file-saver'; import { GlslVariable } from 'webpack-glsl-minify'; $(async () => { // Load previous shaders from local storage on startup shaders = await Shader.createAllFromLocalStorage(); // If there are no shaders in local storage, populate the app with some sample ones to get started if (shaders.length === 0) { shaders = await createSampleShaders(); // Write the sample shaders to local storage for (const shader of shaders) { shader.writeToLocalStorage(); } } refreshShaderList(); }); export namespace Editor { export function addShader(): void { onEditShader(); } export async function addShaderOk(): Promise { try { const name = $('#add-shader-name').val().toString(); if (!name) { throw new Error('Name is required'); } const source = $('#add-shader-source').val().toString(); if (!source) { throw new Error('Source code is required'); } const shader = new Shader(name, source, currentShader); await shader.compile(); shader.writeToLocalStorage(); shaders = shaders.filter(s => s !== currentShader); shaders.push(shader); refreshShaderList(); $('#add-shader').modal('hide'); } catch (err) { $('#add-shader-errors').text(err); $('#add-shader-errors').show(); } } /** Handler for the 'Run Performance Test' button in the execute shader dialog */ export async function executePerformanceTest(): Promise { try { const results = await runCurrentShader(true) as IPerformanceResults; $('#performance-results-body').text(results.message); $('#performance-results').modal('show'); } catch (err) { $('#execute-shader-errors').text(err); $('#execute-shader-errors').show(); } } /** Handler for the OK button in the execute shader dialog */ export async function executeShaderOk(): Promise { try { const canvas = await runCurrentShader() as FimBrowserImage; currentShader.executionCount++; const textureName = $('#execute-shader-name').val().toString(); const texture = new Texture(textureName, canvas); textures.push(texture); refreshTextureList(); $('#execute-shader').modal('hide'); } catch (err) { $('#execute-shader-errors').text(err); $('#execute-shader-errors').show(); } } export async function uploadShaders(files: FileList): Promise { // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < files.length; i++) { shaders.push(await Shader.createFromFile(files[i])); } refreshShaderList(); } export async function uploadTextures(files: FileList): Promise { // eslint-disable-next-line @typescript-eslint/prefer-for-of for (let i = 0; i < files.length; i++) { textures.push(await Texture.createFromFile(files[i])); } refreshTextureList(); } } let shaders: Shader[] = []; function refreshShaderList(): void { // Sort alphabetically by name shaders = shaders.sort(sortByName); $('#shaders tr').remove(); for (const shader of shaders) { const row = $('').appendTo('#shaders'); row.append($('').text(shader.name)); const actions = $('').appendTo(row); actions.append($('Execute').click(() => onExecuteShader(shader))); actions.append(' | '); actions.append($('Edit').click(() => onEditShader(shader))); actions.append(' | '); actions.append($('Delete').click(() => onDeleteShader(shader))); } } let currentShader: Shader = null; /** Displays the execute shader dialog box */ function onExecuteShader(shader: Shader): void { currentShader = shader; const s = shader.shader; // Initialize the name of the texture const textureName = `Output of ${shader.name} ${shader.executionCount + 1}`; $('#execute-shader-name').val(textureName); // Remove all previous edit controls $('#execute-shader-form div').remove(); // Add edit controls for consts for (const cname in s.consts) { const c = s.consts[cname] as GlslVariable; const id = `const-${cname}`; const text = `${cname} (${c.variableType})`; const value = shader.values[id]; const group = $('
').appendTo('#execute-shader-form'); group.append($('