gui.js (380 lines of code) (raw):

const deepClone = require('./deep-clone.js'); const C = require('./constants.js'); const is = require('./check-layer-type.js'); const randomize = require('./randomize.js'); const dat = require('dat.gui'); const update = (gui) => () => { for (let i in gui.__controllers) { gui.__controllers[i].updateDisplay(); } for (let i in gui.__folders) { update(gui.__folders[i])(); } } const updateSizeSet = (target, constants) => (mode) => { const set = getSizeSet(mode, constants); const keys = Object.keys(set); let innerHTMLStr = ""; for (let i in keys) { const str = "<option value='" + set[keys[i]] + "'>" + keys[i] + "</option>"; innerHTMLStr += str; } if (innerHTMLStr != "") target.domElement.children[0].innerHTML = innerHTMLStr; target.updateDisplay(); } const getSizeSet = (mode, constants) => { const modeValues = constants['sizes'].filter(s => s.mode == mode); if (modeValues.length < 1) return []; let sizeSet = {}; modeValues[0]['values'].forEach(value => { sizeSet[value.label] = value.code; }); sizeSet['browser'] = 'browser'; return sizeSet; } const Config = function(layers, defaults, constants, funcs, randomize) { const customAdd = C.BLEND_FUNCS['+']; const one = C.BLEND_FACTORS['1']; const zero = C.BLEND_FACTORS['0']; const mode = defaults.mode; this.product = defaults.product; const sizePresetSet = getSizeSet(mode, constants); layers.forEach((layer, index) => { if (layer.kind == 'webgl') { if (mode !== 'prod') { if (layer.blend[0]) { const blend = layer.blend[0]; this['blendColor' + index] = blend.color || [ 1, 0, 0, 0 ]; // FIXME: get RGBA components this['blendColorEqFn' + index] = C.BLEND_FUNCS[C.funcKeys[blend.colorEq[0]]]; this['blendColorEqFactor0' + index] = C.BLEND_FACTORS[C.factorKeys[blend.colorEq[1]]]; this['blendColorEqFactor1' + index] = C.BLEND_FACTORS[C.factorKeys[blend.colorEq[2]]]; this['blendAlphaEqFn' + index] = C.BLEND_FUNCS[C.funcKeys[blend.alphaEq[0]]]; this['blendAlphaEqFactor0' + index] = C.BLEND_FACTORS[C.factorKeys[blend.alphaEq[1]]]; this['blendAlphaEqFactor1' + index] = C.BLEND_FACTORS[C.factorKeys[blend.alphaEq[2]]]; } else { this['blendColor' + index] = [ 0, 0, 0, 0 ]; this['blendColorEqFn' + index] = customAdd; this['blendColorEqFactor0' + index] = one; this['blendColorEqFactor1' + index] = zero; this['blendAlphaEqFn' + index] = customAdd; this['blendAlphaEqFactor0' + index] = one; this['blendAlphaEqFactor1' + index] = zero; } } else { // mode == 'prod' this['blendSet' + index] = C.BLEND_SETS['soft']; this['blendColor' + index] = layer.blend[0].color || [ 1, 0, 0, 0 ]; // FIXME: get RGBA components } } else { // kind != 'webgl' if (!is.background(layer)) { this['layer' + index + 'Blend'] = layer.blend[1] || 'normal'; } } this['visible' + index] = !!layer.isOn; if (!is.background(layer) && !is.cover(layer)) { this['opacity' + index] = layer.opacity; } if (is.fss(layer)) { this['mirror' + index] = layer.model.mirror; this['renderMode' + index] = 'triangles'; this['lightSpeed' + index] = layer.model.lightSpeed; this['facesX' + index] = layer.model.faces.x; this['facesY' + index] = layer.model.faces.y; this['vignette' + index] = layer.model.vignette; this['iris' + index] = layer.model.iris; this['amplitudeX' + index] = layer.model.amplitude[0]; this['amplitudeY' + index] = layer.model.amplitude[1]; this['amplitudeZ' + index] = layer.model.amplitude[2]; this['opacity' + index] = layer.model.opacity; this['hue' + index] = layer.model.colorShift[0]; this['saturation' + index] = layer.model.colorShift[1]; this['brightness' + index] = layer.model.colorShift[2]; } if (is.cover(layer)) { this['productShown'+index] = !!layer.model.productShown; } if (is.fluid(layer) || is.nativeMetaballs(layer)) { if (is.fluid(layer)) { this['bang' + index] = () => funcs.refreshFluid(index); this['rebuildGradients' + index] = () => funcs.rebuildFluidGradients(index); } if (is.nativeMetaballs(layer)) { this['bang' + index] = () => funcs.refreshNativeMetaballs(index); } this['variety'+index] = layer.model.variety; this['orbit'+index] = layer.model.orbit; this['blur'+index] = layer.model.effects.blur; this['fat'+index] = layer.model.effects.fat; this['ring'+index] = layer.model.effects.ring; } if (is.background(layer)) { const stopStates = layer.model.stops || []; const gradientType = layer.model.orientation || "linear"; this['isRadial'+index] = gradientType == "radial"; this['stop1'+index] = stopStates[0] == "on"; this['stop2'+index] = stopStates[1] == "on"; this['stop3'+index] = stopStates[2] == "on"; this['darken'+index] = layer.model.darken; } }); //this.customSize = sizePresetSet['browser']; this.sizePreset = sizePresetSet['browser']; //this.savePng = funcs.savePng; this.saveBatch = () => funcs.saveBatch(/*Object.values(sizePresetSet)*/); // this.randomize = randomize(this); // FIXME: this way we updated FSS using "I feel lucky", consider returning it back in some way this.randomize = () => funcs.iFeelLucky(); // this.store = () => funcs.store(); // ------- //this.timeShift = 0; // this.getSceneJson = funcs.getSceneJson; // this.loadSceneJson = funcs.loadSceneJson; //this.exportZip = funcs.exportZip; }; function start(document, model, constants, funcs) { const defaults = model; const { mode, layers } = model; const sizePresetSet = getSizeSet(mode, constants); const products = constants.products; const productToId = {}; products.forEach((product) => { productToId[product.label] = product.id; }); const productsById = {}; products.forEach((product) => { productsById[product.id] = product; }); function updateProduct(id) { const product = productsById[id]; funcs.changeProduct(product.id); } function switchLayer(index) { return function(on) { if (on) funcs.turnOn(index); else funcs.turnOff(index); } } function switchMirror(index, on) { if (on) funcs.mirrorOn(index); else funcs.mirrorOff(index); } function updateWebGLBlend(index, f) { return function(value) { const color = config['blendColor'+index]; const curBlend = { color: { r: color[0], g: color[1], b: color[2], a: color[3] } , colorEq: [ C.BLEND_FUNCS_IDS[config['blendColorEqFn'+index]] , C.BLEND_FACTORS_IDS[config['blendColorEqFactor0'+index]] , C.BLEND_FACTORS_IDS[config['blendColorEqFactor1'+index]] ] , alphaEq: [ C.BLEND_FUNCS_IDS[config['blendAlphaEqFn'+index]] , C.BLEND_FACTORS_IDS[config['blendAlphaEqFactor0'+index]] , C.BLEND_FACTORS_IDS[config['blendAlphaEqFactor1'+index]] ] } const newBlend = f(curBlend, value); funcs.changeWGLBlend(index, newBlend); } } function addWebGLBlend(folder, config, layer, index) { if (mode !== 'prod') { const blendFolder = folder.addFolder('blend'); const color = blendFolder.addColor(config, 'blendColor' + index); const colorEqFn = blendFolder.add(config, 'blendColorEqFn' + index, C.BLEND_FUNCS); const colorEqFactor0 = blendFolder.add(config, 'blendColorEqFactor0' + index, C.BLEND_FACTORS); const colorEqFactor1 = blendFolder.add(config, 'blendColorEqFactor1' + index, C.BLEND_FACTORS); const alphaEqFn = blendFolder.add(config, 'blendAlphaEqFn' + index, C.BLEND_FUNCS); const alphaEqFactor0 = blendFolder.add(config, 'blendAlphaEqFactor0' + index, C.BLEND_FACTORS); const alphaEqFactor1 = blendFolder.add(config, 'blendAlphaEqFactor1' + index, C.BLEND_FACTORS); //folder.open(); color.onFinishChange(updateWebGLBlend(index, (blend, value) => { blend.color = { r: value[0], g: value[1], b: value[2], a: value[3] } return blend; })); colorEqFn.onFinishChange(updateWebGLBlend(index, (blend, value) => { blend.colorEq[0] = C.BLEND_FUNCS_IDS[value]; return blend; })); colorEqFactor0.onFinishChange(updateWebGLBlend(index, (blend, value) => { blend.colorEq[1] = C.BLEND_FACTORS_IDS[value]; return blend; })); colorEqFactor1.onFinishChange(updateWebGLBlend(index, (blend, value) => { blend.colorEq[2] = C.BLEND_FACTORS_IDS[value]; return blend; })); alphaEqFn.onFinishChange(updateWebGLBlend(index, (blend, value) => { blend.alphaEq[0] = C.BLEND_FUNCS_IDS[value]; return blend; })); alphaEqFactor0.onFinishChange(updateWebGLBlend(index, (blend, value) => { blend.alphaEq[1] = C.BLEND_FACTORS_IDS[value]; return blend; })); alphaEqFactor1.onFinishChange(updateWebGLBlend(index, (blend, value) => { blend.alphaEq[2] = C.BLEND_FACTORS_IDS[value]; return blend; })); } else { // mode == 'prod' const blendSet = folder.add(config, 'blendSet' + index, C.BLEND_SETS).name('blend'); // const blendColor = folder.addColor(config, 'blendColor' + index).name('color'); // blendColor.onFinishChange(updateWebGLBlend(index, (blend, value) => { // blend.color = { r: value[0], g: value[1], b: value[2], a: value[3] } // return blend; // })); blendSet.onFinishChange((value) => { blendConfig = value.split(','); const color = config['blendColor'+index] || [ 0, 0, 0, 1 ]; const newBlend = { color: { r: color[0], g: color[1], b: color[2], a: color[3] } , colorEq: [ C.BLEND_FUNCS_IDS[C.BLEND_FUNCS[blendConfig[0]]] , C.BLEND_FACTORS_IDS[C.BLEND_FACTORS[blendConfig[1]]] , C.BLEND_FACTORS_IDS[C.BLEND_FACTORS[blendConfig[2]]] ] , alphaEq: [ C.BLEND_FUNCS_IDS[C.BLEND_FUNCS[blendConfig[3]]] , C.BLEND_FACTORS_IDS[C.BLEND_FACTORS[blendConfig[4]]] , C.BLEND_FACTORS_IDS[C.BLEND_FACTORS[blendConfig[5]]] ] } funcs.changeWGLBlend(index, newBlend); // blend.alphaEq[2] = BLEND_FACTORS_IDS[value]; //return blend; }); } } function addHtmlBlend(folder, config, layer, index) { const blendControl = folder.add(config, 'layer' + index + 'Blend', C.HTML_BLENDS).name('blend'); blendControl.onFinishChange((value) => { funcs.changeHtmlBlend(index, value); }); } function addLayerProps(folder, config, layer, index) { if (is.fss(layer)) { const mirrorSwitch = folder.add(config, 'mirror' + index).name('rorschach'); const lightSpeed = folder.add(config, 'lightSpeed' + index).name('light pace') .min(100).max(2000); const facesX = folder.add(config, 'facesX' + index).name('columns').min(1).max(100).step(1); const facesY = folder.add(config, 'facesY' + index).name('rows').min(1).max(100).step(1); const fogFolder = folder.addFolder('fog'); const vignette = fogFolder.add(config, 'vignette' + index).name('shine').min(0).max(1).step(0.01); const iris = fogFolder.add(config, 'iris' + index).name('density').min(0).max(1).step(0.01); const renderMode = folder.add(config, 'renderMode' + index, C.RENDER_MODES).name('structure'); const amplitudeFolder = folder.addFolder('ranges'); const amplitudeX = amplitudeFolder.add(config, 'amplitudeX' + index).name('horizontal') .min(0.0).max(1.0); const amplitudeY = amplitudeFolder.add(config, 'amplitudeY' + index).name('vertical') .min(0.0).max(1.0); const amplitudeZ = amplitudeFolder.add(config, 'amplitudeZ' + index).name('depth') .min(0.0).max(1.0); const opacity = folder.add(config, 'opacity' + index).name('opacity').min(0).max(1).step(0.01); const colorShiftFolder = folder.addFolder('coloring'); const hue = colorShiftFolder.add(config, 'hue' + index).name('hue') .min(-1.0).max(1.0).step(0.01); const saturation = colorShiftFolder.add(config, 'saturation' + index).name('saturation') .min(-1.0).max(1.0).step(0.01); const brightness = colorShiftFolder.add(config, 'brightness' + index).name('brightness') .min(-1.0).max(1.0).step(0.01); mirrorSwitch.onFinishChange(val => switchMirror(index, val)); lightSpeed.onFinishChange(funcs.changeLightSpeed(index)); facesX.onFinishChange(funcs.changeFacesX(index)); facesY.onFinishChange(funcs.changeFacesY(index)); vignette.onFinishChange(funcs.changeVignette(index)); iris.onFinishChange(funcs.changeIris(index)); renderMode.onFinishChange(funcs.changeRenderMode(index)); amplitudeX.onFinishChange(value => { funcs.changeAmplitude(index)(value, null, null); }); amplitudeY.onFinishChange(value => { funcs.changeAmplitude(index)(null, value, null); }); amplitudeZ.onFinishChange(value => { funcs.changeAmplitude(index)(null, null, value); }); opacity.onFinishChange(funcs.changeOpacity(index)); hue.onFinishChange(value => { funcs.shiftColor(index)(value, null, null); }); saturation.onFinishChange(value => { funcs.shiftColor(index)(null, value, null); }); brightness.onFinishChange(value => { funcs.shiftColor(index)(null, null, value); }); } if (layer.visible != 'locked') { const visibitySwitch = folder.add(config, 'visible' + index).name('visible'); visibitySwitch.onFinishChange(switchLayer(index)); } if (!is.background(layer) && !is.cover(layer)) { const opacity = folder.add(config, 'opacity' + index).name('opacity').min(0.0).max(1).step(0.01); opacity.onFinishChange(funcs.changeOpacity(index)); } if (is.cover(layer)) { const productVisibilitySwitch = folder.add(config, 'productShown' + index).name('title'); productVisibilitySwitch.onFinishChange(funcs.switchCoverProductVisibility(index)); } if (is.fluid(layer) || is.nativeMetaballs(layer)) { folder.add(config, 'bang' + index).name('bang'); if (is.fluid(layer)) { folder.add(config, 'rebuildGradients' + index).name('regenerate gradients'); } const variety = folder.add(config, 'variety' + index).name('variety').min(0.01).max(1).step(0.01); const orbit = folder.add(config, 'orbit' + index).name('orbit').min(0).max(1).step(0.05); const blur = folder.add(config, 'blur' + index).name('myopia').min(0).max(1).step(0.01); const fat = folder.add(config, 'fat' + index).name('fat').min(0).max(1).step(0.01); const ring = folder.add(config, 'ring' + index).name('x-ray').min(0).max(1).step(0.01); variety.onFinishChange( is.fluid(layer) ? funcs.changeFluidVariety(index) : funcs.changeNativeMetaballsVariety(index)); orbit.onFinishChange( is.fluid(layer) ? funcs.changeFluidOrbit(index) : funcs.changeNativeMetaballsOrbit(index)); blur.onFinishChange( funcs.changeNativeMetaballsEffects(index, 'blur')); fat.onFinishChange( funcs.changeNativeMetaballsEffects(index, 'fat')); ring.onFinishChange( funcs.changeNativeMetaballsEffects(index, 'ring')); } if (is.background(layer)) { const stop1 = folder.add(config, 'stop1' + index).name('heaven'); const stop2 = folder.add(config, 'stop2' + index).name('dragons'); const stop3 = folder.add(config, 'stop3' + index).name('earth'); const switchStop = funcs.switchBackgroundStop; stop1.onFinishChange(switchStop(index, 0)); stop2.onFinishChange(switchStop(index, 1)); stop3.onFinishChange(switchStop(index, 2)); const gradientType = folder.add(config, 'isRadial' + index).name('radial'); gradientType.onFinishChange(funcs.switchBackgroundGradientType(index)); const darken = folder.add(config, 'darken' + index).name('darken').min(0.0).max(1).step(0.01); darken.onFinishChange(funcs.darkenBackground(index)); } } const gui = new dat.GUI(/*{ load: JSON }*/); const config = new Config(layers, defaults, constants, funcs, randomize(funcs.applyRandomizer, model, update(gui))); const product = gui.add(config, 'product', productToId); const sizePreset = gui.add(config, 'sizePreset', sizePresetSet).name('size'); // gui.add(config, 'savePng').name('save png'); if (mode !== 'prod') gui.add(config, 'saveBatch').name('save batch'); gui.add(config, 'randomize').name('i feel lucky'); // gui.add(config, 'store').name('store'); product.onFinishChange(updateProduct); sizePreset.onFinishChange(funcs.resize); const layersNames = ['heraldry', 'upper lava', 'lower lava', 'canvas']; layers.forEach((layer, index) => { // if ((mode == 'prod') && (layer.name == 'Cover')) return; //console.log(layer); //const index = layers.length - 1 - revIndex; //const folder = gui.addFolder('Layer ' + index + ' (' + layer.kind + ')'); // const folder = gui.addFolder(layer.def.toLowerCase() + ' (' + index + ')'); const folder = gui.addFolder(layersNames[index]); addLayerProps(folder, config, layer, index); if (layer.king == 'webgl') { addWebGLBlend(folder, config, layer, index); } else { if (!is.background(layer)) { addHtmlBlend(folder, config, layer, index); } } }); let guiHidden = false; //update(gui); document.addEventListener('keydown', (event) => { if (event.keyCode == 32) { if (guiHidden) { document.querySelectorAll('.dg')[0].style.display = 'block'; gui.open(); } else { document.querySelectorAll('.dg')[0].style.display = 'none'; gui.close(); } guiHidden = !guiHidden; } }); // const textBlend = gui.add(config, 'textBlend', HTML_BLENDS); // textBlend.onFinishChange((value) => { // funcs.changeHtmlBlend(2, value); // }); // const logoBlend = gui.add(config, 'logoBlend', HTML_BLENDS); // logoBlend.onFinishChange((value) => { // funcs.changeHtmlBlend(3, value); // }); //updateProduct('jetbrains'); // layers.map((layer, index) => { // gui.addFolder() // }); return { config, update : update(gui), updateSizeSet : updateSizeSet(sizePreset, constants) }; } module.exports = start;