├── .gitignore ├── 3rd ├── colorPicker.js ├── colors.js ├── custom-theme │ ├── images │ │ ├── ui-bg_flat_0_aaaaaa_40x100.png │ │ ├── ui-bg_flat_15_777777_40x100.png │ │ ├── ui-bg_flat_16_151515_40x100.png │ │ ├── ui-bg_glass_95_fef1ec_1x400.png │ │ ├── ui-bg_highlight-hard_55_555555_1x100.png │ │ ├── ui-bg_highlight-soft_35_adadad_1x100.png │ │ ├── ui-bg_highlight-soft_60_dddddd_1x100.png │ │ ├── ui-bg_inset-soft_15_121212_1x100.png │ │ ├── ui-icons_666666_256x240.png │ │ ├── ui-icons_aaaaaa_256x240.png │ │ ├── ui-icons_bbbbbb_256x240.png │ │ ├── ui-icons_c98000_256x240.png │ │ ├── ui-icons_cccccc_256x240.png │ │ ├── ui-icons_cd0a0a_256x240.png │ │ └── ui-icons_f29a00_256x240.png │ └── jquery-ui-1.8.16.custom.css ├── dat.gui.js ├── download.png ├── images │ ├── ui-bg_diagonals-thick_18_b81900_40x40.png │ ├── ui-bg_diagonals-thick_20_666666_40x40.png │ ├── ui-bg_flat_10_000000_40x100.png │ ├── ui-bg_glass_100_f6f6f6_1x400.png │ ├── ui-bg_glass_100_fdf5ce_1x400.png │ ├── ui-bg_glass_65_ffffff_1x400.png │ ├── ui-bg_gloss-wave_35_f6a828_500x100.png │ ├── ui-bg_highlight-soft_100_eeeeee_1x100.png │ ├── ui-bg_highlight-soft_75_ffe45c_1x100.png │ ├── ui-icons_222222_256x240.png │ ├── ui-icons_228ef1_256x240.png │ ├── ui-icons_ef8c08_256x240.png │ ├── ui-icons_ffd27a_256x240.png │ └── ui-icons_ffffff_256x240.png ├── jqColorPicker.js ├── jquery-1.11.2.min.js ├── jquery-1.6.2.min.js ├── jquery-ui-1.8.16.custom.min.js ├── jquery-ui.min.css ├── jquery-ui.min.js ├── jquery.text-overflow.js ├── sam.gui.js ├── three.js └── three.min.js ├── README.rst ├── convtester ├── bootstrap.min.css ├── d3.v3.min.js ├── index.html └── justified-nav.css ├── css ├── experiments.css └── paintflow.css ├── fastmccabe ├── index.html ├── render.js └── style.css ├── frustratedflockingfluid ├── grayscott.js ├── grayscott.png └── index.html ├── gaussian-smoothlife ├── grayscott.js └── index.html ├── gradientui ├── gradientui.css ├── gradientui.js └── index.html ├── grayscott ├── grayscott.js ├── grayscott.png └── index.html ├── gsimage ├── grayscott.js ├── index.html ├── lena.js └── lena512.jpg ├── index.html ├── massspring ├── index.html ├── particles.js ├── particles.png └── scenes.js ├── opticalflowtest ├── clicktopaint.png ├── index.html └── opticalflow.js ├── paintflow ├── index.html └── paintflow.js ├── paintflow2 ├── clicktopaint.png ├── index.html └── paintflow.js ├── softmaxdenoise ├── index.html ├── mandrill_noisy.jpg ├── softmax.css ├── softmax.js ├── tetons.jpg ├── tetons.png ├── tetons2.jpg ├── tetons2.png └── tetons3.jpg ├── softmaxdenoisecolor ├── frog.jpg ├── index.html ├── softmax.css ├── softmax.js └── toucan.jpg ├── waveletsharpen ├── index.html ├── sharpen.js └── tetons.jpg └── waveletsharpencolor ├── frog.jpg ├── index.html └── sharpen.js /.gitignore: -------------------------------------------------------------------------------- 1 | ################# 2 | ## Eclipse 3 | ################# 4 | 5 | *.pydevproject 6 | .project 7 | .metadata 8 | bin/ 9 | tmp/ 10 | *.tmp 11 | *.bak 12 | *.swp 13 | *~.nib 14 | local.properties 15 | .classpath 16 | .settings/ 17 | .loadpath 18 | 19 | # External tool builders 20 | .externalToolBuilders/ 21 | 22 | # Locally stored "Eclipse launch configurations" 23 | *.launch 24 | 25 | # CDT-specific 26 | .cproject 27 | 28 | # PDT-specific 29 | .buildpath 30 | 31 | 32 | ################# 33 | ## Visual Studio 34 | ################# 35 | 36 | ## Ignore Visual Studio temporary files, build results, and 37 | ## files generated by popular Visual Studio add-ons. 38 | 39 | # User-specific files 40 | *.suo 41 | *.user 42 | *.sln.docstates 43 | 44 | # Build results 45 | 46 | [Dd]ebug/ 47 | [Rr]elease/ 48 | x64/ 49 | build/ 50 | [Bb]in/ 51 | [Oo]bj/ 52 | 53 | # MSTest test Results 54 | [Tt]est[Rr]esult*/ 55 | [Bb]uild[Ll]og.* 56 | 57 | *_i.c 58 | *_p.c 59 | *.ilk 60 | *.meta 61 | *.obj 62 | *.pch 63 | *.pdb 64 | *.pgc 65 | *.pgd 66 | *.rsp 67 | *.sbr 68 | *.tlb 69 | *.tli 70 | *.tlh 71 | *.tmp 72 | *.tmp_proj 73 | *.log 74 | *.vspscc 75 | *.vssscc 76 | .builds 77 | *.pidb 78 | *.log 79 | *.scc 80 | 81 | # Visual C++ cache files 82 | ipch/ 83 | *.aps 84 | *.ncb 85 | *.opensdf 86 | *.sdf 87 | *.cachefile 88 | 89 | # Visual Studio profiler 90 | *.psess 91 | *.vsp 92 | *.vspx 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | 101 | # TeamCity is a build add-in 102 | _TeamCity* 103 | 104 | # DotCover is a Code Coverage Tool 105 | *.dotCover 106 | 107 | # NCrunch 108 | *.ncrunch* 109 | .*crunch*.local.xml 110 | 111 | # Installshield output folder 112 | [Ee]xpress/ 113 | 114 | # DocProject is a documentation generator add-in 115 | DocProject/buildhelp/ 116 | DocProject/Help/*.HxT 117 | DocProject/Help/*.HxC 118 | DocProject/Help/*.hhc 119 | DocProject/Help/*.hhk 120 | DocProject/Help/*.hhp 121 | DocProject/Help/Html2 122 | DocProject/Help/html 123 | 124 | # Click-Once directory 125 | publish/ 126 | 127 | # Publish Web Output 128 | *.Publish.xml 129 | *.pubxml 130 | *.publishproj 131 | 132 | # NuGet Packages Directory 133 | ## TODO: If you have NuGet Package Restore enabled, uncomment the next line 134 | #packages/ 135 | 136 | # Windows Azure Build Output 137 | csx 138 | *.build.csdef 139 | 140 | # Windows Store app package directory 141 | AppPackages/ 142 | 143 | # Others 144 | sql/ 145 | *.Cache 146 | ClientBin/ 147 | [Ss]tyle[Cc]op.* 148 | ~$* 149 | *~ 150 | *.dbmdl 151 | *.[Pp]ublish.xml 152 | *.pfx 153 | *.publishsettings 154 | 155 | # RIA/Silverlight projects 156 | Generated_Code/ 157 | 158 | # Backup & report files from converting an old project file to a newer 159 | # Visual Studio version. Backup files are not needed, because we have git ;-) 160 | _UpgradeReport_Files/ 161 | Backup*/ 162 | UpgradeLog*.XML 163 | UpgradeLog*.htm 164 | 165 | # SQL Server files 166 | App_Data/*.mdf 167 | App_Data/*.ldf 168 | 169 | ############# 170 | ## Windows detritus 171 | ############# 172 | 173 | # Windows image file caches 174 | Thumbs.db 175 | ehthumbs.db 176 | 177 | # Folder config file 178 | Desktop.ini 179 | 180 | # Recycle Bin used on file shares 181 | $RECYCLE.BIN/ 182 | 183 | # Mac crap 184 | .DS_Store 185 | 186 | 187 | ############# 188 | ## Python 189 | ############# 190 | 191 | *.py[cod] 192 | 193 | # Packages 194 | *.egg 195 | *.egg-info 196 | dist/ 197 | build/ 198 | eggs/ 199 | parts/ 200 | var/ 201 | sdist/ 202 | develop-eggs/ 203 | .installed.cfg 204 | 205 | # Installer logs 206 | pip-log.txt 207 | 208 | # Unit test / coverage reports 209 | .coverage 210 | .tox 211 | 212 | #Translations 213 | *.mo 214 | 215 | #Mr Developer 216 | .mr.developer.cfg 217 | 218 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion 219 | 220 | *.iml 221 | 222 | ## Directory-based project format: 223 | .idea/ 224 | -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-bg_flat_0_aaaaaa_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-bg_flat_0_aaaaaa_40x100.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-bg_flat_15_777777_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-bg_flat_15_777777_40x100.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-bg_flat_16_151515_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-bg_flat_16_151515_40x100.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-bg_glass_95_fef1ec_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-bg_glass_95_fef1ec_1x400.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-bg_highlight-hard_55_555555_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-bg_highlight-hard_55_555555_1x100.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-bg_highlight-soft_35_adadad_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-bg_highlight-soft_35_adadad_1x100.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-bg_highlight-soft_60_dddddd_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-bg_highlight-soft_60_dddddd_1x100.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-bg_inset-soft_15_121212_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-bg_inset-soft_15_121212_1x100.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-icons_666666_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-icons_666666_256x240.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-icons_aaaaaa_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-icons_aaaaaa_256x240.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-icons_bbbbbb_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-icons_bbbbbb_256x240.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-icons_c98000_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-icons_c98000_256x240.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-icons_cccccc_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-icons_cccccc_256x240.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-icons_cd0a0a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-icons_cd0a0a_256x240.png -------------------------------------------------------------------------------- /3rd/custom-theme/images/ui-icons_f29a00_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/custom-theme/images/ui-icons_f29a00_256x240.png -------------------------------------------------------------------------------- /3rd/download.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/download.png -------------------------------------------------------------------------------- /3rd/images/ui-bg_diagonals-thick_18_b81900_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-bg_diagonals-thick_18_b81900_40x40.png -------------------------------------------------------------------------------- /3rd/images/ui-bg_diagonals-thick_20_666666_40x40.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-bg_diagonals-thick_20_666666_40x40.png -------------------------------------------------------------------------------- /3rd/images/ui-bg_flat_10_000000_40x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-bg_flat_10_000000_40x100.png -------------------------------------------------------------------------------- /3rd/images/ui-bg_glass_100_f6f6f6_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-bg_glass_100_f6f6f6_1x400.png -------------------------------------------------------------------------------- /3rd/images/ui-bg_glass_100_fdf5ce_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-bg_glass_100_fdf5ce_1x400.png -------------------------------------------------------------------------------- /3rd/images/ui-bg_glass_65_ffffff_1x400.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-bg_glass_65_ffffff_1x400.png -------------------------------------------------------------------------------- /3rd/images/ui-bg_gloss-wave_35_f6a828_500x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-bg_gloss-wave_35_f6a828_500x100.png -------------------------------------------------------------------------------- /3rd/images/ui-bg_highlight-soft_100_eeeeee_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-bg_highlight-soft_100_eeeeee_1x100.png -------------------------------------------------------------------------------- /3rd/images/ui-bg_highlight-soft_75_ffe45c_1x100.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-bg_highlight-soft_75_ffe45c_1x100.png -------------------------------------------------------------------------------- /3rd/images/ui-icons_222222_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-icons_222222_256x240.png -------------------------------------------------------------------------------- /3rd/images/ui-icons_228ef1_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-icons_228ef1_256x240.png -------------------------------------------------------------------------------- /3rd/images/ui-icons_ef8c08_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-icons_ef8c08_256x240.png -------------------------------------------------------------------------------- /3rd/images/ui-icons_ffd27a_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-icons_ffd27a_256x240.png -------------------------------------------------------------------------------- /3rd/images/ui-icons_ffffff_256x240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/3rd/images/ui-icons_ffffff_256x240.png -------------------------------------------------------------------------------- /3rd/jqColorPicker.js: -------------------------------------------------------------------------------- 1 | ;(function($, Colors, undefined){ 2 | 'use strict'; 3 | 4 | var $document = $(document), 5 | _instance, 6 | _colorPicker, 7 | _color, 8 | _options, 9 | _selector = '', 10 | 11 | _$trigger, 12 | _$UI, _$xy_slider, _$xy_cursor, _$z_cursor , _$alpha , _$alpha_cursor, 13 | 14 | _pointermove = 'touchmove mousemove pointermove', 15 | _pointerup = 'touchend mouseup pointerup', 16 | _GPU = false, 17 | _animate = window.requestAnimationFrame || 18 | window.webkitRequestAnimationFrame || function(cb){cb()}, 19 | _html = '
', 23 | // 'grunt-contrib-uglify' puts all this back to one single string... 24 | _css = '.cp-color-picker{position:absolute;overflow:hidden;padding:6p' + 25 | 'x 6px 0;background-color:#444;color:#bbb;font-family:Arial,Helve' + 26 | 'tica,sans-serif;font-size:12px;font-weight:400;cursor:default;bo' + 27 | 'rder-radius:5px}.cp-color-picker>div{position:relative;overflow:' + 28 | 'hidden}.cp-xy-slider{float:left;height:128px;width:128px;margin-' + 29 | 'bottom:6px;background:linear-gradient(to right,#FFF,rgba(255,255' + 30 | ',255,0))}.cp-white{height:100%;width:100%;background:linear-grad' + 31 | 'ient(rgba(0,0,0,0),#000)}.cp-xy-cursor{position:absolute;top:0;w' + 32 | 'idth:10px;height:10px;margin:-5px;border:1px solid #fff;border-r' + 33 | 'adius:100%;box-sizing:border-box}.cp-z-slider{float:right;margin' + 34 | '-left:6px;height:128px;width:20px;background:linear-gradient(red' + 35 | ' 0,#f0f 17%,#00f 33%,#0ff 50%,#0f0 67%,#ff0 83%,red 100%)}.cp-z-' + 36 | 'cursor{position:absolute;margin-top:-4px;width:100%;border:4px s' + 37 | 'olid #fff;border-color:transparent #fff;box-sizing:border-box}.c' + 38 | 'p-alpha{clear:both;width:100%;height:16px;margin:6px 0;backgroun' + 39 | 'd:linear-gradient(to right,#444,rgba(0,0,0,0))}.cp-alpha-cursor{' + 40 | 'position:absolute;margin-left:-4px;height:100%;border:4px solid ' + 41 | '#fff;border-color:#fff transparent;box-sizing:border-box}', 42 | 43 | ColorPicker = function(options) { 44 | _color = this.color = new Colors(options); 45 | _options = _color.options; 46 | }; 47 | 48 | ColorPicker.prototype = { 49 | render: preRender, 50 | toggle: toggle 51 | } 52 | 53 | function extractValue(elm) { 54 | return elm.value || elm.getAttribute('value') || 55 | $(elm).css('background-color') || '#fff'; 56 | } 57 | 58 | function resolveEventType(event) { 59 | return event.originalEvent.touches ? 60 | event.originalEvent.touches[0] : event; 61 | } 62 | 63 | function findElement($elm) { 64 | return $($elm.find(_options.doRender)[0] || $elm[0]); 65 | } 66 | 67 | function toggle(event) { 68 | var $this = $(this), 69 | position = $this.offset(), 70 | $window = $(window), 71 | gap = _options.gap; 72 | 73 | if (event) { 74 | _$trigger = findElement($this); 75 | _colorPicker.$trigger = $this; 76 | 77 | (_$UI || build()).css({ 78 | // 'width': _$UI[0]._width, 79 | 'left': (_$UI[0]._left = position.left) - 80 | ((_$UI[0]._left = _$UI[0]._left + _$UI[0]._width - 81 | ($window.scrollLeft() + $window.width())) + gap > 0 ? 82 | _$UI[0]._left + gap : 0), 83 | 'top': (_$UI[0]._top = position.top + $this.outerHeight()) - 84 | ((_$UI[0]._top = _$UI[0]._top + _$UI[0]._height - 85 | ($window.scrollTop() + $window.height())) + gap > 0 ? 86 | _$UI[0]._top + gap : 0) 87 | }).show(_options.animationSpeed, function() { 88 | if (event === true) { 89 | return; 90 | } 91 | _$alpha._width = _$alpha.width(); 92 | _$xy_slider._width = _$xy_slider.width(); 93 | _$xy_slider._height = _$xy_slider.height(); 94 | _color.setColor(extractValue(_$trigger[0])); 95 | 96 | preRender(true); 97 | }); 98 | } else { 99 | $(_$UI).hide(_options.animationSpeed, function() { 100 | _$trigger.blur(); 101 | _colorPicker.$trigger = null; 102 | preRender(false); 103 | }); 104 | } 105 | }; 106 | 107 | function build() { 108 | $('head').append(''); 110 | 111 | return _colorPicker.$UI = _$UI = 112 | $(_html).css({'margin': _options.margin}). 113 | appendTo('body'). 114 | show(0, function() { 115 | _GPU = _options.GPU && $(this).css('perspective') !== undefined; 116 | _$xy_slider = $('.cp-xy-slider', this); 117 | _$xy_cursor = $('.cp-xy-cursor', this); 118 | _$z_cursor = $('.cp-z-cursor', this); 119 | _$alpha = $('.cp-alpha', this).toggle(!!_options.opacity); 120 | _$alpha_cursor = $('.cp-alpha-cursor', this); 121 | _options.buidCallback.call(_colorPicker, $(this)); 122 | $(this).prepend('
').children().eq(0).css('width', 123 | $(this).children().eq(0).width() // stabilizer 124 | ); 125 | this._width = this.offsetWidth; 126 | this._height = this.offsetHeight; 127 | }).hide(). 128 | on('touchstart mousedown pointerdown', 129 | '.cp-xy-slider,.cp-z-slider,.cp-alpha', pointerdown); 130 | } 131 | 132 | function pointerdown(e) { 133 | var action = this.className. 134 | replace(/cp-(.*?)(?:\s*|$)/, '$1').replace('-', '_'); 135 | 136 | e.preventDefault && e.preventDefault(); 137 | e.returnValue = false; 138 | 139 | _$trigger._offset = $(this).offset(); 140 | (action = action === 'xy_slider' ? xy_slider : 141 | action === 'z_slider' ? z_slider : alpha)(e); 142 | 143 | $document.on(_pointerup, pointerup).on(_pointermove, action); 144 | } 145 | 146 | function pointerup(e) { 147 | $document.off(_pointermove).off(_pointerup); 148 | } 149 | 150 | function xy_slider(event) { 151 | var e = resolveEventType(event), 152 | x = e.pageX - _$trigger._offset.left, 153 | y = e.pageY - _$trigger._offset.top; 154 | 155 | _color.setColor({ 156 | s: x / _$xy_slider._width * 100, 157 | v: 100 - (y / _$xy_slider._height * 100) 158 | }, 'hsv'); 159 | preRender(); 160 | } 161 | 162 | function z_slider(event) { 163 | var z = resolveEventType(event).pageY - _$trigger._offset.top, 164 | hsv = _color.colors.hsv; 165 | 166 | _color.setColor({h: 360 - (z / _$xy_slider._height * 360)}, 'hsv'); 167 | preRender(); 168 | } 169 | 170 | function alpha(event) { 171 | var x = resolveEventType(event).pageX - _$trigger._offset.left, 172 | alpha = x / _$alpha._width; 173 | 174 | _color.setColor({}, 'rgb', alpha > 1 ? 1 : alpha < 0 ? 0 : alpha); 175 | preRender(); 176 | } 177 | 178 | function preRender(toggled) { 179 | var colors = _color.colors, 180 | hueRGB = colors.hueRGB, 181 | RGB = colors.RND.rgb, 182 | HSL = colors.RND.hsl, 183 | dark = '#222', 184 | light = '#ddd', 185 | colorMode = _$trigger.data('colorMode'), 186 | isAlpha = colors.alpha !== 1, 187 | alpha = Math.round(colors.alpha * 100) / 100, 188 | RGBInnerText = RGB.r + ', ' + RGB.g + ', ' + RGB.b, 189 | text = (colorMode === 'HEX' && !isAlpha ? '#' + colors.HEX : 190 | colorMode === 'rgb' || (colorMode === 'HEX' && isAlpha) ? 191 | (!isAlpha ? 'rgb(' + RGBInnerText + ')' : 192 | 'rgba(' + RGBInnerText + ', ' + alpha + ')') : 193 | ('hsl' + (isAlpha ? 'a(' : '(') + HSL.h + ', ' + HSL.s + '%, ' + 194 | HSL.l + '%' + (isAlpha ? ', ' + alpha : '') + ')')), 195 | HUEContrast = colors.HUELuminance > 0.22 ? dark : light, 196 | alphaContrast = colors.rgbaMixBlack.luminance > 0.22 ? dark : light, 197 | h = (1 - colors.hsv.h) * _$xy_slider._height, 198 | s = colors.hsv.s * _$xy_slider._width, 199 | v = (1 - colors.hsv.v) * _$xy_slider._height, 200 | a = alpha * _$alpha._width, 201 | translate3d = _GPU ? 'translate3d' : ''; 202 | 203 | _$xy_slider._css = { 204 | backgroundColor: 'rgb(' + 205 | hueRGB.r + ',' + hueRGB.g + ',' + hueRGB.b + ')'}; 206 | _$xy_cursor._css = { 207 | transform: translate3d + '(' + s + 'px, ' + v + 'px, 0)', 208 | left: !_GPU ? s : '', 209 | top: !_GPU ? v : '', 210 | borderColor : colors.RGBLuminance > 0.22 ? dark : light 211 | }; 212 | _$z_cursor._css = { 213 | transform: translate3d + '(0, ' + h + 'px, 0)', 214 | top: !_GPU ? h : '', 215 | borderColor : 'transparent ' + HUEContrast 216 | }; 217 | _$alpha._css = {backgroundColor: 'rgb(' + RGBInnerText + ')'}; 218 | _$alpha_cursor._css = { 219 | transform: translate3d + '(' + a + 'px, 0, 0)', 220 | left: !_GPU ? a : '', 221 | borderColor : alphaContrast + ' transparent' 222 | }; 223 | _$trigger._css = { 224 | backgroundColor : text, 225 | color: colors.rgbaMixBGMixCustom.luminance > 0.22 ? dark : light 226 | }; 227 | _$trigger.text = _$trigger.val() !== text ? text : ''; 228 | 229 | toggled !== undefined ? render(toggled) : _animate(render); 230 | } 231 | 232 | // As _animate() is actually requestAnimationFrame(), render() gets called 233 | // decoupled from any pointer action (whenever the browser decides to do 234 | // so) as an event. preRender() is coupled to toggle() and all pointermove 235 | // actions; that's where all the calculations happen. render() can now be 236 | // called without extra calculations which results in faster rendering. 237 | function render(toggled) { 238 | _$xy_slider.css(_$xy_slider._css); 239 | _$xy_cursor.css(_$xy_cursor._css); 240 | _$z_cursor.css(_$z_cursor._css); 241 | _$alpha.css(_$alpha._css); 242 | _$alpha_cursor.css(_$alpha_cursor._css); 243 | 244 | _options.doRender && _$trigger.css(_$trigger._css); 245 | _$trigger.text && _$trigger.val(_$trigger.text); 246 | 247 | _options.renderCallback.call( 248 | _colorPicker, 249 | _$trigger, 250 | typeof toggled === 'boolean' ? toggled : undefined 251 | ); 252 | } 253 | 254 | $.fn.colorPicker = function(options) { 255 | var noop = function(){}; 256 | 257 | options = $.extend({ 258 | animationSpeed: 150, 259 | GPU: true, 260 | doRender: true, 261 | customBG: '#FFF', 262 | opacity: true, 263 | renderCallback: noop, 264 | buidCallback: noop, 265 | body: document.body, 266 | scrollResize: true, 267 | gap: 4 268 | // css: '', 269 | // cssAddon: '', 270 | // margin: '', 271 | // preventFocus: false 272 | }, options); 273 | 274 | !_colorPicker && options.scrollResize && $(window). 275 | on('resize scroll', function() { 276 | if (_colorPicker.$trigger) { 277 | _colorPicker.toggle.call(_colorPicker.$trigger[0], true); 278 | } 279 | }); 280 | _instance = _instance ? _instance.add(this) : this; 281 | _instance.colorPicker = _colorPicker || 282 | (_colorPicker = new ColorPicker(options)); 283 | _selector += (_selector ? ', ' : '') + this.selector; 284 | 285 | $(options.body).off('.a'). 286 | on('touchstart.a mousedown.a pointerdown.a', function(e) { 287 | var $target = $(e.target); 288 | 289 | if ($.inArray($target.closest(_selector)[0], 290 | _instance) === -1 && 291 | !$target.closest(_$UI).length) { 292 | toggle(); 293 | } 294 | }). 295 | on('focus.a click.a', _selector, toggle). 296 | on('change.a', _selector, function() { 297 | _color.setColor(this.value); 298 | _instance.colorPicker.render(); 299 | }); 300 | 301 | return this.each(function() { 302 | var value = extractValue(this), 303 | mode = value.split('('), 304 | $elm = findElement($(this)); 305 | 306 | $elm.data('colorMode', mode[1] ? mode[0].substr(0, 3) : 'HEX'). 307 | attr('readonly', _options.preventFocus); 308 | options.doRender && $elm. 309 | css({'background-color': value, 310 | 'color': function() { 311 | return _color.setColor(value). 312 | rgbaMixBGMixCustom.luminance > 0.22 ? '#222' : '#ddd' 313 | } 314 | }); 315 | }); 316 | }; 317 | })(window.jQuery, Colors); -------------------------------------------------------------------------------- /3rd/jquery.text-overflow.js: -------------------------------------------------------------------------------- 1 | (function($) { 2 | $.fn.ellipsis = function(enableUpdating){ 3 | var s = document.documentElement.style; 4 | if (!('textOverflow' in s || 'OTextOverflow' in s)) { 5 | return this.each(function(){ 6 | var el = $(this); 7 | if(el.css("overflow") == "hidden"){ 8 | var originalText = el.html(); 9 | var w = el.width(); 10 | 11 | var t = $(this.cloneNode(true)).hide().css({ 12 | 'position': 'absolute', 13 | 'width': 'auto', 14 | 'overflow': 'visible', 15 | 'max-width': 'inherit' 16 | }); 17 | el.after(t); 18 | 19 | var text = originalText; 20 | while(text.length > 0 && t.width() > el.width()){ 21 | text = text.substr(0, text.length - 1); 22 | t.html(text + "..."); 23 | } 24 | el.html(t.html()); 25 | 26 | t.remove(); 27 | 28 | if(enableUpdating == true){ 29 | var oldW = el.width(); 30 | setInterval(function(){ 31 | if(el.width() != oldW){ 32 | oldW = el.width(); 33 | el.html(originalText); 34 | el.ellipsis(); 35 | } 36 | }, 200); 37 | } 38 | } 39 | }); 40 | } else return this; 41 | }; 42 | })(jQuery); -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | ====================== 2 | JavaScript Experiments 3 | ====================== 4 | 5 | Some JavaScript experiments. You can see them online using the links below. 6 | `Google Chrome `_ is the best browser 7 | for these demos, but `Opera `_ or 8 | Firefox should be fine too. 9 | 10 | `Gray-Scott `_ 11 | ========================================================== 12 | 13 | `Gray-Scott `_ 14 | is a solver for the Gray-Scott reaction-diffusion model. Roughly, this 15 | can be seen as a simulation of the behavior of diffusive living beings reproducing 16 | under conditions of limited food. Very different patterns emerge for 17 | slight changes in feeding and death rates. 18 | 19 | This experiment uses `Three.js `_ 20 | and performs calculations on the GPU. 21 | It requires a WebGL enabled browser. 22 | 23 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/grayscott.png 24 | :align: center 25 | :target: http://pmneila.github.com/jsexp/grayscott 26 | 27 | Screenshots 28 | ----------- 29 | 30 | Some screenshots of the application. 31 | 32 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/default_s.png 33 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/default.png 34 | 35 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/holes_s.png 36 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/holes.png 37 | 38 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/mazes_s.png 39 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/mazes.png 40 | 41 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/solitons_s.png 42 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/solitons.png 43 | 44 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/solitons2_s.png 45 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/solitons2.png 46 | 47 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/spots_s.png 48 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/spots.png 49 | 50 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/waves1_s.png 51 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/waves1.png 52 | 53 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/waves2_s.png 54 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/waves2.png 55 | 56 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/worm_s.png 57 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/worm.png 58 | 59 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/worms_s.png 60 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/worms.png 61 | 62 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/inverseworms_s.png 63 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/inverseworms.png 64 | 65 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/chaos_s.png 66 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/chaos.png 67 | 68 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/spotsx_s.png 69 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/spotsx.png 70 | 71 | .. image:: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/wormsx_s.png 72 | :target: https://github.com/pmneila/jsexp/raw/master/grayscott/snapshots/wormsx.png 73 | 74 | 75 | `Particles `_ 76 | ========================================================= 77 | 78 | `Particles `_ 79 | is a simple mass-spring physics simulation. 80 | 81 | .. image:: https://github.com/pmneila/jsexp/raw/master/massspring/particles.png 82 | :align: center 83 | :target: http://pmneila.github.com/jsexp/massspring 84 | -------------------------------------------------------------------------------- /convtester/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 22 | 23 | 24 |
25 |
26 | 27 | 211 |
212 |
213 | 214 | -------------------------------------------------------------------------------- /convtester/justified-nav.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding-top: 20px; 3 | } 4 | 5 | .footer { 6 | padding-top: 40px; 7 | padding-bottom: 40px; 8 | margin-top: 40px; 9 | border-top: 1px solid #eee; 10 | } 11 | 12 | /* Main marketing message and sign up button */ 13 | .jumbotron { 14 | text-align: center; 15 | background-color: transparent; 16 | } 17 | .jumbotron .btn { 18 | padding: 14px 24px; 19 | font-size: 21px; 20 | } 21 | 22 | /* Customize the nav-justified links to be fill the entire space of the .navbar */ 23 | 24 | .nav-justified { 25 | background-color: #eee; 26 | border: 1px solid #ccc; 27 | border-radius: 5px; 28 | } 29 | .nav-justified > li > a { 30 | padding-top: 15px; 31 | padding-bottom: 15px; 32 | margin-bottom: 0; 33 | font-weight: bold; 34 | color: #777; 35 | text-align: center; 36 | background-color: #e5e5e5; /* Old browsers */ 37 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e5e5e5)); 38 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e5e5e5 100%); 39 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e5e5e5 100%); 40 | background-image: -webkit-gradient(linear, left top, left bottom, from(top), color-stop(0%, #f5f5f5), to(#e5e5e5)); 41 | background-image: linear-gradient(top, #f5f5f5 0%, #e5e5e5 100%); 42 | filter: progid:DXImageTransform.Microsoft.gradient( startColorstr='#f5f5f5', endColorstr='#e5e5e5',GradientType=0 ); /* IE6-9 */ 43 | background-repeat: repeat-x; /* Repeat the gradient */ 44 | border-bottom: 1px solid #d5d5d5; 45 | } 46 | .nav-justified > .active > a, 47 | .nav-justified > .active > a:hover, 48 | .nav-justified > .active > a:focus { 49 | background-color: #ddd; 50 | background-image: none; 51 | -webkit-box-shadow: inset 0 3px 7px rgba(0,0,0,.15); 52 | box-shadow: inset 0 3px 7px rgba(0,0,0,.15); 53 | } 54 | .nav-justified > li:first-child > a { 55 | border-radius: 5px 5px 0 0; 56 | } 57 | .nav-justified > li:last-child > a { 58 | border-bottom: 0; 59 | border-radius: 0 0 5px 5px; 60 | } 61 | 62 | @media (min-width: 768px) { 63 | .nav-justified { 64 | max-height: 52px; 65 | } 66 | .nav-justified > li > a { 67 | border-right: 1px solid #d5d5d5; 68 | border-left: 1px solid #fff; 69 | } 70 | .nav-justified > li:first-child > a { 71 | border-left: 0; 72 | border-radius: 5px 0 0 5px; 73 | } 74 | .nav-justified > li:last-child > a { 75 | border-right: 0; 76 | border-radius: 0 5px 5px 0; 77 | } 78 | } 79 | 80 | /* Responsive: Portrait tablets and up */ 81 | @media screen and (min-width: 768px) { 82 | /* Remove the padding we set earlier */ 83 | .masthead, 84 | .marketing, 85 | .footer { 86 | padding-right: 0; 87 | padding-left: 0; 88 | } 89 | } -------------------------------------------------------------------------------- /css/experiments.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font-family:sans-serif; 4 | background:#333333; 5 | color:#777777; 6 | width: 1200px; 7 | margin: 0 auto; 8 | } 9 | 10 | header, footer, aside, nav { 11 | display: block; 12 | } 13 | 14 | a:link {color:#777777;} 15 | a:visited {color:#777777;} 16 | a:hover {color:#999999;} 17 | a:active {color:#ffffff;} 18 | 19 | #copyright { 20 | font-size:8pt; 21 | text-align:center; 22 | margin-top:10px; 23 | } 24 | 25 | .remark { 26 | color: #ffffff; 27 | } 28 | 29 | .unsafe { 30 | color : #c86464; 31 | } 32 | 33 | #simulation { 34 | display:table; 35 | margin: 0 auto; 36 | border:1px solid; 37 | box-shadow: 10px 10px 7px #222; 38 | } 39 | 40 | #simulation .viewer { 41 | display:table-cell; 42 | } 43 | 44 | #simulation .panel { 45 | display:table-cell; 46 | vertical-align:top; 47 | width: 200px; 48 | padding: 0px 5px 0px 5px; 49 | font-size: 9pt; 50 | background:#151515; 51 | } 52 | #simulation .panel header { 53 | color: #ffffff; 54 | } 55 | 56 | #simulation .panel .slider { 57 | margin: 7px 10px 10px 10px; 58 | } 59 | #simulation .panel section { 60 | margin-bottom: 15px; 61 | border-bottom: 1px dotted; 62 | } 63 | #simulation .panel section:last-child { 64 | margin-bottom: 0px; 65 | border-bottom: 0px; 66 | } 67 | 68 | 69 | #myCanvas { 70 | display:block; 71 | vertical-align:bottom; 72 | background-color:#000000; 73 | border-right:1px solid; 74 | } 75 | -------------------------------------------------------------------------------- /css/paintflow.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font-family:sans-serif; 4 | background:#333333; 5 | color:#777777; 6 | margin: 0 auto; 7 | } 8 | 9 | header, footer, aside, nav { 10 | display: block; 11 | } 12 | 13 | a:link {color:#777777;} 14 | a:visited {color:#777777;} 15 | a:hover {color:#999999;} 16 | a:active {color:#ffffff;} 17 | 18 | #copyright { 19 | font-size:8pt; 20 | text-align:center; 21 | margin-top:10px; 22 | } 23 | 24 | .remark { 25 | color: #ffffff; 26 | } 27 | 28 | .unsafe { 29 | color : #c86464; 30 | } 31 | 32 | #myCanvas { 33 | display:block; 34 | vertical-align:bottom; 35 | background-color:#000000; 36 | } -------------------------------------------------------------------------------- /fastmccabe/render.js: -------------------------------------------------------------------------------- 1 | /* 2 | x y z w x y z w x y z w x y z w 3 | isrc -> x0 -> y0 -> x1 -> y1 -> x2 -> y2 -> x3 -> y3 -> x4 -> y4 -> x5 -> y5 -> x6 -> y6 -> x7 -> y7 4 | 5 | */ 6 | 7 | var Renderer = function(config){ 8 | 9 | this.canvas = undefined; 10 | this.canvasQ = undefined; 11 | this.canvasWidth = undefined; 12 | this.canvasHeight = undefined; 13 | 14 | this.mRenderer = undefined; 15 | this.mScene = undefined; 16 | this.mCamera = undefined; 17 | 18 | this.uiStep = 0 >>> 0; // coerce to uint32 19 | 20 | this.time = new Date().getTime(); 21 | 22 | this.mTexture0 = undefined; 23 | this.mTexture1 = undefined; 24 | this.mTexture2 = undefined; 25 | this.mTexture3 = undefined; 26 | this.mTexture4 = undefined; 27 | this.mTexture5 = undefined; 28 | this.mTexture6 = undefined; 29 | this.mTexture7 = undefined; 30 | this.mTexture8 = undefined; 31 | this.mTexture9 = undefined; 32 | this.debugTexture = undefined; 33 | this.mScreenQuad = undefined; 34 | 35 | this.mccabeMaterial = undefined; 36 | this.debugMaterial = undefined; 37 | this.noiseMaterial = undefined; 38 | this.pass0Material = undefined; 39 | this.pass1Material = undefined; 40 | this.pass2Material = undefined; 41 | this.pass3Material = undefined; 42 | this.screenMaterial = undefined; 43 | 44 | this.textureWidth = 1024; 45 | this.textureHeight = 1024; 46 | 47 | // Configuration. 48 | this.hard = config.hard; 49 | this.rate = config.rate; 50 | this.sharp = config.sharp; 51 | this.exponent = config.exponent; 52 | this.scale = config.scale; 53 | this.stddev = config.stddev; 54 | this.hystj = config.hystj; 55 | this.hystk = config.hystk; 56 | this.blurl = config.blurl; 57 | 58 | this.debug = false; 59 | 60 | this.mUniforms = { 61 | screenWidth: {type: "f", value: undefined}, 62 | screenHeight: {type: "f", value: undefined}, 63 | sSource: {type: "t", value: undefined}, 64 | bSource0: {type: "t", value: undefined}, 65 | bSource1: {type: "t", value: undefined}, 66 | bSource2: {type: "t", value: undefined}, 67 | bSource3: {type: "t", value: undefined}, 68 | iSource: {type: "t", value: undefined}, 69 | hard: {type: "f", value: this.hard}, 70 | rate: {type: "f", value: this.rate}, 71 | sharp: {type: "f", value: this.sharp}, 72 | exponent: {type: "f", value: this.exponent}, 73 | scale: {type: "f", value: this.scale}, 74 | stddev: {type: "f", value: this.stddev}, 75 | hystj: {type: "f", value: this.hystj}, 76 | hystk: {type: "f", value: this.hystk}, 77 | blurl: {type: "f", value: this.blurl} 78 | }; 79 | 80 | this.updateUniforms = function() 81 | { 82 | this.mUniforms.hard.value = this.hard; 83 | this.mUniforms.rate.value = this.rate; 84 | this.mUniforms.sharp.value = this.sharp; 85 | this.mUniforms.exponent.value = this.exponent; 86 | this.mUniforms.scale.value = this.scale; 87 | this.mUniforms.stddev.value = this.stddev; 88 | this.mUniforms.hystj.value = this.hystj; 89 | this.mUniforms.hystk.value = this.hystk; 90 | this.mUniforms.blurl.value = this.blurl; 91 | }; 92 | 93 | this.init = function() 94 | { 95 | this.initCanvas(); 96 | this.initGl(); 97 | this.render(); 98 | }; 99 | 100 | this.initCanvas = function() 101 | { 102 | this.canvasQ = $('#myCanvas'); 103 | this.canvas = this.canvasQ.get(0); 104 | 105 | window.addEventListener('resize', this.onResize.bind(this), false ); 106 | }; 107 | 108 | this.getMaterial = function(vertexShaderId, fragmentShaderId) 109 | { 110 | return new THREE.ShaderMaterial({ 111 | uniforms: this.mUniforms, 112 | vertexShader: document.getElementById(vertexShaderId).textContent, 113 | fragmentShader: document.getElementById(fragmentShaderId).textContent 114 | }); 115 | }; 116 | 117 | this.initGl = function() 118 | { 119 | this.mRenderer = new THREE.WebGLRenderer({canvas: this.canvas, preserveDrawingBuffer: true}); 120 | 121 | this.mScene = new THREE.Scene(); 122 | this.mCamera = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5, -1, 1); 123 | this.mCamera.position.z = 0; 124 | this.mScene.add(this.mCamera); 125 | 126 | this.screenMaterial = this.getMaterial('standardVertexShader', 'screenFragmentShader'); 127 | this.mccabeMaterial = this.getMaterial('standardVertexShader', 'mccabeFragmentShader'); 128 | this.debugMaterial = this.getMaterial('standardVertexShader', 'debugFragmentShader'); 129 | this.noiseMaterial = this.getMaterial('standardVertexShader', 'noiseFragmentShader'); 130 | this.pass0Material = this.getMaterial('gaussianPyramidVertexShader0', 'gaussianPyramidFragmentShader'); 131 | this.pass1Material = this.getMaterial('gaussianPyramidVertexShader1', 'gaussianPyramidFragmentShader'); 132 | this.pass2Material = this.getMaterial('gaussianPyramidVertexShader2', 'gaussianPyramidFragmentShader'); 133 | this.pass3Material = this.getMaterial('gaussianPyramidVertexShader3', 'gaussianPyramidFragmentShader'); 134 | 135 | var plane = new THREE.PlaneGeometry(1.0, 1.0); 136 | this.mScreenQuad = new THREE.Mesh(plane, this.screenMaterial); 137 | this.mScene.add(this.mScreenQuad); 138 | 139 | // Set the new shape of canvas. 140 | this.canvasQ.width(this.getCanvasWidth()); 141 | this.canvasQ.height(this.getCanvasHeight()); 142 | 143 | // Get the real size of canvas. 144 | this.canvasWidth = this.canvasQ.width(); 145 | this.canvasHeight = this.canvasQ.height(); 146 | 147 | this.mRenderer.setSize(this.canvasWidth, this.canvasHeight); 148 | 149 | this.mTexture0 = this.getWrappedRenderTarget(); 150 | this.mTexture1 = this.getWrappedRenderTarget(); 151 | this.mTexture2 = this.getWrappedRenderTarget(); 152 | this.mTexture3 = this.getWrappedRenderTarget(); 153 | this.mTexture4 = this.getWrappedRenderTarget(); 154 | this.mTexture5 = this.getWrappedRenderTarget(); 155 | this.mTexture6 = this.getWrappedRenderTarget(); 156 | this.mTexture7 = this.getWrappedRenderTarget(); 157 | this.mTexture8 = this.getWrappedRenderTarget(); 158 | this.mTexture9 = this.getWrappedRenderTarget(); 159 | this.debugTexture = this.getWrappedRenderTarget(); 160 | 161 | this.mUniforms.screenWidth.value = this.textureWidth; 162 | this.mUniforms.screenHeight.value = this.textureHeight; 163 | 164 | }; 165 | 166 | this.getWrappedRenderTarget = function() 167 | { 168 | return new THREE.WebGLRenderTarget(this.textureWidth, this.textureHeight, { 169 | minFilter: THREE.NearestFilter, 170 | magFilter: THREE.NearestFilter, 171 | format: THREE.RGBAFormat, 172 | type: THREE.FloatType, 173 | wrapS: THREE.RepeatWrapping, 174 | wrapT: THREE.RepeatWrapping 175 | }); 176 | }; 177 | 178 | this.renderToTarget = function(material, iSource, sSource, target) 179 | { 180 | this.mScreenQuad.material = material; 181 | this.mUniforms.iSource.value = iSource; 182 | this.mUniforms.sSource.value = sSource; 183 | this.mRenderer.render(this.mScene, this.mCamera, target, true); 184 | }; 185 | 186 | this.renderToFinalTarget = function(material, iSource, bSource0, bSource1, bSource2, bSource3, target) 187 | { 188 | this.mScreenQuad.material = material; 189 | this.mUniforms.iSource.value = iSource; 190 | this.mUniforms.bSource0.value = bSource0; 191 | this.mUniforms.bSource1.value = bSource1; 192 | this.mUniforms.bSource2.value = bSource2; 193 | this.mUniforms.bSource3.value = bSource3; 194 | this.mRenderer.render(this.mScene, this.mCamera, target, true); 195 | }; 196 | 197 | this.render = function() 198 | { 199 | this.updateUniforms(); 200 | var imageTexture; 201 | 202 | if (this.uiStep == 0) { 203 | this.renderToTarget(this.noiseMaterial, this.mTexture0, this.mTexture1, this.mTexture0); 204 | this.renderToTarget(this.noiseMaterial, this.mTexture0, this.mTexture1, this.mTexture9); 205 | } 206 | if (this.uiStep % 2 == 0) { 207 | this.renderToTarget(this.pass0Material, this.mTexture0, this.mTexture1, this.mTexture2); 208 | this.renderToTarget(this.pass1Material, this.mTexture2, this.mTexture3, this.mTexture4); 209 | this.renderToTarget(this.pass2Material, this.mTexture4, this.mTexture5, this.mTexture6); 210 | this.renderToTarget(this.pass3Material, this.mTexture6, this.mTexture7, this.mTexture8); 211 | this.renderToFinalTarget(this.mccabeMaterial, this.mTexture0, this.mTexture2, this.mTexture4, this.mTexture6, this.mTexture8, this.mTexture9); 212 | if (this.debug) { 213 | this.renderToFinalTarget(this.debugMaterial, this.mTexture0, this.mTexture2, this.mTexture4, this.mTexture6, this.mTexture8, this.debugTexture); 214 | imageTexture = this.debugTexture; 215 | } else { 216 | imageTexture = this.mTexture9; 217 | } 218 | } else { 219 | this.renderToTarget(this.pass0Material, this.mTexture9, this.mTexture2, this.mTexture1); 220 | this.renderToTarget(this.pass1Material, this.mTexture1, this.mTexture4, this.mTexture3); 221 | this.renderToTarget(this.pass2Material, this.mTexture3, this.mTexture6, this.mTexture5); 222 | this.renderToTarget(this.pass3Material, this.mTexture5, this.mTexture8, this.mTexture7); 223 | this.renderToFinalTarget(this.mccabeMaterial, this.mTexture9, this.mTexture1, this.mTexture3, this.mTexture5, this.mTexture7, this.mTexture0); 224 | if (this.debug) { 225 | this.renderToFinalTarget(this.debugMaterial, this.mTexture9, this.mTexture1, this.mTexture3, this.mTexture5, this.mTexture7, this.debugTexture); 226 | imageTexture = this.debugTexture; 227 | } else { 228 | imageTexture = this.mTexture0; 229 | } 230 | } 231 | 232 | this.mUniforms.iSource.value = imageTexture; 233 | this.mScreenQuad.material = this.screenMaterial; 234 | this.mRenderer.render(this.mScene, this.mCamera); 235 | 236 | this.uiStep++; 237 | requestAnimationFrame(this.render.bind(this)); 238 | }; 239 | 240 | this.resetCounter = function() { 241 | this.uiStep = 0 >>> 0; 242 | }; 243 | 244 | this.snapshot = function() 245 | { 246 | var dataURL = this.canvas.toDataURL("image/jpeg"); 247 | window.open(dataURL, "name-"+Math.random()); 248 | }; 249 | 250 | this.toggleDebug = function() 251 | { 252 | this.debug = !this.debug; 253 | }; 254 | 255 | this.onResize = function() 256 | { 257 | 258 | // Set the new shape of canvas. 259 | this.canvasQ.width(this.getCanvasWidth()); 260 | this.canvasQ.height(this.getCanvasHeight()); 261 | 262 | // Get the real size of canvas. 263 | this.canvasWidth = this.canvasQ.width(); 264 | this.canvasHeight = this.canvasQ.height(); 265 | 266 | this.mRenderer.setSize(this.canvasWidth, this.canvasHeight); 267 | 268 | }; 269 | 270 | this.getCanvasWidth = function() 271 | { 272 | return window.innerWidth; 273 | }; 274 | 275 | this.getCanvasHeight = function() 276 | { 277 | return window.innerHeight; 278 | }; 279 | 280 | }; 281 | 282 | window.onload = function() { 283 | var renderer = new Renderer({ 284 | hard: 10.0, 285 | rate: 25.0, 286 | sharp: 10.0, 287 | exponent: 2.0, 288 | stddev: 4.0, 289 | scale: 0.001, 290 | hystj: 5.0, 291 | hystk: 20.0, 292 | blurl: 4.0 293 | }); 294 | var gui = new dat.GUI(); 295 | 296 | gui.add(renderer, 'hard').min(0.0).max(50.0).step(0.01).name("Hardness"); 297 | gui.add(renderer, 'sharp').min(0.0).max(20.0).step(0.01).name("Sharpness"); 298 | gui.add(renderer, 'exponent').min(-5.0).max(5.0).step(0.01).name("Scale Exponent"); 299 | gui.add(renderer, 'scale').min(0.001).max(1.0).step(0.001).name("Prescale"); 300 | gui.add(renderer, 'rate').min(0.0).max(50.0).step(0.01).name("Rate"); 301 | gui.add(renderer, 'stddev').min(0.0).max(10.0).step(0.01).name("Std Deviation"); 302 | gui.add(renderer, 'hystj').min(0.01).max(10.0).step(0.01).name("Hysteresis Scale"); 303 | gui.add(renderer, 'hystk').min(0.01).max(40.0).step(0.01).name("Hysteresis Delta"); 304 | gui.add(renderer, 'blurl').min(0.0).max(7.0).step(0.01).name("Debug View Ctrl"); 305 | gui.add(renderer, 'toggleDebug').name("Debug View"); 306 | gui.add(renderer, 'snapshot').name("Screenshot"); 307 | 308 | renderer.init(); 309 | }; -------------------------------------------------------------------------------- /fastmccabe/style.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font-family:sans-serif; 4 | background:#333333; 5 | color:#777777; 6 | margin: 0 auto; 7 | } 8 | 9 | header, footer, aside, nav { 10 | display: block; 11 | } 12 | 13 | #myCanvas { 14 | display:block; 15 | vertical-align:bottom; 16 | background-color:#000000; 17 | } -------------------------------------------------------------------------------- /frustratedflockingfluid/grayscott.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/frustratedflockingfluid/grayscott.png -------------------------------------------------------------------------------- /gradientui/gradientui.css: -------------------------------------------------------------------------------- 1 | 2 | .gradient-view 3 | { 4 | border: 1px solid; 5 | } 6 | 7 | .gradient-dragger 8 | { 9 | border: 1px solid; 10 | width: 7px; 11 | height: 8px; 12 | position: absolute; 13 | bottom: 10px; 14 | cursor: auto; 15 | } 16 | -------------------------------------------------------------------------------- /gradientui/gradientui.js: -------------------------------------------------------------------------------- 1 | 2 | (function($){ 3 | 4 | var hexToRgb = function(hex) { 5 | var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex); 6 | return result ? { 7 | r: parseInt(result[1], 16)/255.0, 8 | g: parseInt(result[2], 16)/255.0, 9 | b: parseInt(result[3], 16)/255.0 10 | } : null; 11 | } 12 | 13 | var clamp = function(value, min, max) 14 | { 15 | return Math.max(min, Math.min(max, value)); 16 | } 17 | 18 | var Dragger = function(parent, position, color) 19 | { 20 | this.parent = parent; 21 | this.parent.$this.append('
'); 22 | this.$this = parent.$this.children('.gradient-dragger:last'); 23 | this.width = parent.$this.children('.gradient-view').width() - 7; 24 | this.position = position; 25 | this.color = color; 26 | this.dragging = false; 27 | this.moved = false; 28 | this.oldleft = undefined 29 | this.mousedownx = undefined; 30 | this.$this.css("left", this.position*this.width); 31 | this.$this.css("background-color", this.color); 32 | 33 | this.$this.bind("click.dragger", {this : this}, function(event){event.data.this.click(event)}); 34 | this.$this.bind("mousedown.dragger", {this : this}, function(event){event.data.this.mousedown(event)}); 35 | $(window).bind("mouseup.dragger", {this : this}, function(event){event.data.this.mouseup(event)}); 36 | $(window).bind("mousemove.dragger", {this : this}, function(event){event.data.this.mousemove(event)}); 37 | } 38 | 39 | Dragger.prototype.click = function(event) 40 | { 41 | if(this.moved) 42 | return; 43 | 44 | var aux = this; 45 | colorPicker.exportColor = function() 46 | { 47 | aux.color = '#' + colorPicker.CP.hex; 48 | aux.$this.css("background-color", aux.color); 49 | aux.parent.redraw(); 50 | }; 51 | 52 | colorPicker.expColor = false; 53 | colorPicker.expHEX = false; 54 | colorPicker.mode = 'H'; 55 | colorPicker.objs = this.color; 56 | colorPicker(event); 57 | } 58 | 59 | Dragger.prototype.mousedown = function(event) 60 | { 61 | this.oldleft = parseInt(this.$this.css("left"), 10); 62 | this.mousedownx = event.pageX; 63 | this.dragging = true; 64 | this.moved = false; 65 | } 66 | 67 | Dragger.prototype.mouseup = function(event) 68 | { 69 | this.dragging = false; 70 | } 71 | 72 | Dragger.prototype.mousemove = function(event) 73 | { 74 | if(!this.dragging) 75 | return; 76 | 77 | var diff = event.pageX - this.mousedownx; 78 | var newleft = clamp(this.oldleft + diff, 0, this.width); 79 | 80 | this.position = newleft / this.width; 81 | this.$this.css("left", newleft); 82 | this.parent.redraw(); 83 | 84 | this.moved = true; 85 | } 86 | 87 | Dragger.prototype.setPosition = function(pos) 88 | { 89 | pos = clamp(pos, 0.0, 1.0); 90 | var newleft = pos*this.width; 91 | 92 | this.$this.css("left", newleft); 93 | this.position = pos; 94 | } 95 | 96 | Dragger.prototype.setColor = function(color) 97 | { 98 | this.color = color; 99 | this.$this.css("background-color", color); 100 | this.parent.redraw(); 101 | } 102 | 103 | var Gradient = function(parent, values) 104 | { 105 | this.$this = parent; 106 | 107 | // Disable selection. 108 | this.$this.get(0).onselectstart = function(){return false;}; 109 | 110 | this.$this.css("position", "relative"); 111 | this.width = this.$this.width(); 112 | this.height = this.$this.height(); 113 | this.$this.append(''); 114 | 115 | this.gradientview = this.$this.children('.gradient-view:first'); 116 | this.gradientview.width(this.width); 117 | this.gradientview.height(this.height - 21); 118 | this.gradientview.css('position', 'absolute'); 119 | this.gradientview.css('left', 0); 120 | 121 | this.canvas = this.gradientview.get(0); 122 | this.canvas.width = this.gradientview.width(); 123 | this.canvas.height = this.gradientview.height(); 124 | this.ctx = this.canvas.getContext('2d'); 125 | 126 | this.draggers = []; 127 | for(var i=0; i < values.length; i++) 128 | this.draggers.push(new Dragger(this, values[i][0], values[i][1])); 129 | 130 | this.redraw(); 131 | } 132 | 133 | Gradient.prototype.updateValues = function() 134 | { 135 | var aux = this.draggers.map(function(a){return [a.position, a.color];}); 136 | aux.sort(function(a,b){return a[0]-b[0];}); 137 | 138 | this.values = aux; 139 | 140 | if(this.callback !== undefined) 141 | this.callback.fn(this.callback.data); 142 | } 143 | 144 | Gradient.prototype.setValues = function(values) 145 | { 146 | this.values = values; 147 | for (var i = values.length - 1; i >= 0; i--) { 148 | var v = values[i]; 149 | this.draggers[i].setPosition(v[0]); 150 | this.draggers[i].setColor(v[1]); 151 | }; 152 | } 153 | 154 | Gradient.prototype.redraw = function() 155 | { 156 | this.updateValues(); 157 | var values = this.values; 158 | 159 | var lingrad = this.ctx.createLinearGradient(0, 0, this.canvas.width, 0); 160 | for(var i=0; i 2 | 3 | 4 | 5 | Gradient widget 6 | 7 | 8 | 9 | 10 | 14 | 19 | 20 | 21 |
22 |
23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /grayscott/grayscott.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/grayscott/grayscott.png -------------------------------------------------------------------------------- /gsimage/grayscott.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Gray-Scott 3 | * 4 | * A solver of the Gray-Scott model of reaction diffusion. 5 | * 6 | * ©2012 pmneila. 7 | * p.mneila at upm.es 8 | */ 9 | 10 | (function(){ 11 | 12 | // Canvas. 13 | var canvas; 14 | var canvasQ; 15 | var canvasWidth; 16 | var canvasHeight; 17 | 18 | var mMouseX, mMouseY; 19 | var mMouseDown = false; 20 | 21 | var mRenderer; 22 | var mScene; 23 | var mCamera; 24 | var mUniforms; 25 | var mColors; 26 | var mColorsNeedUpdate = true; 27 | var mLastTime = 0; 28 | 29 | var mMap; 30 | var mTexture1, mTexture2; 31 | var mGSMaterial, mScreenMaterial; 32 | var mScreenQuad; 33 | 34 | var mToggled = false; 35 | 36 | var mMinusOnes = new THREE.Vector2(-1, -1); 37 | 38 | // Some presets. 39 | var presets = [ 40 | { // Default 41 | //feed: 0.018, 42 | //kill: 0.051 43 | feed: 0.037, 44 | kill: 0.061 45 | }, 46 | { // Solitons 47 | feed: 0.03, 48 | kill: 0.062 49 | }, 50 | { // Pulsating solitons 51 | feed: 0.025, 52 | kill: 0.06 53 | }, 54 | { // Worms. 55 | feed: 0.078, 56 | kill: 0.061 57 | }, 58 | { // Mazes 59 | feed: 0.029, 60 | kill: 0.057 61 | }, 62 | { // Holes 63 | feed: 0.039, 64 | kill: 0.058 65 | }, 66 | { // Chaos 67 | feed: 0.026, 68 | kill: 0.051 69 | }, 70 | { // Chaos and holes (by clem) 71 | feed: 0.034, 72 | kill: 0.056 73 | }, 74 | { // Moving spots. 75 | feed: 0.014, 76 | kill: 0.054 77 | }, 78 | { // Spots and loops. 79 | feed: 0.018, 80 | kill: 0.051 81 | }, 82 | { // Waves 83 | feed: 0.014, 84 | kill: 0.045 85 | }, 86 | { // The U-Skate World 87 | feed: 0.062, 88 | kill: 0.06093 89 | } 90 | ]; 91 | 92 | // Configuration. 93 | var feed = presets[0].feed; 94 | var kill = presets[0].kill; 95 | 96 | lena.onload = function(){init()}; 97 | 98 | init = function() 99 | { 100 | init_controls(); 101 | 102 | canvasQ = $('#myCanvas'); 103 | canvas = canvasQ.get(0); 104 | 105 | canvas.onmousedown = onMouseDown; 106 | canvas.onmouseup = onMouseUp; 107 | canvas.onmousemove = onMouseMove; 108 | 109 | mRenderer = new THREE.WebGLRenderer({canvas: canvas, preserveDrawingBuffer: true}); 110 | 111 | mScene = new THREE.Scene(); 112 | mCamera = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5, -10000, 10000); 113 | mCamera.position.z = 100; 114 | mScene.add(mCamera); 115 | 116 | mMap = new THREE.Texture(lena); 117 | mMap.wrapS = THREE.RepeatWrapping; 118 | mMap.wrapT = THREE.RepeatWrapping; 119 | mMap.repeat.x = mMap.repeat.y = 512; 120 | mMap.needsUpdate = true; 121 | mUniforms = { 122 | screenWidth: {type: "f", value: undefined}, 123 | screenHeight: {type: "f", value: undefined}, 124 | tSource: {type: "t", value: undefined}, 125 | delta: {type: "f", value: 1.0}, 126 | feed_texture: {type: "t", value: mMap}, 127 | kill: {type: "f", value: kill}, 128 | brush: {type: "v2", value: new THREE.Vector2(-10, -10)}, 129 | color1: {type: "v4", value: new THREE.Vector4(0, 0, 0.0, 0)}, 130 | color2: {type: "v4", value: new THREE.Vector4(0, 1, 0, 0.2)}, 131 | color3: {type: "v4", value: new THREE.Vector4(1, 1, 0, 0.21)}, 132 | color4: {type: "v4", value: new THREE.Vector4(1, 0, 0, 0.4)}, 133 | color5: {type: "v4", value: new THREE.Vector4(1, 1, 1, 0.6)} 134 | }; 135 | mColors = [mUniforms.color1, mUniforms.color2, mUniforms.color3, mUniforms.color4, mUniforms.color5]; 136 | $("#gradient").gradient("setUpdateCallback", onUpdatedColor); 137 | 138 | mGSMaterial = new THREE.ShaderMaterial({ 139 | uniforms: mUniforms, 140 | vertexShader: document.getElementById('standardVertexShader').textContent, 141 | fragmentShader: document.getElementById('gsFragmentShader').textContent, 142 | }); 143 | mScreenMaterial = new THREE.ShaderMaterial({ 144 | uniforms: mUniforms, 145 | vertexShader: document.getElementById('standardVertexShader').textContent, 146 | fragmentShader: document.getElementById('screenFragmentShader').textContent, 147 | }); 148 | 149 | var plane = new THREE.PlaneGeometry(1.0, 1.0); 150 | mScreenQuad = new THREE.Mesh(plane, mScreenMaterial); 151 | mScene.add(mScreenQuad); 152 | 153 | mColorsNeedUpdate = true; 154 | 155 | resize(512, 512); 156 | 157 | render(0); 158 | mUniforms.brush.value = new THREE.Vector2(0.5, 0.5); 159 | mLastTime = new Date().getTime(); 160 | requestAnimationFrame(render); 161 | } 162 | 163 | var resize = function(width, height) 164 | { 165 | // Set the new shape of canvas. 166 | canvasQ.width(width); 167 | canvasQ.height(height); 168 | 169 | // Get the real size of canvas. 170 | canvasWidth = canvasQ.width(); 171 | canvasHeight = canvasQ.height(); 172 | 173 | mRenderer.setSize(canvasWidth, canvasHeight); 174 | 175 | // TODO: Possible memory leak? 176 | var scale = 1.0; 177 | mTexture1 = new THREE.WebGLRenderTarget(canvasWidth*scale, canvasHeight*scale, 178 | {minFilter: THREE.LinearFilter, 179 | magFilter: THREE.LinearFilter, 180 | format: THREE.RGBFormat, 181 | type: THREE.FloatType}); 182 | mTexture2 = new THREE.WebGLRenderTarget(canvasWidth*scale, canvasHeight*scale, 183 | {minFilter: THREE.LinearFilter, 184 | magFilter: THREE.LinearFilter, 185 | format: THREE.RGBFormat, 186 | type: THREE.FloatType}); 187 | 188 | mUniforms.screenWidth.value = canvasWidth*scale; 189 | mUniforms.screenHeight.value = canvasHeight*scale; 190 | } 191 | 192 | var render = function(time) 193 | { 194 | var dt = (time - mLastTime)/20.0; 195 | if(dt > 0.8 || dt<=0) 196 | dt = 0.8; 197 | mLastTime = time; 198 | 199 | mScreenQuad.material = mGSMaterial; 200 | mUniforms.delta.value = dt; 201 | // mUniforms.feed.value = feed; 202 | mUniforms.kill.value = kill; 203 | 204 | for(var i=0; i<8; ++i) 205 | { 206 | if(!mToggled) 207 | { 208 | mUniforms.tSource.value = mTexture1; 209 | mRenderer.render(mScene, mCamera, mTexture2, true); 210 | mUniforms.tSource.value = mTexture2; 211 | } 212 | else 213 | { 214 | mUniforms.tSource.value = mTexture2; 215 | mRenderer.render(mScene, mCamera, mTexture1, true); 216 | mUniforms.tSource.value = mTexture1; 217 | } 218 | 219 | mToggled = !mToggled; 220 | mUniforms.brush.value = mMinusOnes; 221 | } 222 | 223 | if(mColorsNeedUpdate) 224 | updateUniformsColors(); 225 | 226 | mScreenQuad.material = mScreenMaterial; 227 | mRenderer.render(mScene, mCamera); 228 | 229 | requestAnimationFrame(render); 230 | } 231 | 232 | loadPreset = function(idx) 233 | { 234 | feed = presets[idx].feed; 235 | kill = presets[idx].kill; 236 | worldToForm(); 237 | } 238 | 239 | var updateUniformsColors = function() 240 | { 241 | var values = $("#gradient").gradient("getValuesRGBS"); 242 | for(var i=0; i 2 | 3 | 4 | Reaction diffusion simulation 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 23 | 70 | 123 | 124 | 125 | 126 | 136 | 155 | 156 | 157 |
158 |

Gray-Scott model with image-based feed rate (alpha)

159 |
160 |
161 | 162 | 183 |
184 | 192 | 193 |
194 |

This simulation requires the GL extensions framebuffer_object and texture_float. 195 | If you cannot see the simulation your system probably lacks at least one of these extensions.

196 | 197 |

In Google Chrome, you can see the available GL extensions going to chrome://gpu.

198 |
199 | 200 | 201 | -------------------------------------------------------------------------------- /gsimage/lena512.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/gsimage/lena512.jpg -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /massspring/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Mass-spring simulation 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 17 | 18 | 19 |
20 |

Mass-spring simulation

21 |
22 |
23 | 24 | 76 |
77 |
78 | 81 |
82 | 83 | 84 | -------------------------------------------------------------------------------- /massspring/particles.js: -------------------------------------------------------------------------------- 1 | 2 | /* 3 | * Particles 4 | * 5 | * A simple mass-spring simulator. 6 | * 7 | * ©2010 pmneila 8 | * p.mneila at upm.es 9 | */ 10 | 11 | // Canvas. 12 | var canvas; 13 | var canvasWidth = 1000; 14 | var canvasHeight = 500; 15 | var ctx; 16 | var simulation; 17 | 18 | // World constants. 19 | var airFriction = 0.05; 20 | var floorFriction = 0.8; 21 | var gravity = 9.8; 22 | var pixelsPerMeter = 50; 23 | 24 | var particleMass = 0.1; 25 | 26 | var springLength = 100; // In pixels. 27 | var springStiffness = 0.5; 28 | var springDamping = 0.2; 29 | 30 | // Physical world. 31 | var particles = []; 32 | var springs = []; 33 | 34 | // Mouse. 35 | var mouseX, mouseY, mouseDown; 36 | var clickRadius = 30; 37 | var heldParticle = 0; 38 | 39 | // Time variables. 40 | var simStep = 0.033; 41 | var simSpeedup = 1; 42 | 43 | // Scale show. 44 | var scaleAlpha = 0; 45 | 46 | function Particle(pos, vel) 47 | { 48 | this.position = pos; 49 | this.velocity = vel; 50 | this.radius = 3;//Math.log(mass); 51 | this.style = "rgba(200, 255, 255, 1)"; 52 | this.hold = false; 53 | this.pin = false; 54 | 55 | this.force = [0,0]; 56 | 57 | this.update = function(step) 58 | { 59 | // Ignore held particles. 60 | if(this.hold) 61 | { 62 | this.velocity = [0,0]; 63 | this.position = [mouseX, mouseY]; 64 | this.force = [0,0]; 65 | return; 66 | } 67 | 68 | if(this.pin) 69 | { 70 | this.velocity = [0,0]; 71 | this.force = [0,0]; 72 | return; 73 | } 74 | 75 | // Euler method (slightly different version). 76 | this.velocity[0] += this.force[0] * step / particleMass; 77 | this.velocity[1] += this.force[1] * step / particleMass; 78 | this.position[0] += pixelsPerMeter * this.velocity[0] * step; 79 | this.position[1] += pixelsPerMeter * this.velocity[1] * step; 80 | 81 | // Rough collision detection. 82 | if(this.position[0] < 0) 83 | { 84 | this.position[0] = 0; 85 | if(this.velocity[0] < 0) 86 | this.velocity[0] = 0; 87 | this.velocity[1] -= floorFriction * this.velocity[1]; 88 | } 89 | if(this.position[1] < 0) 90 | { 91 | this.position[1] = 0; 92 | if(this.velocity[1] < 0) 93 | this.velocity[1] = 0; 94 | this.velocity[0] -= floorFriction * this.velocity[0]; 95 | } 96 | if(this.position[0] > canvasWidth) 97 | { 98 | this.position[0] = canvasWidth; 99 | if(this.velocity[0] > 0) 100 | this.velocity[0] = 0; 101 | this.velocity[1] -= floorFriction * this.velocity[1]; 102 | } 103 | if(this.position[1] > canvasHeight) 104 | { 105 | this.position[1] = canvasHeight; 106 | if(this.velocity[1] > 0) 107 | this.velocity[1] = 0; 108 | this.velocity[0] -= floorFriction * this.velocity[0]; 109 | } 110 | 111 | this.force = [0,0]; 112 | } 113 | 114 | this.addForce = function(force) 115 | { 116 | this.force[0] += force[0]; 117 | this.force[1] += force[1]; 118 | } 119 | 120 | this.addGravity = function() 121 | { 122 | this.addForce([0, particleMass * gravity]); 123 | } 124 | 125 | this.addAirFriction = function() 126 | { 127 | this.force[0] -= this.velocity[0] * airFriction; 128 | this.force[1] -= this.velocity[1] * airFriction; 129 | } 130 | 131 | this.setHold = function(val) 132 | { 133 | this.hold = val; 134 | } 135 | 136 | this.setPin = function(val) 137 | { 138 | this.pin = val; 139 | if(val) 140 | this.style = "rgba(200, 100, 100, 1)"; 141 | else 142 | this.style = "rgba(200, 255, 255, 1)"; 143 | } 144 | } 145 | 146 | function Spring(p1, p2) 147 | { 148 | this.particle1 = p1; 149 | this.particle2 = p2; 150 | this.length = 0; 151 | this.v12 = [0,0]; 152 | this.dir12 = [0,0]; 153 | 154 | this.updateValues = function() 155 | { 156 | var p1 = this.particle1; 157 | var p2 = this.particle2; 158 | this.v12 = [p2.position[0] - p1.position[0], p2.position[1] - p1.position[1]]; 159 | this.length = norm(this.v12); 160 | if(this.length == 0) 161 | { 162 | this.v12 = [Math.random()/10 - 0.05, Math.random()/10 - 0.05]; 163 | this.length = norm(this.v12); 164 | } 165 | this.dir12 = [this.v12[0]/this.length, this.v12[1]/this.length]; 166 | } 167 | 168 | this.getVector12 = function() 169 | { 170 | return this.v12; 171 | } 172 | 173 | this.getVector21 = function() 174 | { 175 | return [-this.v12[0], -this.v12[1]]; 176 | } 177 | 178 | this.getDir12 = function() 179 | { 180 | return this.dir12; 181 | } 182 | 183 | this.getDir21 = function() 184 | { 185 | return [-this.dir12[0], -this.dir12[1]] 186 | } 187 | 188 | this.getLength = function() 189 | { 190 | return this.length; 191 | } 192 | } 193 | 194 | function init() 195 | { 196 | init_controls(); 197 | 198 | canvas = document.getElementById("myCanvas"); 199 | simulation = document.getElementById("simulation"); 200 | canvas.onmousedown = onMouseDown; 201 | canvas.onmouseup = onMouseUp; 202 | canvas.onmousemove = onMouseMove; 203 | ctx = canvas.getContext("2d"); 204 | 205 | loadPentagon(); 206 | 207 | setInterval(run, simStep*1000); 208 | } 209 | 210 | function createPolygon(center, radius, nsides) 211 | { 212 | var particles = []; 213 | var springs = []; 214 | 215 | var i = 0; 216 | for(i = 0; i < nsides; ++i) 217 | { 218 | var angle = i*2*Math.PI/nsides + 0.1; 219 | var x = center[0] + radius * Math.cos(angle); 220 | var y = center[1] + radius * Math.sin(angle); 221 | particles[i] = new Particle([x,y], [0,0]); 222 | 223 | var j; 224 | for(j = 0; j < i; ++j) 225 | springs.push(new Spring(particles[i], particles[j])); 226 | } 227 | 228 | return [particles, springs]; 229 | } 230 | 231 | function createGrid(lu, M, N, side) 232 | { 233 | var particles = []; 234 | var springs = []; 235 | 236 | var i, j; 237 | for(i = 0; i < M; ++i) 238 | { 239 | var y = lu[1] + i*side; 240 | for(j = 0; j < N; ++j) 241 | { 242 | var x = lu[0] + j*side; 243 | var idx = i * N + j; 244 | particles[idx] = new Particle([x,y], [0,0]); 245 | if(j > 0) 246 | springs.push(new Spring(particles[idx], particles[idx-1])); 247 | if(i > 0) 248 | springs.push(new Spring(particles[idx], particles[idx-N])); 249 | if(i==0 && j%3==0) 250 | particles[idx].setPin(true); 251 | } 252 | } 253 | 254 | return [particles, springs]; 255 | } 256 | 257 | function run() 258 | { 259 | // Update forces. 260 | var i; 261 | for(i in springs) 262 | { 263 | var s = springs[i]; 264 | var p = s.particle1; 265 | var q = s.particle2; 266 | 267 | s.updateValues(); 268 | var r = s.getLength(); 269 | var dir12 = s.getDir12(); 270 | var cte = springStiffness * (r - springLength); 271 | cte -= springDamping * dot(diff(p.velocity, q.velocity), dir12); 272 | var force1 = [cte*dir12[0], cte*dir12[1]]; 273 | var force2 = [-force1[0], -force1[1]]; 274 | p.addForce(force1); 275 | q.addForce(force2); 276 | } 277 | 278 | for(i in particles) 279 | { 280 | var p = particles[i]; 281 | p.addAirFriction(); 282 | p.addGravity(); 283 | p.update(simStep * simSpeedup); 284 | } 285 | 286 | // Update the view. 287 | ctx.fillStyle = "rgba(0, 0, 0, 0.65)";//"#000000"; 288 | ctx.fillRect(0, 0, canvasWidth, canvasHeight); 289 | 290 | ctx.strokeStyle = "#666666"; 291 | for(i in springs) 292 | { 293 | var s = springs[i]; 294 | var p = s.particle1; 295 | var q = s.particle2; 296 | ctx.beginPath(); 297 | ctx.moveTo(p.position[0], p.position[1]); 298 | ctx.lineTo(q.position[0], q.position[1]); 299 | ctx.stroke(); 300 | } 301 | 302 | for(i in particles) 303 | { 304 | var p = particles[i]; 305 | ctx.fillStyle = p.style; 306 | ctx.beginPath(); 307 | ctx.arc(p.position[0], p.position[1], p.radius, 0, 2*Math.PI, false); 308 | ctx.closePath(); 309 | ctx.fill(); 310 | } 311 | 312 | if(scaleAlpha > 0) 313 | { 314 | drawScale(scaleAlpha); 315 | scaleAlpha -= 0.01; 316 | } 317 | } 318 | 319 | function drawScale(scaleAlpha) 320 | { 321 | ctx.strokeStyle = "rgba(255, 255, 255, " + scaleAlpha + ")"; 322 | ctx.fillStyle = ctx.strokeStyle; 323 | ctx.beginPath(); 324 | // Top line. 325 | ctx.moveTo(5, 20); 326 | ctx.lineTo(canvasWidth/2-40, 20); 327 | ctx.moveTo(canvasWidth/2+40, 20); 328 | ctx.lineTo(canvasWidth-5, 20); 329 | // Right line. 330 | ctx.moveTo(canvasWidth-20, 5); 331 | ctx.lineTo(canvasWidth-20, canvasHeight/2-40); 332 | ctx.moveTo(canvasWidth-20, canvasHeight/2+40); 333 | ctx.lineTo(canvasWidth-20, canvasHeight-5); 334 | ctx.stroke(); 335 | // Top text. 336 | ctx.textAlign = "center"; 337 | ctx.textBaseline = "middle"; 338 | ctx.fillText((canvasWidth/pixelsPerMeter).toFixed(2) + "m", canvasWidth/2, 20); 339 | // Right text. 340 | ctx.save(); 341 | ctx.translate(canvasWidth-20, canvasHeight/2); 342 | ctx.rotate(Math.PI/2); 343 | ctx.fillText((canvasHeight/pixelsPerMeter).toFixed(2) + "m", 0, 0); 344 | ctx.restore(); 345 | } 346 | 347 | function getNearestParticle(pos) 348 | { 349 | var i = 0; 350 | for(i = 0; i < particles.length; ++i) 351 | { 352 | var p = particles[i]; 353 | var dist = norm(diff(p.position, pos)); 354 | if(dist < clickRadius) 355 | return p; 356 | } 357 | return 0; 358 | } 359 | 360 | function holdParticle(p) 361 | { 362 | if(p != 0) 363 | { 364 | heldParticle = p; 365 | heldParticle.setHold(true); 366 | } 367 | } 368 | 369 | function releaseParticle() 370 | { 371 | if(!heldParticle) 372 | return; 373 | 374 | heldParticle.setHold(false); 375 | heldParticle = 0; 376 | } 377 | 378 | function diff(p1, p2) 379 | { 380 | var res = []; 381 | var i = 0; 382 | for(i = 0; i < p1.length; ++i) 383 | res[i] = p1[i] - p2[i]; 384 | return res; 385 | } 386 | 387 | function dot(v1, v2) 388 | { 389 | var sum = 0; 390 | var i; 391 | for (i in v1) 392 | sum += v1[i]*v2[i]; 393 | return sum; 394 | } 395 | 396 | function norm(vector) 397 | { 398 | var sum = 0; 399 | var i; 400 | for (i in vector) 401 | sum += vector[i]*vector[i]; 402 | return Math.sqrt(sum); 403 | } 404 | 405 | function onMouseMove(e) 406 | { 407 | var ev = e ? e : window.event; 408 | mouseX = ev.pageX - simulation.offsetLeft; 409 | mouseY = ev.pageY - simulation.offsetTop; 410 | } 411 | 412 | function onMouseDown(e) 413 | { 414 | var ev = e ? e : window.event; 415 | mouseDown = true; 416 | var p = getNearestParticle([mouseX, mouseY]); 417 | if(!p) 418 | return; 419 | 420 | if(ev.button == 0) 421 | holdParticle(p); 422 | if(ev.button == 1) 423 | p.setPin(!p.pin); 424 | } 425 | 426 | function onMouseUp(e) 427 | { 428 | mouseDown = false; 429 | releaseParticle(); 430 | } 431 | 432 | function worldToForm() 433 | { 434 | $("#sld_gravity").slider("value", gravity); 435 | $("#sld_length").slider("value", springLength); 436 | $("#sld_stiffness").slider("value", springStiffness); 437 | $("#sld_floor_friction").slider("value", floorFriction); 438 | $("#sld_air_friction").slider("value", airFriction); 439 | $("#sld_mass").slider("value", particleMass); 440 | } 441 | 442 | function init_controls() 443 | { 444 | $("#sld_air_friction").slider({ 445 | value: 0.05, min: -0.05, max:1, step:0.05, 446 | change: function(event, ui) {$("#airFriction").html(ui.value); airFriction = ui.value;}, 447 | slide: function(event, ui) {$("#airFriction").html(ui.value); airFriction = ui.value;} 448 | }); 449 | $("#sld_floor_friction").slider({ 450 | value: 0.8, min: -0.1, max:1, step:0.05, 451 | change: function(event, ui) {$("#floorFriction").html(ui.value); floorFriction = ui.value;}, 452 | slide: function(event, ui) {$("#floorFriction").html(ui.value); floorFriction = ui.value;} 453 | }); 454 | $("#sld_gravity").slider({ 455 | value: 9.8, min: -10, max:40, step:0.1, 456 | change: function(event, ui) {$("#gravity").html(ui.value); gravity = ui.value;}, 457 | slide: function(event, ui) {$("#gravity").html(ui.value); gravity = ui.value;} 458 | }); 459 | $("#sld_mass").slider({ 460 | value: 0.1, min: 0.1, max:2, step:0.1, 461 | change: function(event, ui) {$("#mass").html(ui.value); particleMass = ui.value;}, 462 | slide: function(event, ui) {$("#mass").html(ui.value); particleMass = ui.value;} 463 | }); 464 | $("#sld_length").slider({ 465 | value: 100, min: 20, max:150, step:1, 466 | change: function(event, ui) {$("#length").html(ui.value); springLength = ui.value;}, 467 | slide: function(event, ui) {$("#length").html(ui.value); springLength = ui.value;} 468 | }); 469 | $("#sld_stiffness").slider({ 470 | value: 0.5, min: 0.1, max:2, step:0.1, 471 | change: function(event, ui) {$("#stiffness").html(ui.value); springStiffness = ui.value;}, 472 | slide: function(event, ui) {$("#stiffness").html(ui.value); springStiffness = ui.value;} 473 | }); 474 | //$("#btn_reset").button(); 475 | } 476 | 477 | function showScale() 478 | { 479 | scaleAlpha = 1; 480 | } 481 | 482 | function showParticles() 483 | { 484 | var i; 485 | for (i in particles) 486 | { 487 | var p = particles[i]; 488 | alert(p.position); 489 | } 490 | } 491 | -------------------------------------------------------------------------------- /massspring/particles.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/massspring/particles.png -------------------------------------------------------------------------------- /massspring/scenes.js: -------------------------------------------------------------------------------- 1 | 2 | function loadPentagon() 3 | { 4 | airFriction = 0.05; 5 | floorFriction = 0.8; 6 | gravity = 9.8; 7 | pixelsPerMeter = 50; 8 | 9 | particleMass = 0.1; 10 | 11 | springLength = 100; // In pixels. 12 | springStiffness = 0.5; 13 | springDamping = 0.2; 14 | 15 | initialMass = 0.1; 16 | 17 | worldToForm(); 18 | 19 | var res = createPolygon([canvasWidth/2, canvasHeight/2], 50, 5); 20 | particles = res[0]; 21 | springs = res[1]; 22 | } 23 | 24 | function loadHexagon() 25 | { 26 | airFriction = 0.05; 27 | floorFriction = 0.8; 28 | gravity = 9.8; 29 | pixelsPerMeter = 50; 30 | 31 | particleMass = 0.1; 32 | 33 | springLength = 100; // In pixels. 34 | springStiffness = 0.5; 35 | springDamping = 0.2; 36 | 37 | initialMass = 0.1; 38 | 39 | worldToForm(); 40 | 41 | var res = createPolygon([canvasWidth/2, canvasHeight/2], 50, 6); 42 | particles = res[0]; 43 | springs = res[1]; 44 | } 45 | 46 | function loadFabric() 47 | { 48 | airFriction = 0.05; 49 | floorFriction = 0.8; 50 | gravity = 9.8; 51 | pixelsPerMeter = 100; 52 | 53 | particleMass = 0.1; 54 | 55 | springLength = 40; // In pixels. 56 | springStiffness = 0.2; 57 | springDamping = 0.2; 58 | 59 | initialMass = 0.1; 60 | 61 | worldToForm(); 62 | 63 | var res = createGrid([250,30], 7, 10, springLength+10); 64 | particles = res[0]; 65 | springs = res[1]; 66 | } 67 | 68 | function loadFabric2() 69 | { 70 | airFriction = 0.05; 71 | floorFriction = 0.8; 72 | gravity = 9.8; 73 | pixelsPerMeter = 100; 74 | 75 | particleMass = 0.1; 76 | 77 | springLength = 40; // In pixels. 78 | springStiffness = 0.2; 79 | springDamping = 0.2; 80 | 81 | initialMass = 0.1; 82 | 83 | worldToForm(); 84 | 85 | var res = createGrid([250,30], 7, 10, springLength+10); 86 | particles = res[0]; 87 | springs = res[1]; 88 | 89 | particles[3].setPin(false); 90 | particles[6].setPin(false); 91 | particles[60].setPin(true); 92 | particles[69].setPin(true); 93 | particles[0].position = [100,50]; 94 | particles[60].position = [350,80]; 95 | particles[9].position = [650, 50]; 96 | particles[69].position = [780, 70]; 97 | } 98 | 99 | function loadPolygons() 100 | { 101 | airFriction = 0.05; 102 | floorFriction = 0.8; 103 | gravity = 9.8; 104 | pixelsPerMeter = 50; 105 | 106 | particleMass = 0.1; 107 | 108 | springLength = 100; // In pixels. 109 | springStiffness = 0.5; 110 | springDamping = 0.2; 111 | 112 | initialMass = 0.1; 113 | 114 | worldToForm(); 115 | 116 | var res = createPolygon([canvasWidth/2-300, canvasHeight/2], 50, 3); 117 | res[0][0].setPin(true); 118 | particles = res[0]; 119 | springs = res[1]; 120 | res = createPolygon([canvasWidth/2-150, canvasHeight/2], 50, 4); 121 | res[0][0].setPin(true); 122 | particles = particles.concat(res[0]); 123 | springs = springs.concat(res[1]); 124 | res = createPolygon([canvasWidth/2, canvasHeight/2], 50, 5); 125 | res[0][0].setPin(true); 126 | particles = particles.concat(res[0]); 127 | springs = springs.concat(res[1]); 128 | res = createPolygon([canvasWidth/2+150, canvasHeight/2], 50, 6); 129 | res[0][0].setPin(true); 130 | particles = particles.concat(res[0]); 131 | springs = springs.concat(res[1]); 132 | } 133 | -------------------------------------------------------------------------------- /opticalflowtest/clicktopaint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/opticalflowtest/clicktopaint.png -------------------------------------------------------------------------------- /opticalflowtest/opticalflow.js: -------------------------------------------------------------------------------- 1 | var PaintFlow = function(){ 2 | 3 | this.canvas = undefined; 4 | this.canvasQ = undefined; 5 | this.canvasWidth = undefined; 6 | this.canvasHeight = undefined; 7 | 8 | this.mMouseX = undefined; 9 | this.mMouseY = undefined; 10 | this.mMouseDown = false; 11 | 12 | this.mRenderer = undefined; 13 | this.mScene = undefined; 14 | this.mCamera = undefined; 15 | 16 | this.mStep = 0 >>> 0; // coerce to uint32 17 | this.uiFour = 4 >>> 0; 18 | 19 | this.mTexture1 = undefined; 20 | this.mTexture2 = undefined; 21 | this.mTexture3 = undefined; 22 | this.mTexture4 = undefined; 23 | this.mScreenQuad = undefined; 24 | 25 | this.fluidShaderId = 'frustratedFlockingFluidFragmentShader'; 26 | this.feedbackMaterial = undefined; 27 | this.screenMaterial = undefined; 28 | this.opticalFlowMaterial = undefined; 29 | this.debugScreenMaterial = undefined; 30 | 31 | this.textureWidth = 1024; 32 | this.textureHeight = 512; 33 | 34 | this.mMinusOnes = new THREE.Vector2(-1, -1); 35 | 36 | this.presets = [ 37 | { // Default 38 | curlf: 0.256, 39 | fluxf: 0.128, 40 | divf: 0.01, 41 | lapf: 0.04, 42 | feedf: 1.001, 43 | expf: 0.2, 44 | mixf: 0.85, 45 | offf: 0.0, 46 | sofff: 1.0, 47 | scalef: 5.0, 48 | flockf: 0.5, 49 | frustf: 0.4, 50 | contf: 0.0 51 | } 52 | ]; 53 | 54 | // Configuration. 55 | this.curlf = this.presets[0].curlf; 56 | this.fluxf = this.presets[0].fluxf; 57 | this.divf = this.presets[0].divf; 58 | this.lapf = this.presets[0].lapf; 59 | this.feedf = this.presets[0].feedf; 60 | this.expf = this.presets[0].expf; 61 | this.mixf = this.presets[0].mixf; 62 | this.offf = this.presets[0].offf; 63 | this.flockf = this.presets[0].flockf; 64 | this.frustf = this.presets[0].frustf; 65 | this.brushsize = 50.0; 66 | this.timesteps = 2; 67 | 68 | this.mUniforms = { 69 | screenWidth: {type: "f", value: undefined}, 70 | screenHeight: {type: "f", value: undefined}, 71 | tSource: {type: "t", value: undefined}, 72 | tSource2: {type: "t", value: undefined}, 73 | sSource: {type: "t", value: undefined}, 74 | loadImage: {type: "f", value: 1.0}, 75 | mixf : {type: "f", value: this.mixf}, 76 | curlf : {type: "f", value: this.curlf}, 77 | fluxf : {type: "f", value: this.fluxf}, 78 | divf : {type: "f", value: this.divf}, 79 | lapf : {type: "f", value: this.lapf}, 80 | feedf : {type: "f", value: this.feedf}, 81 | expf : {type: "f", value: this.expf}, 82 | offf : {type: "f", value: this.offf}, 83 | flockf : {type: "f", value: this.flockf}, 84 | frustf : {type: "f", value: this.frustf}, 85 | brushsize: {type: "f", value: this.brushsize}, 86 | brush: {type: "v2", value: this.mMinusOnes} 87 | }; 88 | 89 | this.init = function() 90 | { 91 | this.initCanvas(); 92 | this.initGl(); 93 | this.render(); 94 | }; 95 | 96 | this.initCanvas = function() 97 | { 98 | this.canvasQ = $('#myCanvas'); 99 | this.canvas = this.canvasQ.get(0); 100 | 101 | this.canvas.onmousedown = this.onMouseDown.bind(this); 102 | this.canvas.onmouseup = this.onMouseUp.bind(this); 103 | this.canvas.onmousemove = this.onMouseMove.bind(this); 104 | 105 | window.addEventListener( 'resize', this.onResize.bind(this), false ); 106 | }; 107 | 108 | this.getMaterial = function(fragmentShaderId) 109 | { 110 | return new THREE.ShaderMaterial({ 111 | uniforms: this.mUniforms, 112 | vertexShader: document.getElementById('standardVertexShader').textContent, 113 | fragmentShader: document.getElementById(fragmentShaderId).textContent 114 | }); 115 | }; 116 | 117 | this.initGl = function() 118 | { 119 | this.mRenderer = new THREE.WebGLRenderer({canvas: this.canvas, preserveDrawingBuffer: true}); 120 | 121 | this.mScene = new THREE.Scene(); 122 | this.mCamera = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5, -1, 1); 123 | this.mCamera.position.z = 0; 124 | this.mScene.add(this.mCamera); 125 | 126 | this.feedbackMaterial = this.getMaterial(this.fluidShaderId); 127 | this.opticalFlowMaterial = this.getMaterial('opticalFlowFragmentShader'); 128 | this.screenMaterial = this.getMaterial('screenFragmentShader'); 129 | this.debugScreenMaterial = this.getMaterial('debugScreenFragmentShader'); 130 | 131 | var plane = new THREE.PlaneGeometry(1.0, 1.0); 132 | this.mScreenQuad = new THREE.Mesh(plane, this.screenMaterial); 133 | this.mScene.add(this.mScreenQuad); 134 | 135 | // Set the new shape of canvas. 136 | this.canvasQ.width(this.getCanvasWidth()); 137 | this.canvasQ.height(this.getCanvasHeight()); 138 | 139 | // Get the real size of canvas. 140 | this.canvasWidth = this.canvasQ.width(); 141 | this.canvasHeight = this.canvasQ.height(); 142 | 143 | this.mRenderer.setSize(this.canvasWidth, this.canvasHeight); 144 | 145 | this.mTexture1 = this.getWrappedRenderTarget(); 146 | this.mTexture2 = this.getWrappedRenderTarget(); 147 | this.mTexture3 = this.getWrappedRenderTarget(); 148 | this.mTexture4 = this.getWrappedRenderTarget(); 149 | 150 | this.mUniforms.screenWidth.value = this.textureWidth; 151 | this.mUniforms.screenHeight.value = this.textureHeight; 152 | this.mUniforms.brush.value = this.mMinusOnes; 153 | 154 | }; 155 | 156 | this.getWrappedRenderTarget = function() 157 | { 158 | var rt = new THREE.WebGLRenderTarget(this.textureWidth, this.textureHeight, { 159 | minFilter: THREE.LinearFilter, 160 | magFilter: THREE.LinearFilter, 161 | format: THREE.RGBFormat, 162 | type: THREE.FloatType, 163 | wrapS: THREE.RepeatWrapping, 164 | wrapT: THREE.RepeatWrapping 165 | }); 166 | this.mRenderer.clearTarget(rt, true, true, true); 167 | return rt; 168 | }; 169 | 170 | this.updateUniforms = function() 171 | { 172 | this.mUniforms.curlf.value = this.curlf; 173 | this.mUniforms.fluxf.value = this.fluxf; 174 | this.mUniforms.divf.value = this.divf; 175 | this.mUniforms.lapf.value = this.lapf; 176 | this.mUniforms.feedf.value = this.feedf; 177 | this.mUniforms.expf.value = this.expf; 178 | this.mUniforms.flockf.value = this.flockf; 179 | this.mUniforms.frustf.value = this.frustf; 180 | this.mUniforms.brushsize.value = this.brushsize; 181 | }; 182 | 183 | this.renderToTarget = function(material, tSource, tSource2, sSource, target) 184 | { 185 | this.mScreenQuad.material = material; 186 | this.mUniforms.tSource.value = tSource; 187 | this.mUniforms.tSource2.value = tSource2; 188 | this.mUniforms.sSource.value = sSource; 189 | this.mRenderer.render(this.mScene, this.mCamera, target, true); 190 | }; 191 | 192 | this.render = function() 193 | { 194 | 195 | this.updateUniforms(); 196 | 197 | for(var i = 0; i < this.timesteps; ++i) { 198 | 199 | var pStep = this.mStep % this.uiFour; 200 | 201 | if (pStep == 0) { 202 | this.renderToTarget(this.feedbackMaterial, this.mTexture1, this.mTexture2, this.mTexture3, this.mTexture4); 203 | this.renderToTarget(this.opticalFlowMaterial, this.mTexture4, this.mTexture1, this.mTexture3, this.mTexture2); 204 | } else if (pStep == 1) { 205 | this.renderToTarget(this.feedbackMaterial, this.mTexture4, this.mTexture1, this.mTexture2, this.mTexture3); 206 | this.renderToTarget(this.opticalFlowMaterial, this.mTexture3, this.mTexture4, this.mTexture2, this.mTexture1); 207 | } else if (pStep == 2) { 208 | this.renderToTarget(this.feedbackMaterial, this.mTexture3, this.mTexture4, this.mTexture1, this.mTexture2); 209 | this.renderToTarget(this.opticalFlowMaterial, this.mTexture2, this.mTexture3, this.mTexture1, this.mTexture4); 210 | } else if (pStep == 3) { 211 | this.renderToTarget(this.feedbackMaterial, this.mTexture2, this.mTexture3, this.mTexture4, this.mTexture1); 212 | this.renderToTarget(this.opticalFlowMaterial, this.mTexture1, this.mTexture2, this.mTexture4, this.mTexture3); 213 | } 214 | 215 | this.mUniforms.brush.value = this.mMinusOnes; 216 | 217 | this.mStep++; 218 | } 219 | 220 | this.mScreenQuad.material = this.screenMaterial; 221 | this.mRenderer.render(this.mScene, this.mCamera); 222 | this.mUniforms.loadImage.value = 0.0; // only load image on first frame 223 | requestAnimationFrame(this.render.bind(this)); 224 | }; 225 | 226 | this.snapshot = function() 227 | { 228 | var dataURL = this.canvas.toDataURL("image/jpeg"); 229 | window.open(dataURL, "name-"+Math.random()); 230 | }; 231 | 232 | this.debug = function() 233 | { 234 | var temp = this.debugScreenMaterial; 235 | this.debugScreenMaterial = this.screenMaterial; 236 | this.screenMaterial = temp; 237 | }; 238 | 239 | this.onMouseMove = function(e) 240 | { 241 | var ev = e ? e : window.event; 242 | 243 | this.mMouseX = ev.pageX - this.canvasQ.offset().left; // these offsets work with 244 | this.mMouseY = ev.pageY - this.canvasQ.offset().top; // scrolled documents too 245 | 246 | if(this.mMouseDown) { 247 | this.mUniforms.brush.value = new THREE.Vector2(this.mMouseX / this.canvasWidth, 1 - this.mMouseY / this.canvasHeight); 248 | } 249 | }; 250 | 251 | this.onMouseDown = function() 252 | { 253 | this.mMouseDown = true; 254 | this.mUniforms.brush.value = new THREE.Vector2(this.mMouseX/this.canvasWidth, 1-this.mMouseY/this.canvasHeight); 255 | }; 256 | 257 | this.onMouseUp = function() 258 | { 259 | this.mMouseDown = false; 260 | }; 261 | 262 | this.onResize = function() 263 | { 264 | 265 | // Set the new shape of canvas. 266 | this.canvasQ.width(this.getCanvasWidth()); 267 | this.canvasQ.height(this.getCanvasHeight()); 268 | 269 | // Get the real size of canvas. 270 | this.canvasWidth = this.canvasQ.width(); 271 | this.canvasHeight = this.canvasQ.height(); 272 | 273 | this.mRenderer.setSize(this.canvasWidth, this.canvasHeight); 274 | 275 | }; 276 | 277 | this.getCanvasWidth = function() 278 | { 279 | return window.innerWidth; 280 | }; 281 | 282 | this.getCanvasHeight = function() 283 | { 284 | return window.innerHeight; 285 | }; 286 | 287 | this.parseColorString = function(colorString) 288 | { 289 | var m = colorString.match(/^#([0-9a-f]{6})$/i)[1]; 290 | if( m ) { 291 | return [ 292 | parseInt(m.substr(0,2),16), 293 | parseInt(m.substr(2,2),16), 294 | parseInt(m.substr(4,2),16) 295 | ]; 296 | } else { 297 | return [255, 255, 255]; 298 | } 299 | }; 300 | 301 | this.updateFluidShader = function(shaderId) { 302 | this.feedbackMaterial = this.getMaterial(shaderId); 303 | }; 304 | 305 | }; 306 | 307 | var swappableControllers = []; 308 | 309 | var swappableControllerUniforms = { 310 | 'smokeFluidFragmentShader' : [ 311 | {id: 'curlf', name: 'Curl', min: -2.0, max: 2.0, step: 0.001}, 312 | {id: 'fluxf', name: 'Flux', min: -0.5, max: 0.5, step: 0.001}, 313 | {id: 'divf', name: 'Divergence', min: -1, max: 1, step: 0.001}, 314 | {id: 'lapf', name: 'Laplacian', min: -0.1, max: 0.1, step: 0.001}, 315 | {id: 'feedf', name: 'Amplification', min: 0.9998, max: 1.01, step: 0.001}, 316 | {id: 'expf', name: 'Curl Exponent', min: 0.0, max: 3.0, step: 0.001} 317 | ], 318 | 'frustratedFlockingFluidFragmentShader' : [ 319 | {id: 'flockf', name: 'Flocking', min: -0.6, max: 0.6, step: 0.001}, 320 | {id: 'frustf', name: 'Frustration', min: -0.6, max: 0.6, step: 0.001}, 321 | {id: 'fluxf', name: 'Flux', min: -0.5, max: 0.5, step: 0.001}, 322 | {id: 'divf', name: 'Divergence', min: -0.6, max: 0.6, step: 0.001}, 323 | {id: 'lapf', name: 'Laplacian', min: -0.1, max: 0.1, step: 0.001}, 324 | {id: 'feedf', name: 'Amplification', min: 0.9998, max: 1.01, step: 0.001} 325 | ], 326 | 'simplexNoiseFragmentShader' : [ 327 | {id: 'scalef', name: 'Simplex Scale', min: 0.0, max: 100.0, step: 0.1}, 328 | {id: 'sofff', name: 'Y Offset', min: 0.0, max: 1.0, step: 0.001} 329 | ] 330 | }; 331 | 332 | var updateUI = function(shaderId, gui, paintFlow) { 333 | swappableControllers.forEach( function (controller) { 334 | gui.remove(controller); 335 | }); 336 | swappableControllers = []; 337 | var uniformsToSwap = swappableControllerUniforms[shaderId]; 338 | uniformsToSwap.forEach( function (params) { 339 | swappableControllers.push( 340 | gui.add(paintFlow, params.id) 341 | .min(params.min) 342 | .max(params.max) 343 | .step(params.step) 344 | .name(params.name) 345 | ); 346 | }); 347 | paintFlow.updateFluidShader(shaderId); 348 | }; 349 | 350 | window.onload = function() { 351 | var paintFlow = new PaintFlow(); 352 | var gui = new dat.GUI(); 353 | 354 | gui.add(paintFlow, 'timesteps').min(0).max(10).step(1).name("Speed"); 355 | gui.add(paintFlow, 'snapshot').name("Screenshot"); 356 | gui.add(paintFlow, 'debug').name("Fluid View"); 357 | gui.add(paintFlow, 'fluidShaderId', { 358 | 'Frustrated Flocking': 'frustratedFlockingFluidFragmentShader', 359 | 'Smoke': 'smokeFluidFragmentShader' 360 | }).name("Fluid Type").onChange(function(shaderId){updateUI(shaderId, gui, paintFlow)}); 361 | updateUI('frustratedFlockingFluidFragmentShader', gui, paintFlow); 362 | 363 | gui.remember(paintFlow); 364 | 365 | paintFlow.init(); 366 | }; 367 | -------------------------------------------------------------------------------- /paintflow2/clicktopaint.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/paintflow2/clicktopaint.png -------------------------------------------------------------------------------- /softmaxdenoise/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Softmax Manifold Denoise 5 | 6 | 7 | 8 | 9 | 10 | 19 | 28 | 139 | 140 | 141 | 142 |
143 | 144 |
145 | 146 | 147 | -------------------------------------------------------------------------------- /softmaxdenoise/mandrill_noisy.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/softmaxdenoise/mandrill_noisy.jpg -------------------------------------------------------------------------------- /softmaxdenoise/softmax.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font-family:sans-serif; 4 | background:#333333; 5 | color:#777777; 6 | margin: 0 auto; 7 | } 8 | 9 | header, footer, aside, nav { 10 | display: block; 11 | } 12 | 13 | #myCanvas { 14 | display:block; 15 | vertical-align:bottom; 16 | background-color:#000000; 17 | } -------------------------------------------------------------------------------- /softmaxdenoise/softmax.js: -------------------------------------------------------------------------------- 1 | var ManifoldDenoise = function(config){ 2 | 3 | this.canvas = undefined; 4 | this.canvasQ = undefined; 5 | this.canvasWidth = undefined; 6 | this.canvasHeight = undefined; 7 | 8 | this.mRenderer = undefined; 9 | this.mScene = undefined; 10 | this.mCamera = undefined; 11 | 12 | this.uiStep = 0 >>> 0; // coerce to uint32 13 | this.uiTwo = 2 >>> 0; 14 | this.uiMax = 6 >>> 0; 15 | 16 | this.mTexture1 = undefined; 17 | this.mTexture2 = undefined; 18 | this.mScreenQuad = undefined; 19 | 20 | this.feedbackMaterial = undefined; 21 | this.screenMaterial = undefined; 22 | 23 | this.image = undefined; 24 | 25 | this.textureWidth = 2048; 26 | this.textureHeight = 1024; 27 | 28 | // Configuration. 29 | this.amount = config.amount; 30 | this.mix = config.mix; 31 | this.devs = config.devs; 32 | this.exps = config.exps; 33 | 34 | this.mUniforms = { 35 | screenWidth: {type: "f", value: undefined}, 36 | screenHeight: {type: "f", value: undefined}, 37 | sSource: {type: "t", value: undefined}, 38 | iSource: {type: "t", value: undefined}, 39 | step: {type: "i", value: this.uiStep}, 40 | amount: {type: "f", value: this.amount}, 41 | mix: {type: "f", value: this.mix}, 42 | devs: {type: "f", value: this.devs}, 43 | exps: {type: "f", value: this.exps} 44 | }; 45 | 46 | this.load = function() 47 | { 48 | this.image = THREE.ImageUtils.loadTexture('tetons.jpg', THREE.UVMapping, this.init.bind(this)) 49 | }; 50 | 51 | this.init = function() 52 | { 53 | this.mUniforms.iSource.value = this.image; 54 | this.initCanvas(); 55 | this.initGl(); 56 | this.render(); 57 | }; 58 | 59 | this.initCanvas = function() 60 | { 61 | this.canvasQ = $('#myCanvas'); 62 | this.canvas = this.canvasQ.get(0); 63 | 64 | window.addEventListener('resize', this.onResize.bind(this), false ); 65 | }; 66 | 67 | this.getMaterial = function(fragmentShaderId) 68 | { 69 | return new THREE.ShaderMaterial({ 70 | uniforms: this.mUniforms, 71 | vertexShader: document.getElementById('standardVertexShader').textContent, 72 | fragmentShader: document.getElementById(fragmentShaderId).textContent 73 | }); 74 | }; 75 | 76 | this.initGl = function() 77 | { 78 | this.mRenderer = new THREE.WebGLRenderer({canvas: this.canvas, preserveDrawingBuffer: true}); 79 | 80 | this.mScene = new THREE.Scene(); 81 | this.mCamera = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5, -1, 1); 82 | this.mCamera.position.z = 0; 83 | this.mScene.add(this.mCamera); 84 | 85 | this.feedbackMaterial = this.getMaterial('feedbackFragmentShader'); 86 | this.screenMaterial = this.getMaterial('screenFragmentShader'); 87 | 88 | var plane = new THREE.PlaneGeometry(1.0, 1.0); 89 | this.mScreenQuad = new THREE.Mesh(plane, this.screenMaterial); 90 | this.mScene.add(this.mScreenQuad); 91 | 92 | // Set the new shape of canvas. 93 | this.canvasQ.width(this.getCanvasWidth()); 94 | this.canvasQ.height(this.getCanvasHeight()); 95 | 96 | // Get the real size of canvas. 97 | this.canvasWidth = this.canvasQ.width(); 98 | this.canvasHeight = this.canvasQ.height(); 99 | 100 | this.mRenderer.setSize(this.canvasWidth, this.canvasHeight); 101 | 102 | this.mTexture1 = this.getWrappedRenderTarget(); 103 | this.mTexture2 = this.getWrappedRenderTarget(); 104 | 105 | this.mUniforms.screenWidth.value = this.textureWidth; 106 | this.mUniforms.screenHeight.value = this.textureHeight; 107 | 108 | }; 109 | 110 | this.getWrappedRenderTarget = function() 111 | { 112 | return new THREE.WebGLRenderTarget(this.textureWidth, this.textureHeight, { 113 | minFilter: THREE.NearestFilter, 114 | magFilter: THREE.NearestFilter, 115 | format: THREE.RGBFormat, 116 | type: THREE.FloatType, 117 | wrapS: THREE.MirroredRepeatWrapping, 118 | wrapT: THREE.MirroredRepeatWrapping 119 | }); 120 | }; 121 | 122 | this.updateUniforms = function() 123 | { 124 | this.mUniforms.amount.value = this.amount; 125 | this.mUniforms.devs.value = this.devs; 126 | this.mUniforms.exps.value = this.exps; 127 | this.mUniforms.mix.value = this.mix; 128 | }; 129 | 130 | this.renderToTarget = function(material, sSource, target) 131 | { 132 | this.mScreenQuad.material = material; 133 | this.mUniforms.sSource.value = sSource; 134 | this.mRenderer.render(this.mScene, this.mCamera, target, true); 135 | }; 136 | 137 | this.render = function() 138 | { 139 | if (this.uiStep < this.uiMax) { 140 | this.updateUniforms(); 141 | for (var i = 0; i < this.uiMax; ++i) { 142 | this.mUniforms.step.value = Math.min(this.uiStep, this.uiMax); 143 | var pStep = this.uiStep % this.uiTwo; 144 | 145 | if (pStep == 0) { 146 | this.renderToTarget(this.feedbackMaterial, this.mTexture1, this.mTexture2); 147 | } else if (pStep == 1) { 148 | this.renderToTarget(this.feedbackMaterial, this.mTexture2, this.mTexture1); 149 | } 150 | 151 | this.uiStep++; 152 | } 153 | 154 | this.mScreenQuad.material = this.screenMaterial; 155 | this.mRenderer.render(this.mScene, this.mCamera); 156 | } 157 | requestAnimationFrame(this.render.bind(this)); 158 | }; 159 | 160 | this.resetCounter = function() { 161 | this.uiStep = 0 >>> 0; 162 | }; 163 | 164 | this.snapshot = function() 165 | { 166 | var dataURL = this.canvas.toDataURL("image/jpeg"); 167 | window.open(dataURL, "name-"+Math.random()); 168 | }; 169 | 170 | this.debug = function() 171 | { 172 | var temp = this.debugScreenMaterial; 173 | this.debugScreenMaterial = this.screenMaterial; 174 | this.screenMaterial = temp; 175 | }; 176 | 177 | this.onResize = function() 178 | { 179 | 180 | // Set the new shape of canvas. 181 | this.canvasQ.width(this.getCanvasWidth()); 182 | this.canvasQ.height(this.getCanvasHeight()); 183 | 184 | // Get the real size of canvas. 185 | this.canvasWidth = this.canvasQ.width(); 186 | this.canvasHeight = this.canvasQ.height(); 187 | 188 | this.mRenderer.setSize(this.canvasWidth, this.canvasHeight); 189 | 190 | }; 191 | 192 | this.getCanvasWidth = function() 193 | { 194 | return window.innerWidth; 195 | }; 196 | 197 | this.getCanvasHeight = function() 198 | { 199 | return window.innerHeight; 200 | }; 201 | 202 | }; 203 | 204 | var swappableControllers = []; 205 | 206 | var swappableControllerUniforms = {}; 207 | 208 | var updateUI = function(shaderId, gui, paintFlow) { 209 | swappableControllers.forEach( function (controller) { 210 | gui.remove(controller); 211 | }); 212 | swappableControllers = []; 213 | var uniformsToSwap = swappableControllerUniforms[shaderId]; 214 | uniformsToSwap.forEach( function (params) { 215 | swappableControllers.push( 216 | gui.add(paintFlow, params.id) 217 | .min(params.min) 218 | .max(params.max) 219 | .step(params.step) 220 | .name(params.name) 221 | ); 222 | }); 223 | paintFlow.updateFluidShader(shaderId); 224 | }; 225 | 226 | window.onload = function() { 227 | var manifoldDenoise = new ManifoldDenoise({ 228 | amount: 10.0, 229 | mix: 1.0, 230 | exps: 1.0, 231 | devs: 1.5 232 | }); 233 | var gui = new dat.GUI(); 234 | 235 | gui.add(manifoldDenoise, 'mix').min(0.0).max(1.0).step(0.01).name("Mix").onChange(manifoldDenoise.resetCounter.bind(manifoldDenoise)); 236 | gui.add(manifoldDenoise, 'amount').min(0.0).max(20.0).step(0.01).name("Hardness").onChange(manifoldDenoise.resetCounter.bind(manifoldDenoise)); 237 | gui.add(manifoldDenoise, 'exps').min(0.0).max(2.0).step(0.01).name("Exponent").onChange(manifoldDenoise.resetCounter.bind(manifoldDenoise)); 238 | gui.add(manifoldDenoise, 'devs').min(0.5).max(3.0).step(0.01).name("Deviation").onChange(manifoldDenoise.resetCounter.bind(manifoldDenoise)); 239 | 240 | manifoldDenoise.load(); 241 | }; -------------------------------------------------------------------------------- /softmaxdenoise/tetons.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/softmaxdenoise/tetons.jpg -------------------------------------------------------------------------------- /softmaxdenoise/tetons.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/softmaxdenoise/tetons.png -------------------------------------------------------------------------------- /softmaxdenoise/tetons2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/softmaxdenoise/tetons2.jpg -------------------------------------------------------------------------------- /softmaxdenoise/tetons2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/softmaxdenoise/tetons2.png -------------------------------------------------------------------------------- /softmaxdenoise/tetons3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/softmaxdenoise/tetons3.jpg -------------------------------------------------------------------------------- /softmaxdenoisecolor/frog.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/softmaxdenoisecolor/frog.jpg -------------------------------------------------------------------------------- /softmaxdenoisecolor/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Softmax Manifold Denoise 5 | 6 | 7 | 8 | 9 | 10 | 19 | 33 | 223 | 289 | 341 | 355 | 356 | 357 | 358 |
359 | 360 |
361 | 362 | 363 | -------------------------------------------------------------------------------- /softmaxdenoisecolor/softmax.css: -------------------------------------------------------------------------------- 1 | 2 | body { 3 | font-family:sans-serif; 4 | background:#333333; 5 | color:#777777; 6 | margin: 0 auto; 7 | } 8 | 9 | header, footer, aside, nav { 10 | display: block; 11 | } 12 | 13 | #myCanvas { 14 | display:block; 15 | vertical-align:bottom; 16 | background-color:#000000; 17 | } -------------------------------------------------------------------------------- /softmaxdenoisecolor/softmax.js: -------------------------------------------------------------------------------- 1 | var ManifoldDenoise = function(config){ 2 | 3 | this.canvas = undefined; 4 | this.canvasQ = undefined; 5 | this.canvasWidth = undefined; 6 | this.canvasHeight = undefined; 7 | 8 | this.mRenderer = undefined; 9 | this.mScene = undefined; 10 | this.mCamera = undefined; 11 | 12 | this.uiStep = 0 >>> 0; // coerce to uint32 13 | this.uiMax = 1 >>> 0; 14 | 15 | this.uiChannel = 0 >>> 0; 16 | 17 | this.time = new Date().getTime(); 18 | 19 | this.mTexture1 = undefined; 20 | this.mTexture2 = undefined; 21 | this.mTexture3 = undefined; 22 | this.mTexture4 = undefined; 23 | this.mTexture5 = undefined; 24 | this.mTexture6 = undefined; 25 | this.mTexture7 = undefined; 26 | this.mTexture8 = undefined; 27 | this.dummyTexture = undefined; 28 | this.mScreenQuad = undefined; 29 | 30 | this.feedbackMaterial = undefined; 31 | this.pathTracerMaterial = undefined; 32 | this.sliceMaterial = undefined; 33 | this.screenMaterial = undefined; 34 | this.accumulatorMaterial = undefined; 35 | 36 | this.image = undefined; 37 | 38 | this.textureWidth = 1024; 39 | this.textureHeight = 1024; 40 | 41 | // Configuration. 42 | this.amount = config.amount; 43 | this.mix = config.mix; 44 | this.exps = config.exps; 45 | this.detail = config.detail; 46 | this.arate = config.arate; 47 | 48 | this.mUniforms = { 49 | screenWidth: {type: "f", value: undefined}, 50 | screenHeight: {type: "f", value: undefined}, 51 | sSource: {type: "t", value: undefined}, 52 | sSource0: {type: "t", value: undefined}, 53 | sSource1: {type: "t", value: undefined}, 54 | sSource2: {type: "t", value: undefined}, 55 | iSource: {type: "t", value: undefined}, 56 | step: {type: "i", value: this.uiStep}, 57 | chan: {type: "i", value: this.uiChannel}, 58 | amount: {type: "f", value: this.amount}, 59 | mix: {type: "f", value: this.mix}, 60 | detail: {type: "f", value: this.detail}, 61 | exps: {type: "f", value: this.exps}, 62 | time: {type: "i", value: 0}, 63 | arate: {type: "f", value: this.arate} 64 | }; 65 | 66 | this.load = function() 67 | { 68 | // Collared Aracari -- Parque Nacional Darién, Panama -- 2008 February 69 | // https://commons.wikimedia.org/wiki/File:Pteroglossus-torquatus-001.jpg#/media/File:Pteroglossus-torquatus-001.jpg 70 | this.image = THREE.ImageUtils.loadTexture('toucan.jpg', THREE.UVMapping, this.init.bind(this)) 71 | }; 72 | 73 | this.init = function() 74 | { 75 | this.mUniforms.iSource.value = this.image; 76 | this.initCanvas(); 77 | this.initGl(); 78 | this.render(); 79 | }; 80 | 81 | this.initCanvas = function() 82 | { 83 | this.canvasQ = $('#myCanvas'); 84 | this.canvas = this.canvasQ.get(0); 85 | 86 | window.addEventListener('resize', this.onResize.bind(this), false ); 87 | }; 88 | 89 | this.getMaterial = function(fragmentShaderId) 90 | { 91 | return new THREE.ShaderMaterial({ 92 | uniforms: this.mUniforms, 93 | vertexShader: document.getElementById('standardVertexShader').textContent, 94 | fragmentShader: document.getElementById(fragmentShaderId).textContent 95 | }); 96 | }; 97 | 98 | this.initGl = function() 99 | { 100 | this.mRenderer = new THREE.WebGLRenderer({canvas: this.canvas, preserveDrawingBuffer: true}); 101 | 102 | this.mScene = new THREE.Scene(); 103 | this.mCamera = new THREE.OrthographicCamera(-0.5, 0.5, 0.5, -0.5, -1, 1); 104 | this.mCamera.position.z = 0; 105 | this.mScene.add(this.mCamera); 106 | 107 | this.feedbackMaterial = this.getMaterial('feedbackFragmentShader'); 108 | this.pathTracerMaterial = this.getMaterial('pathTracerFragmentShader'); 109 | this.sliceMaterial = this.getMaterial('sliceFragmentShader'); 110 | this.screenMaterial = this.getMaterial('screenFragmentShader'); 111 | this.accumulatorMaterial = this.getMaterial('accumulatorFragmentShader'); 112 | 113 | var plane = new THREE.PlaneGeometry(1.0, 1.0); 114 | this.mScreenQuad = new THREE.Mesh(plane, this.screenMaterial); 115 | this.mScene.add(this.mScreenQuad); 116 | 117 | // Set the new shape of canvas. 118 | this.canvasQ.width(this.getCanvasWidth()); 119 | this.canvasQ.height(this.getCanvasHeight()); 120 | 121 | // Get the real size of canvas. 122 | this.canvasWidth = this.canvasQ.width(); 123 | this.canvasHeight = this.canvasQ.height(); 124 | 125 | this.mRenderer.setSize(this.canvasWidth, this.canvasHeight); 126 | 127 | this.mTexture1 = this.getWrappedRenderTarget(); 128 | this.mTexture2 = this.getWrappedRenderTarget(); 129 | this.mTexture3 = this.getWrappedRenderTarget(); 130 | this.mTexture4 = this.getWrappedRenderTarget(); 131 | this.mTexture5 = this.getWrappedRenderTarget(); 132 | this.mTexture6 = this.getWrappedRenderTarget(); 133 | this.mTexture7 = this.getWrappedRenderTarget(); 134 | this.mTexture8 = this.getWrappedRenderTarget(); 135 | this.mTexture9 = this.getWrappedRenderTarget(); 136 | this.dummyTexture = this.getWrappedRenderTarget(); 137 | 138 | this.mUniforms.screenWidth.value = this.textureWidth; 139 | this.mUniforms.screenHeight.value = this.textureHeight; 140 | 141 | }; 142 | 143 | this.getWrappedRenderTarget = function() 144 | { 145 | return new THREE.WebGLRenderTarget(this.textureWidth, this.textureHeight, { 146 | minFilter: THREE.NearestFilter, 147 | magFilter: THREE.NearestFilter, 148 | format: THREE.RGBFormat, 149 | type: THREE.FloatType, 150 | wrapS: THREE.MirroredRepeatWrapping, 151 | wrapT: THREE.MirroredRepeatWrapping 152 | }); 153 | }; 154 | 155 | this.updateUniforms = function() 156 | { 157 | this.mUniforms.arate.value = this.arate; 158 | this.mUniforms.amount.value = this.amount; 159 | this.mUniforms.exps.value = this.exps; 160 | this.mUniforms.mix.value = this.mix; 161 | this.mUniforms.time.value = new Date().getTime() - this.time; 162 | }; 163 | 164 | this.renderToTarget = function(material, iSource, sSource, target) 165 | { 166 | this.mScreenQuad.material = material; 167 | this.mUniforms.iSource.value = iSource; 168 | this.mUniforms.sSource.value = sSource; 169 | this.mRenderer.render(this.mScene, this.mCamera, target, true); 170 | }; 171 | 172 | this.sliceToTarget = function(iSource, sSource0, sSource1, sSource2, target) 173 | { 174 | this.mScreenQuad.material = this.sliceMaterial; 175 | this.mUniforms.iSource.value = iSource; 176 | this.mUniforms.sSource0.value = sSource0; 177 | this.mUniforms.sSource1.value = sSource1; 178 | this.mUniforms.sSource2.value = sSource2; 179 | this.mRenderer.render(this.mScene, this.mCamera, target, true); 180 | }; 181 | 182 | this.render = function() 183 | { 184 | var imageTexture; 185 | this.updateUniforms(); 186 | 187 | this.renderToTarget(this.pathTracerMaterial, this.dummyTexture, this.dummyTexture, this.mTexture1); 188 | 189 | if (this.uiStep % 2 == 0) { 190 | this.renderToTarget(this.accumulatorMaterial, this.mTexture8, this.mTexture1, this.mTexture9); 191 | imageTexture = this.mTexture9; 192 | } else { 193 | this.renderToTarget(this.accumulatorMaterial, this.mTexture9, this.mTexture1, this.mTexture8); 194 | imageTexture = this.mTexture8; 195 | } 196 | 197 | this.mUniforms.step.value = 0; 198 | 199 | this.mUniforms.chan.value = 0; 200 | this.renderToTarget(this.feedbackMaterial, imageTexture, this.dummyTexture, this.mTexture2); 201 | this.mUniforms.chan.value = 1; 202 | this.renderToTarget(this.feedbackMaterial, imageTexture, this.dummyTexture, this.mTexture3); 203 | this.mUniforms.chan.value = 2; 204 | this.renderToTarget(this.feedbackMaterial, imageTexture, this.dummyTexture, this.mTexture4); 205 | 206 | this.mUniforms.step.value = 1; 207 | 208 | this.renderToTarget(this.feedbackMaterial, imageTexture, this.mTexture2, this.mTexture5); 209 | this.renderToTarget(this.feedbackMaterial, imageTexture, this.mTexture3, this.mTexture6); 210 | this.renderToTarget(this.feedbackMaterial, imageTexture, this.mTexture4, this.mTexture7); 211 | 212 | this.sliceToTarget(imageTexture, this.mTexture5, this.mTexture6, this.mTexture7, this.mTexture2); 213 | 214 | this.mUniforms.detail.value = this.detail; 215 | this.mUniforms.iSource.value = imageTexture; 216 | this.mUniforms.sSource.value = this.mTexture2; 217 | this.mScreenQuad.material = this.screenMaterial; 218 | this.mRenderer.render(this.mScene, this.mCamera); 219 | 220 | this.uiStep++; 221 | requestAnimationFrame(this.render.bind(this)); 222 | }; 223 | 224 | this.resetCounter = function() { 225 | this.uiStep = 0 >>> 0; 226 | }; 227 | 228 | this.snapshot = function() 229 | { 230 | var dataURL = this.canvas.toDataURL("image/jpeg"); 231 | window.open(dataURL, "name-"+Math.random()); 232 | }; 233 | 234 | this.debug = function() 235 | { 236 | var temp = this.debugScreenMaterial; 237 | this.debugScreenMaterial = this.screenMaterial; 238 | this.screenMaterial = temp; 239 | }; 240 | 241 | this.onResize = function() 242 | { 243 | 244 | // Set the new shape of canvas. 245 | this.canvasQ.width(this.getCanvasWidth()); 246 | this.canvasQ.height(this.getCanvasHeight()); 247 | 248 | // Get the real size of canvas. 249 | this.canvasWidth = this.canvasQ.width(); 250 | this.canvasHeight = this.canvasQ.height(); 251 | 252 | this.mRenderer.setSize(this.canvasWidth, this.canvasHeight); 253 | 254 | }; 255 | 256 | this.getCanvasWidth = function() 257 | { 258 | return window.innerWidth; 259 | }; 260 | 261 | this.getCanvasHeight = function() 262 | { 263 | return window.innerHeight; 264 | }; 265 | 266 | }; 267 | 268 | var swappableControllers = []; 269 | 270 | var swappableControllerUniforms = {}; 271 | 272 | var updateUI = function(shaderId, gui, paintFlow) { 273 | swappableControllers.forEach( function (controller) { 274 | gui.remove(controller); 275 | }); 276 | swappableControllers = []; 277 | var uniformsToSwap = swappableControllerUniforms[shaderId]; 278 | uniformsToSwap.forEach( function (params) { 279 | swappableControllers.push( 280 | gui.add(paintFlow, params.id) 281 | .min(params.min) 282 | .max(params.max) 283 | .step(params.step) 284 | .name(params.name) 285 | ); 286 | }); 287 | paintFlow.updateFluidShader(shaderId); 288 | }; 289 | 290 | window.onload = function() { 291 | var manifoldDenoise = new ManifoldDenoise({ 292 | amount: 10.0, 293 | mix: 1.0, 294 | exps: 15.0, 295 | detail: 0.0, 296 | arate: 0.05 297 | }); 298 | var gui = new dat.GUI(); 299 | 300 | gui.add(manifoldDenoise, 'mix').min(0.0).max(1.0).step(0.01).name("Mix"); 301 | gui.add(manifoldDenoise, 'amount').min(0.0).max(50.0).step(0.01).name("Hardness"); 302 | gui.add(manifoldDenoise, 'exps').min(0.0).max(20.0).step(0.01).name("Exponent"); 303 | gui.add(manifoldDenoise, 'arate').min(0.0).max(0.2).step(0.001).name("Accumulator Rate"); 304 | gui.add(manifoldDenoise, 'detail').min(0.0).max(10.0).step(0.01).name("Enhance Detail"); 305 | 306 | manifoldDenoise.load(); 307 | }; -------------------------------------------------------------------------------- /softmaxdenoisecolor/toucan.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CornuAmmonis/jsexp/24ecb3d621c47a8abfb01828775703674eaf9250/softmaxdenoisecolor/toucan.jpg -------------------------------------------------------------------------------- /waveletsharpen/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Wavelet Sharpen 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 23 | 141 | 142 | 143 | 149 | 150 | 151 |
152 |

Wavelet Sharpen

153 |
154 |
155 | 156 | 174 |
175 | 182 | 183 |
184 |

This simulation requires the GL extensions framebuffer_object and texture_float. 185 | If you cannot see the simulation your system probably lacks at least one of these extensions.

186 | 187 |

In Google Chrome, you can see the available GL extensions going to chrome://gpu.

188 |
189 | 190 | 191 | -------------------------------------------------------------------------------- /waveletsharpen/sharpen.js: -------------------------------------------------------------------------------- 1 | var init, load, loadPreset; 2 | 3 | /* State table 4 | hpass: 0 1 2 1 2 d d 5 | lpass: 1 2 1 2 1 1 d 6 | level: 0 1 2 3 4 d d 7 | state: 2 2 2 2 2 1 0 8 | */ 9 | 10 | var maxStep = 10; 11 | var hpass_arr = [0, 1, 2, 1, 2, 1, 2, 1, 1, 1]; 12 | var lpass_arr = [1, 2, 1, 2, 1, 2, 1, 2, 2, 2]; 13 | var level_arr = [0, 1, 2, 3, 4, 5, 6, 7, 0, 0]; 14 | var state_arr = [0, 1, 1, 1, 1, 1, 1, 1, 2, 3]; 15 | 16 | (function(){ 17 | 18 | // Canvas. 19 | var canvas; 20 | var canvasQ; 21 | var canvasWidth; 22 | var canvasHeight; 23 | 24 | var mRenderer; 25 | var mScene; 26 | var mCamera; 27 | var mUniforms; 28 | var mStep = 0 >>> 0; // coerce to uint32 29 | 30 | var mTexture1, mTexture2, iSource; 31 | var mScreenQuad; 32 | 33 | var presets = [ 34 | { // Default 35 | amount: 1.0, 36 | radius: 3.0 37 | } 38 | ]; 39 | 40 | // Configuration. 41 | var amount = presets[0].amount; 42 | var radius = presets[0].radius; 43 | 44 | load = function() 45 | { 46 | // https://commons.wikimedia.org/wiki/File:Adams_The_Tetons_and_the_Snake_River.jpg 47 | iSource = THREE.ImageUtils.loadTexture('tetons.jpg', THREE.UVMapping, function() { 48 | init(); 49 | }) 50 | }; 51 | 52 | init = function() 53 | { 54 | init_canvas(); 55 | init_controls(); 56 | init_uniforms(); 57 | init_image(iSource); 58 | init_gl(canvas.clientWidth, canvas.clientHeight); 59 | init_presets(); 60 | 61 | }; 62 | 63 | var init_canvas = function() 64 | { 65 | canvasQ = $('#myCanvas'); 66 | canvas = canvasQ.get(0); 67 | }; 68 | 69 | var init_uniforms = function() 70 | { 71 | mUniforms = { 72 | screenWidth: {type: "f", value: undefined}, 73 | screenHeight: {type: "f", value: undefined}, 74 | sSource: {type: "t", value: undefined}, 75 | iSource: {type: "t", value: undefined}, 76 | amount: {type: "f", value: amount}, 77 | radius: {type: "f", value: radius}, 78 | hpass: {type: "i", value: undefined}, 79 | lpass: {type: "i", value: undefined}, 80 | level: {type: "i", value: undefined}, 81 | state: {type: "i", value: undefined} 82 | }; 83 | }; 84 | 85 | var init_gl = function(width, height) 86 | { 87 | mRenderer = new THREE.WebGLRenderer({canvas: canvas, preserveDrawingBuffer: true}); 88 | mScene = new THREE.Scene(); 89 | var ws = 0.5; 90 | mCamera = new THREE.OrthographicCamera(-ws, ws, ws, -ws, -10000, 10000); 91 | mCamera.position.z = 100; 92 | mScene.add(mCamera); 93 | 94 | var mWaveletSharpenMaterial = new THREE.ShaderMaterial({ 95 | uniforms: mUniforms, 96 | vertexShader: document.getElementById('standardVertexShader').textContent, 97 | fragmentShader: document.getElementById('waveletSharpenFragmentShader').textContent 98 | }); 99 | 100 | mScreenQuad = new THREE.Mesh( 101 | new THREE.PlaneGeometry(1.0, 1.0), 102 | mWaveletSharpenMaterial 103 | ); 104 | 105 | mScene.add(mScreenQuad); 106 | 107 | resize(width, height); 108 | 109 | render(); 110 | requestAnimationFrame(render); 111 | }; 112 | 113 | var init_presets = function() 114 | { 115 | document.ex.scene.value = 0; 116 | }; 117 | 118 | var init_image = function(iSource) 119 | { 120 | iSource.wrapS = THREE.MirroredRepeatWrapping; 121 | iSource.wrapT = THREE.MirroredRepeatWrapping; 122 | iSource.needsUpdate = true; 123 | mUniforms.iSource.value = iSource; 124 | }; 125 | 126 | var getMirrorWrappedRenderTarget = function(width, height) 127 | { 128 | var tgt = new THREE.WebGLRenderTarget(width, height, { 129 | minFilter: THREE.LinearFilter, 130 | magFilter: THREE.LinearFilter, 131 | format: THREE.RGBFormat, 132 | type: THREE.FloatType}); 133 | 134 | tgt.wrapS = THREE.MirroredRepeatWrapping; 135 | tgt.wrapT = THREE.MirroredRepeatWrapping; 136 | return tgt; 137 | }; 138 | 139 | var resize = function(width, height) 140 | { 141 | // Set the new shape of canvas. 142 | canvasQ.width(width); 143 | canvasQ.height(height); 144 | 145 | // Get the real size of canvas. 146 | canvasWidth = canvasQ.width(); 147 | canvasHeight = canvasQ.height(); 148 | 149 | mRenderer.setSize(canvasWidth, canvasHeight); 150 | 151 | var tgtWidth = canvasWidth; 152 | var tgtHeight = canvasHeight; 153 | mTexture1 = getMirrorWrappedRenderTarget(tgtWidth, tgtHeight); 154 | mTexture2 = getMirrorWrappedRenderTarget(tgtWidth, tgtHeight); 155 | 156 | mUniforms.screenWidth.value = tgtWidth; 157 | mUniforms.screenHeight.value = tgtHeight; 158 | }; 159 | 160 | var updateUniforms = function(step) 161 | { 162 | var pass = Math.min(step, maxStep - 1); 163 | mUniforms.hpass.value = hpass_arr[pass]; 164 | mUniforms.lpass.value = lpass_arr[pass]; 165 | mUniforms.level.value = level_arr[pass]; 166 | mUniforms.state.value = state_arr[pass]; 167 | if (step < maxStep) { 168 | console.log(pass + " " 169 | + hpass_arr[pass] + " " 170 | + lpass_arr[pass] + " " 171 | + level_arr[pass] + " " 172 | + state_arr[pass] ); 173 | } 174 | }; 175 | 176 | var render = function() 177 | { 178 | mUniforms.radius.value = radius; 179 | mUniforms.amount.value = amount; 180 | 181 | for(var i=0; i 2 | 3 | 4 | Wavelet Sharpen 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 22 | 44 | 73 | 214 | 215 | 216 | 222 | 223 | 224 |
225 |

Wavelet Sharpen

226 |
227 |
228 | 229 | 256 |
257 | 265 | 266 |
267 |

This simulation requires the WebGL extensions framebuffer_object, texture_float, and draw_buffers. 268 | If you cannot see the simulation your system probably lacks at least one of these extensions.

269 | 270 |

In Google Chrome, you can see the available GL extensions going to chrome://gpu.

271 |
272 | 273 | 274 | -------------------------------------------------------------------------------- /waveletsharpencolor/sharpen.js: -------------------------------------------------------------------------------- 1 | var init; 2 | 3 | var mWaveletSharpenMaterial, mXformInputMaterial, mXformOutputMaterial; 4 | 5 | var enableLogging = false; 6 | 7 | var maxStep = 10; 8 | 9 | var hpass_arr = [0, 1, 2, 1, 2, 1, 2, 1, 1, 1]; 10 | var lpass_arr = [1, 2, 1, 2, 1, 2, 1, 2, 2, 2]; 11 | var level_arr = [1, 2, 3, 4, 5, 6, 7, 8, 0, 0]; 12 | var state_arr = [0, 1, 1, 1, 1, 1, 1, 1, 2, 3]; 13 | 14 | (function(){ 15 | 16 | // Canvas. 17 | var canvas; 18 | var canvasQ; 19 | var canvasWidth; 20 | var canvasHeight; 21 | 22 | var mRenderer; 23 | var mScene; 24 | var mCamera; 25 | var mUniforms; 26 | var mStep = 0 >>> 0; // coerce to uint32 27 | var lumaOnly = 0 >>> 0; 28 | 29 | var mTexture0a, mTexture0b, mTexture1a, mTexture1b, mTexture2a, mTexture2b, iSource, iSourcePre; 30 | var mScreenQuad; 31 | 32 | var presets = [ 33 | { // Default 34 | amount: 1.0, 35 | radius: 3.0 36 | } 37 | ]; 38 | 39 | // Configuration. 40 | var amount = presets[0].amount; 41 | var radius = presets[0].radius; 42 | 43 | load = function() 44 | { 45 | iSourcePre = THREE.ImageUtils.loadTexture('frog.jpg', THREE.UVMapping, function() { 46 | init(); 47 | }) 48 | }; 49 | 50 | var init = function() 51 | { 52 | init_canvas(); 53 | init_controls(); 54 | init_uniforms(); 55 | init_gl(canvas.clientWidth, canvas.clientHeight); 56 | 57 | }; 58 | 59 | var init_canvas = function() 60 | { 61 | canvasQ = $('#myCanvas'); 62 | canvas = canvasQ.get(0); 63 | }; 64 | 65 | var init_uniforms = function() 66 | { 67 | mUniforms = { 68 | screenWidth: {type: "f", value: undefined}, 69 | screenHeight: {type: "f", value: undefined}, 70 | sSource0: {type: "t", value: undefined}, 71 | sSource1: {type: "t", value: undefined}, 72 | sSource2: {type: "t", value: undefined}, 73 | iSource: {type: "t", value: undefined}, 74 | amount: {type: "f", value: amount}, 75 | radius: {type: "f", value: radius}, 76 | hpass: {type: "i", value: undefined}, 77 | lpass: {type: "i", value: undefined}, 78 | level: {type: "i", value: undefined}, 79 | state: {type: "i", value: undefined}, 80 | lumaOnly: {type: "i", value: 0} 81 | }; 82 | }; 83 | 84 | var init_gl = function(width, height) 85 | { 86 | mRenderer = new THREE.WebGLRenderer({canvas: canvas, preserveDrawingBuffer: true}); 87 | mScene = new THREE.Scene(); 88 | var ws = 0.5; 89 | mCamera = new THREE.OrthographicCamera(-ws, ws, ws, -ws, -10000, 10000); 90 | mCamera.position.z = 100; 91 | mScene.add(mCamera); 92 | 93 | mWaveletSharpenMaterial = new THREE.ShaderMaterial({ 94 | uniforms: mUniforms, 95 | vertexShader: document.getElementById('standardVertexShader').textContent, 96 | fragmentShader: document.getElementById('waveletSharpenFragmentShader').textContent 97 | }); 98 | 99 | mXformInputMaterial = new THREE.ShaderMaterial({ 100 | uniforms: mUniforms, 101 | vertexShader: document.getElementById('standardVertexShader').textContent, 102 | fragmentShader: document.getElementById('colorSpaceXformInputFragmentShader').textContent 103 | }); 104 | 105 | mXformOutputMaterial = new THREE.ShaderMaterial({ 106 | uniforms: mUniforms, 107 | vertexShader: document.getElementById('standardVertexShader').textContent, 108 | fragmentShader: document.getElementById('colorSpaceXformOutputFragmentShader').textContent 109 | }); 110 | 111 | mScreenQuad = new THREE.Mesh( 112 | new THREE.PlaneGeometry(1.0, 1.0), 113 | mWaveletSharpenMaterial 114 | ); 115 | 116 | mScene.add(mScreenQuad); 117 | 118 | resize(width, height); 119 | 120 | initRender(); 121 | }; 122 | 123 | var getMirrorWrappedRenderTarget = function(width, height, attachmentNumber) 124 | { 125 | var tgt = new THREE.WebGLRenderTarget(width, height, { 126 | minFilter: THREE.LinearFilter, 127 | magFilter: THREE.LinearFilter, 128 | format: THREE.RGBFormat, 129 | type: THREE.FloatType}); 130 | 131 | tgt.wrapS = THREE.MirroredRepeatWrapping; 132 | tgt.wrapT = THREE.MirroredRepeatWrapping; 133 | tgt.attachmentNumber = attachmentNumber; 134 | return tgt; 135 | }; 136 | 137 | var resize = function(width, height) 138 | { 139 | // Set the new shape of canvas. 140 | canvasQ.width(width); 141 | canvasQ.height(height); 142 | 143 | // Get the real size of canvas. 144 | canvasWidth = canvasQ.width(); 145 | canvasHeight = canvasQ.height(); 146 | 147 | mRenderer.setSize(canvasWidth, canvasHeight); 148 | 149 | var tgtWidth = canvasWidth; 150 | var tgtHeight = canvasHeight; 151 | 152 | iSourcePre.needsUpdate = true; 153 | iSource = getMirrorWrappedRenderTarget(width, height, null); 154 | mTexture0a = getMirrorWrappedRenderTarget(tgtWidth, tgtHeight, 0); 155 | mTexture0b = getMirrorWrappedRenderTarget(tgtWidth, tgtHeight, 0); 156 | mTexture1a = getMirrorWrappedRenderTarget(tgtWidth, tgtHeight, 1); 157 | mTexture1b = getMirrorWrappedRenderTarget(tgtWidth, tgtHeight, 1); 158 | mTexture2a = getMirrorWrappedRenderTarget(tgtWidth, tgtHeight, 2); 159 | mTexture2b = getMirrorWrappedRenderTarget(tgtWidth, tgtHeight, 2); 160 | 161 | mUniforms.screenWidth.value = tgtWidth; 162 | mUniforms.screenHeight.value = tgtHeight; 163 | }; 164 | 165 | var updateUniforms = function(step) 166 | { 167 | var pass = Math.min(step, maxStep - 1); 168 | mUniforms.radius.value = radius; 169 | mUniforms.amount.value = amount; 170 | mUniforms.lumaOnly.value = lumaOnly; 171 | mUniforms.hpass.value = hpass_arr[pass]; 172 | mUniforms.lpass.value = lpass_arr[pass]; 173 | mUniforms.level.value = level_arr[pass]; 174 | mUniforms.state.value = state_arr[pass]; 175 | if (enableLogging && step < maxStep) { 176 | console.log(pass + " " 177 | + hpass_arr[pass] + " " 178 | + lpass_arr[pass] + " " 179 | + level_arr[pass] + " " 180 | + state_arr[pass] ); 181 | } 182 | }; 183 | 184 | var colorSpaceTransformRender = function() 185 | { 186 | mScreenQuad.material = mXformInputMaterial; 187 | mUniforms.iSource.value = iSourcePre; 188 | mRenderer.render(mScene, mCamera, iSource, true); 189 | mUniforms.iSource.value = iSource; 190 | }; 191 | 192 | /* 193 | On the first two calls to drawBuffersWEBGL it fails with the error: 194 | WebGL: INVALID_VALUE: drawBuffersWEBGL: more than one buffer 195 | So we run the two initial passes here as a workaround. 196 | */ 197 | var initRender = function() 198 | { 199 | colorSpaceTransformRender(); 200 | 201 | mScreenQuad.material = mWaveletSharpenMaterial; 202 | 203 | updateUniforms(0); 204 | 205 | mUniforms.sSource0.value = mTexture0a; 206 | mUniforms.sSource1.value = mTexture1a; 207 | mUniforms.sSource2.value = mTexture2a; 208 | mRenderer.render(mScene, mCamera, [mTexture0b, mTexture1b, mTexture2b], true); 209 | 210 | mUniforms.sSource0.value = mTexture0b; 211 | mUniforms.sSource1.value = mTexture1b; 212 | mUniforms.sSource2.value = mTexture2b; 213 | mRenderer.render(mScene, mCamera, [mTexture0a, mTexture1a, mTexture2a], true); 214 | 215 | mScreenQuad.material = mXformOutputMaterial; 216 | mRenderer.render(mScene, mCamera); 217 | 218 | requestAnimationFrame(render); 219 | }; 220 | 221 | var render = function() 222 | { 223 | mScreenQuad.material = mWaveletSharpenMaterial; 224 | 225 | if (mStep < maxStep) { 226 | updateUniforms(mStep); 227 | 228 | if (mStep % 2 == 0) { 229 | mUniforms.sSource0.value = mTexture0a; 230 | mUniforms.sSource1.value = mTexture1a; 231 | mUniforms.sSource2.value = mTexture2a; 232 | mRenderer.render(mScene, mCamera, [mTexture0b, mTexture1b, mTexture2b], true); 233 | } else if (mStep % 2 == 1) { 234 | mUniforms.sSource0.value = mTexture0b; 235 | mUniforms.sSource1.value = mTexture1b; 236 | mUniforms.sSource2.value = mTexture2b; 237 | mRenderer.render(mScene, mCamera, [mTexture0a, mTexture1a, mTexture2a], true); 238 | } 239 | 240 | mStep++; 241 | 242 | } else { 243 | 244 | mScreenQuad.material = mXformOutputMaterial; 245 | mRenderer.render(mScene, mCamera); 246 | 247 | } 248 | 249 | requestAnimationFrame(render); 250 | }; 251 | 252 | var loadPreset = function(idx) 253 | { 254 | amount = presets[idx].amount; 255 | radius = presets[idx].radius; 256 | worldToForm(); 257 | }; 258 | 259 | var worldToForm = function() 260 | { 261 | $("#sld_amount").slider("value", amount); 262 | $("#sld_radius").slider("value", radius); 263 | }; 264 | 265 | var init_controls = function() 266 | { 267 | $("#sld_radius").slider({ 268 | value: radius, min: 0.0, max:8.0, step:0.01, 269 | change: function(event, ui) {$("#radius").html(ui.value); radius = ui.value; mStep = 0;}, 270 | slide: function(event, ui) {$("#radius").html(ui.value); radius = ui.value; mStep = 0;} 271 | }); 272 | $("#sld_radius").slider("value", radius); 273 | 274 | $("#sld_amount").slider({ 275 | value: amount, min: 0.0, max:10.0, step:0.01, 276 | change: function(event, ui) {$("#amount").html(ui.value); amount = ui.value; mStep = 0;}, 277 | slide: function(event, ui) {$("#amount").html(ui.value); amount = ui.value; mStep = 0;} 278 | }); 279 | $("#sld_amount").slider("value", amount); 280 | 281 | $('#but_luma').buttonset(); 282 | $('#but_luma input[type=radio]').change(function() { 283 | lumaOnly = this.value; 284 | mStep = 0; 285 | }); 286 | 287 | $("#notworking").click(function(){ 288 | $("#requirement_dialog").dialog("open"); 289 | }); 290 | 291 | $("#requirement_dialog").dialog({ 292 | autoOpen: false 293 | }); 294 | }; 295 | 296 | })(); 297 | --------------------------------------------------------------------------------