diff options
| author | jules <jules@okfoc.us> | 2013-12-29 22:57:30 -0500 |
|---|---|---|
| committer | jules <jules@okfoc.us> | 2013-12-29 22:57:30 -0500 |
| commit | e1b9ea1a6e20a5d3a1c9bc78e459dfbfdb4b1f9e (patch) | |
| tree | 941eb6168480abe74318e3d9c7ac5eb1f2eff9d2 /shader-picker.html | |
| parent | 8829a743db3ec88182f3034d077971ba5c2a5cbf (diff) | |
shader picker
Diffstat (limited to 'shader-picker.html')
| -rw-r--r-- | shader-picker.html | 464 |
1 files changed, 464 insertions, 0 deletions
diff --git a/shader-picker.html b/shader-picker.html new file mode 100644 index 0000000..a6d1e12 --- /dev/null +++ b/shader-picker.html @@ -0,0 +1,464 @@ +<!doctype html> +<html> +<head> +<title>Shader</title> +<style type="text/css"> +html,body { margin: 0; padding: 0; } +#url { width: 450px; } +#width,#height,#framecount,#framedelay,#frameinterval,#background { width: 30px; } +#shader { width: 100%; height: 247px; font-family: fixed; } +#controls { width: 450px; } +#frames { width: 435px; min-height: 100px; border: 1px solid #ddd; line-height: 0; } +#frames div { margin: 1px; padding: 0; position: relative; border: 1px solid #eee; cursor: -webkit-grab; } +.dragging { cursor: -webkit-grabbing !important; } +.ui-sortable-helper { cursor: -webkit-grabbing !important; } +#frames canvas { display: block } +#frames .remove { position: absolute; top: 5px; right: 5px; color: #f00; padding: 3px; border: 0;background: white; font-size: 10px; line-height: 10px; } +.paused { background: black; color: white; border-width: 1px; padding: 1px 3px 2px 4px; } +.paused { outline: 0 !important; } +div { display: inline-block; padding: 10px;} +#gallery,#controls,#workspace,#rendered{ float: left; } +#rendered img { min-width: 500px; display: block; } +#render,#save { font-weight: bold; } +#render { float: right; } +#instructions { position: absolute;top:20px;right:20px; width:190px;height:465px; box-shadow:5px 5px 10px rgba(0,0,0,0.3); background:rgba(255,255,255,0.8); display: none; cursor: -webkit-grab; } +#instructions iframe {width: 100%;height:100%;margin:0;padding:0;border:0;} +#instructions.dragging iframe { pointer-events: none; } +#instructions .close { position: absolute; top: 5px; right: 5px; color: #f00; padding: 3px; border: 0;background: white; font-size: 10px; line-height: 10px; } +.close,.remove { cursor: pointer; } +#uploaded-url { display: none; width: 300px; } +form { display: inline-block; } +#gallery-images img { max-width: 200px; height: 90px; margin: 5px; } +#gallery { clear: right; width:100%;} +</style> +</head> +<body> + +<div id="gallery"> + <form id="gallery-search"> + <input type="text" id="dumpfm-search-query" value="duck bill"> + <button id="gallery-search">DUMP SEARCH</button> + </form> + <button id="gallery-random">IM RANDOM</button> + <span id="status"></span> + <div id="gallery-images"></div> +</div> + +<div id="controls"> + + <input type="text" id="url" value="img/1376516658960-dumpfm-DoritoWitch-TimeFLyTrans0001.png"> + <br> + <br> + + <textarea id="shader"></textarea> + <br> + <br> + + frames <input type="text" id="framecount" value="1"> + interval <input type="text" id="frameinterval" value="0.1s"> + <button id="add-frame">+add frame</button> + <button id="remove-all-frames">clear</button> + <button id="render" disabled>render</button> + <br> + + <div id="frames"></div> + <br> + <br> + + gif delay <input type="text" id="framedelay" value="0.1s"> + background <input type="text" id="background" value="#fff"> + <br> + <br> + <button id="help">help</button> + <button id="demo">demo</button> + <button id="dither-demo">dither</button> + <br> +</div> + +<div id="workspace"></div> + +<div id="rendered"> + <button id="reset">reset</button> + <button id="pause">pause</button> + <button id="step-forward">>></button> + <span id="status"></span> + <button id="save" disabled>save</button> + <button id="upload" disabled>upload</button> + <br> + <input type="text" id="uploaded-url"> +</div> + +<div id="instructions"><iframe src="instructions.html"></iframe><button class="close">x</button></div> +</body> +<script type="text/javascript" src="js/vendor/gif-encode/util.js"></script> +<script type="text/javascript" src="js/vendor/gif-encode/tube.js"></script> +<script type="text/javascript" src="js/vendor/gif-encode/client.js"></script> +<script type="text/javascript" src="js/vendor/gif.js"></script> +<script type="text/javascript" src="js/vendor/FileSaver/FileSaver.js"></script> +<script type="text/javascript" src="js/vendor/dataUriToBlob.js"></script> +<script type="text/javascript" src="js/vendor/jquery/jquery.min.js"></script> +<script type="text/javascript" src="js/vendor/jquery-ui-1.10.3.custom.min.js"></script> +<script type="text/javascript" src="js/vendor/canvasquery.js"></script> +<script type="text/javascript" src="js/canvasquery.dither.js"></script> +<script type="text/javascript" src="js/asdf.js"></script> +<script type="text/javascript" src="js/image.js"></script> +<script type="text/javascript" src="js/gallery.js"></script> +<script type="text/javascript" src="js/color.js"></script> +<script type="text/javascript" src="js/image.js"></script> +<script type="text/javascript" src="js/util.js"></script> +<script type="text/javascript"> + +var cc = cq(0,0).appendTo("#workspace") +var w, h +var lastGif + +$(init) + +var mousex, mousey + +function init(){ + $("#url").change(load) + $("#reset").click(reset) + $("#pause").click(pause) + $("#step-forward").click(step_forward) + $("#add-frame").click(add_frame) + $("#demo").click(function(){ demo("#first") }) + $("#dither-demo").click(function(){ demo("#second") }) + $("#frames").sortable({ + start: drag_start, + stop: drag_stop + }); + $(document).on("mousemove", function(e) { + mousex = event.pageX + mousey = event.pageY + }) + $(document).on("click","#frames .remove",remove_frame) + $("#framecount").change(function(){ + var val = $(this).int() + if (val < 1 || isNaN(val)) $(this).val(val = 1) + if (val == 1) $("#add-frame").html("+add frame") + else $("#add-frame").html("+add frames") + }) + $("#background").change(function(){ + document.body.style.backgroundColor = $("#background").string() + }) + $("#frames").disableSelection(); + $("#remove-all-frames").click(remove_all_frames) + $("#render").click(render) + $("#save").click(save) + $("#upload").click(upload) + $("#help,#instructions .close").click(function(){ $("#instructions").toggle() }) + $("#instructions").draggable({ + start: drag_start, + stop: drag_stop + }) + $("#instructions").disableSelection(); + + demo('#first') + load() + $(window).on("scroll", function(){ scrolling = true }) + + gallery.choose = choose + gallery.init() + console.log("gallery init") + + requestAnimationFrame(animate) +} +function choose (){ + imageURL = this.src + loading = true + $("#url").val(imageURL) + loadImage(imageURL, ready) +} + +function drag_start(){ dragging = true; $(this).addClass("dragging") } +function drag_stop(){ dragging = false; $(".dragging").removeClass("dragging") } +function demo(el){ + $el = $(el) + s = $el.html() + $("#shader").html(s) +} +function load(){ + loading = true + var imageURL = $("#url").val() + loadImage(imageURL, ready) +} + +function reset(){ + start_t = old_t + pause_t = 0 + $("#rendered img").remove() + draw(0) +} +function pause(state){ + $("#pause").toggleClass("paused", paused = typeof state == "boolean" ? state : ! paused).html(paused ? "paused" : "pause") +} +function step_forward(){ + var step = $("#framedelay").float() * 1000 || 100 + old_t += step + draw(old_t) +} +var timeout, raf_id, start_t = 0, old_t = 0, pause_t = 0 +var paused = false, dragging = false, rendering = false, scrolling = false; +var fps = 30; +function animate(t){ + raf_id = requestAnimationFrame(animate); + + var step_t = t - old_t + old_t = t + + if (paused || dragging || rendering || scrolling) { + pause_t += step_t + scrolling = false + return + } + + // var timing = +(new Date()) + draw(t) + // timing = +(new Date()) - timing + fps = avg(fps, 1000/step_t, 4) + status(~~(fps) + " fps") +} +function draw(t) { + t -= start_t + t -= pause_t + frame = giveFrame(t) + shade(frame, t) +} + +var frame, img_frame; +function giveFrame(t){ + if (window.gif) { + if (gif.currentFrame) { + return gif.frames[gif.currentFrame(t)] + } + else { + return gif.frames[0] + } + } + else if (window.img) { + return img_frame + } + else { + return cq(w, h) + } +} +function ready(){ + loading = false + if (window.gif) { + frame = gif.frames[0] + } + else { + fc = cq(img.width, img.height) + fc.drawImage(img, 0, 0) + frame = img_frame = { ctx: fc.context } + } + w = cc.canvas.width = frame.ctx.canvas.width + h = cc.canvas.height = frame.ctx.canvas.height +} + +function shade(frame, t){ + if (! t || isNaN(t)) throw Error ("No time specified") + if (! frame) throw Error ("No frame specified") + try { + var f = $("#shader").val() + if (!f.length) return; + var shader = new Function('x','y','t','d', f) + } + catch (e) { + throw Error ("Shader compilation error") + } + + var imageData = frame.ctx.getImageData(0,0,w,h) + var data = imageData.data + + var cloneData = frame.ctx.getImageData(0,0,w,h) + var clone = cloneData.data + + try { + var realw = w, realh = h + for (var x = 0; x < w; x++) { + for (var y = 0; y < h; y++) { + q = 4*(y*w+x) + r = data[q], g = data[q+1], b = data[q+2], a = data[q+3] + result = shader(x,y,t,clone) + data[q] = r + data[q+1] = g + data[q+2] = b + data[q+3] = a + w = realw, h = realh + } + } + } + catch(e){ + throw Error ("Shader execution error") + } + cc.putImageData(imageData,0,0) +} + +function add_frame(){ + var frame_count = $("#framecount").int() + if (frame_count < 2) { + add_single_frame() + } + else { + add_frames(frame_count) + } +} +function add_single_frame(){ + var $el = $("<div>") + $el.html( $("#frame-template").html() ) + var frame = cc.clone().appendTo($el.find(".frame")[0]) + frame.canvas.className = "fullsize" + frame.canvas.style.display = "none" + var thumb = cc.clone().resize(100,100).appendTo($el.find(".frame")[0]) + $("#frames").append($el) + $("#render").enable() +} +function add_frames(frame_count){ + rendering = true + var t = old_t - start_t - pause_t + var frame_delay = $("#frameinterval").float() * 1000 + var frame + for (var i = 0; i < frame_count; i++) { + frame = giveFrame(t) + t += frame_delay + shade(frame, t) + add_single_frame() + } + rendering = false +} +function remove_frame(){ + $(this).closest("div").remove() + if ($("#frames div").length == 0) { + $("#render").disable() + } +} +function remove_all_frames(){ + $("#frames").empty() +} + +function render (){ + if (rendering) return + rendering = true + encoder.reset() + var delay = $("#framedelay").float() * 1000 || 100 + $("#frames canvas.fullsize").each(function(){ + var frame = cq(this.width, this.height).fillStyle($("#background").string()).fillRect(0,0,this.width, this.height).drawImage(this,0,0) + encoder.addFrame(frame.canvas, delay) + }) + $("#pause,#render,#add-frame").disable() + $("#rendered").find("img").remove() + $("#rendered").show() + // really bad results with neuquant? + // status("quantizing") + // encoder.quantize() + status("encoding") + try { + encoder.encode() + } catch (e) { + $("#pause,#render,#add-frame").enable() + rendering = false + status(e) + throw e + } + $("#render").html("rendering") +} + +function status(s){ + $("#status").html(s) +} + +var encoder = new GifEncoder() + +encoder.on("quantized", function(url){ + status("encoding") + encoder.encode() +}) + +encoder.on("encoded-frame", function(done,count){ + status("encoded " + done + " / " + count) +}) + +encoder.on("rendered", function(bytes){ + status(filesize(bytes.length)) +}) + +encoder.on("rendered-url", function(url){ + var image = new Image () + lastGif = image.src = url + $("#rendered").append(image) + $("#save,#upload,#rendered").show() + $("#pause,#render,#add-frame,#save,#upload").enable() + $("#render").html("render") + rendering = false + pause(true) +}) + +function save (){ + if (! lastGif) return; + var filename = document.getElementById("url").value.replace(/^.*\//,"").replace(/\.gif.*$/,"") + var blob = dataUriToBlob(lastGif) + saveAs(blob, filename + "-" + (+new Date()) + ".gif"); +} + +function upload(){ + var filename = document.getElementById("url").value.replace(/^.*\//,"").replace(/\.gif.*$/,"") + var blob = dataUriToBlob(lastGif) + uploadImage({ + blob: blob, + filename: filename + "-" + (+new Date()) + ".gif", + username: "", + success: function(data){ + + // data.url + // data.filesize + // data.success + + console.log(data); + status("uploaded"); + + $("#uploaded-url").show().focus().val(data.url) + }, + error: function(data){ + console.log(data) + status("error uploading: " + data.error) + } + }); +} + +</script> +<script type="text/html" id="frame-template"> +<button class="remove">x</button> +<span class="frame"></span> +</script> +<script type="text/javascript-shader" id="first"> +t /= 500 +if (a == 0) { r = g = b = x; t /= -3 } +r *= (Math.sin(t*x/y) + 1)/2 +g *= (Math.cos(t*y/x) + 0.4)/2 +b *= (Math.sin(t) + 1.5)/2 +a = y + +</script> +<script type="text/javascript-shader" id="second"> +xx = x, yy = y + +var d = ((x % 2) + 2 * (y % 2)) - 2 + +x += w/2 +y -= h/2 +t/=-200 +y/=96 +x/=50 +v = (Math.sin(t+x*y) + 1.0) / 2 +v = (0.6) * v - 0.4 + Math.random() + +v = clamp( v*64 + 128 , 0, 255) +v += d*32 +if (a == 0) r = g = b = xx/w * 255 +a = v > 128 ? v:0 + +</script> +</html> + |
