var vsSource = [ "attribute vec2 pos;", "void main()", "{", "gl_Position = vec4(pos.x,pos.y,0.0,1.0);", "}" ].join("\n"); var fsSource = [ "void main()", "{", "gl_FragColor = vec4(0.0,0.0,0.0,1.0);", "}" ].join("\n"); //-------------------------------------- function createGLTexture( ctx, image, format, texture ) { if( ctx==null ) return; ctx.bindTexture( ctx.TEXTURE_2D, texture); ctx.pixelStorei( ctx.UNPACK_FLIP_Y_WEBGL, false ); ctx.texImage2D( ctx.TEXTURE_2D, 0, format, ctx.RGBA, ctx.UNSIGNED_BYTE, image); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR_MIPMAP_LINEAR); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.REPEAT); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.REPEAT); ctx.generateMipmap(ctx.TEXTURE_2D); ctx.bindTexture(ctx.TEXTURE_2D, null); } function createGLTextureLinear( ctx, image, texture ) { if( ctx==null ) return; ctx.bindTexture( ctx.TEXTURE_2D, texture); ctx.pixelStorei( ctx.UNPACK_FLIP_Y_WEBGL, false ); ctx.texImage2D( ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); ctx.bindTexture(ctx.TEXTURE_2D, null); } function createGLTextureNearestRepeat( ctx, image, texture ) { if( ctx==null ) return; ctx.bindTexture(ctx.TEXTURE_2D, texture); ctx.pixelStorei( ctx.UNPACK_FLIP_Y_WEBGL, false ); ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST); ctx.bindTexture(ctx.TEXTURE_2D, null); } function createGLTextureNearest( ctx, image, texture ) { if( ctx==null ) return; ctx.bindTexture(ctx.TEXTURE_2D, texture); ctx.pixelStorei( ctx.UNPACK_FLIP_Y_WEBGL, false ); ctx.texImage2D(ctx.TEXTURE_2D, 0, ctx.RGBA, ctx.RGBA, ctx.UNSIGNED_BYTE, image); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE); ctx.texParameteri(ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE); ctx.bindTexture(ctx.TEXTURE_2D, null); } function createAudioTexture( ctx, texture ) { if( ctx==null ) return; ctx.bindTexture( ctx.TEXTURE_2D, texture ); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.LINEAR ); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.LINEAR ); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE ); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE) ; ctx.texImage2D( ctx.TEXTURE_2D, 0, ctx.LUMINANCE, 512, 2, 0, ctx.LUMINANCE, ctx.UNSIGNED_BYTE, null); ctx.bindTexture( ctx.TEXTURE_2D, null); } function createKeyboardTexture( ctx, texture ) { if( ctx==null ) return; ctx.bindTexture( ctx.TEXTURE_2D, texture ); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MAG_FILTER, ctx.NEAREST ); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_MIN_FILTER, ctx.NEAREST ); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_S, ctx.CLAMP_TO_EDGE ); ctx.texParameteri( ctx.TEXTURE_2D, ctx.TEXTURE_WRAP_T, ctx.CLAMP_TO_EDGE) ; ctx.texImage2D( ctx.TEXTURE_2D, 0, ctx.LUMINANCE, 256, 2, 0, ctx.LUMINANCE, ctx.UNSIGNED_BYTE, null); ctx.bindTexture( ctx.TEXTURE_2D, null); } function Effect( ac, gl, xres, yres, callback, obj, forceMuted, forcePaused) { this.mAudioContext = ac; this.mNoAudioMessageShowed = false; this.mGLContext = gl; this.mQuadVBO = null; this.mProgram = null; this.mXres = xres; this.mYres = yres; this.mInputs = new Array(4); this.mInputs[0] = null; this.mInputs[1] = null; this.mInputs[2] = null; this.mInputs[3] = null; this.mTextureCallbackFun = callback; this.mTextureCallbackObj = obj; this.mSource = null; this.mForceMuted = forceMuted; this.mForcePaused = forcePaused; this.mSupportsDerivatives = false; //------------- if( gl==null ) return; var ext = gl.getExtension('OES_standard_derivatives'); this.mSupportsDerivatives = (ext != null); if( this.mSupportsDerivatives ) { gl.hint( ext.FRAGMENT_SHADER_DERIVATIVE_HINT_OES, gl.NICEST ); } var ext2 = gl.getExtension('OES_texture_float'); this.mSupportTextureFloat = (ext2 != null ); var vertices = new Float32Array( [ -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, -1.0, 1.0] ); this.mQuadVBO = gl.createBuffer(); gl.bindBuffer(gl.ARRAY_BUFFER, this.mQuadVBO); gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW); var res = this.NewShader(fsSource); this.DetermineShaderPrecission(); this.MakeHeader(); } Effect.prototype.DestroyInput = function( id ) { if( this.mInputs[id]==null ) return; if( this.mGLContext== null ) return; var gl = this.mGLContext; if( this.mInputs[id].mInfo.mType=="texture" ) { gl.deleteTexture( this.mInputs[id].globject ); } else if( this.mInputs[id].mInfo.mType=="slideshow" ) { gl.deleteTexture( this.mInputs[id].globject ); } else if( this.mInputs[id].mInfo.mType=="webcam" ) { gl.deleteTexture( this.mInputs[id].globject ); } else if( this.mInputs[id].mInfo.mType=="video" ) { this.mInputs[id].video.pause(); this.mInputs[id].video = null; gl.deleteTexture( this.mInputs[id].globject ); } else if( this.mInputs[id].mInfo.mType=="music" ) { this.mInputs[id].audio.pause(); this.mInputs[id].audio = null; gl.deleteTexture( this.mInputs[id].globject ); } else if( this.mInputs[id].mInfo.mType=="cubemap" ) { gl.deleteTexture( this.mInputs[id].globject ); } else if( this.mInputs[id].mInfo.mType=="keyboard" ) { gl.deleteTexture( this.mInputs[id].globject ); } this.mInputs[id] = null; } Effect.prototype.NewTexture = function( slot, url ) { var me = this; var gl = this.mGLContext; var texture = null; if (url!=null && url.mType=="webcam" && this.mForceMuted) { url.mType = "texture"; } if( url==null ) { if( me.mTextureCallbackFun!=null ) me.mTextureCallbackFun( this.mTextureCallbackObj, slot, null, false, true, 0, -1.0 ); return false; } else if( url.mType=="texture" ) { texture = {}; texture.mInfo = url; texture.globject = (gl!=null) ? gl.createTexture() : null; texture.loaded = false; texture.image = new Image(); texture.image.crossOrigin = ''; texture.image.onload = function() { var format = gl.RGBA; if( url.mSrc=="/presets/tex15.png" || url.mSrc=="/presets/tex17.png" ) format = gl.LUMINANCE; if( url.mSrc=="/presets/tex14.png" ) createGLTextureNearest( gl, texture.image, texture.globject ); else if( url.mSrc=="/presets/tex15.png" ) createGLTextureNearestRepeat( gl, texture.image, texture.globject ); else createGLTexture( gl, texture.image, format, texture.globject ); texture.loaded = true; if( me.mTextureCallbackFun!=null ) me.mTextureCallbackFun( me.mTextureCallbackObj, slot, texture.image, true, true, 0, -1.0 ); } texture.image.src = url.mSrc; } else if( url.mType=="slideshow" ) { texture = {}; texture.mInfo = url; texture.globject = (gl!=null) ? gl.createTexture() : null; texture.loaded = false; texture.image = new Image(); texture.image.crossOrigin = ''; texture.image.onload = function() { createGLTexture( gl, texture.image, gl.RGBA, texture.globject ); texture.loaded = true; if( me.mTextureCallbackFun!=null ) me.mTextureCallbackFun( me.mTextureCallbackObj, slot, texture.image, true, true, 3, -1.0 ); } texture.slideshow = {}; texture.slideshow.mCurrentSlide = 0; texture.slideshow.mNewTextureReady = false; var urlSlide = url.mSrc.replace("??","00"); texture.image.src = urlSlide; } else if( url.mType=="cubemap" ) { texture = {}; texture.mInfo = url; texture.globject = (gl!=null) ? gl.createTexture() : null; texture.loaded = false; texture.image = [ new Image(), new Image(), new Image(), new Image(), new Image(), new Image() ]; gl.bindTexture( gl.TEXTURE_CUBE_MAP, texture.globject ); gl.texParameteri( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MAG_FILTER, gl.LINEAR ); gl.texParameteri( gl.TEXTURE_CUBE_MAP, gl.TEXTURE_MIN_FILTER, gl.LINEAR ); gl.bindTexture( gl.TEXTURE_CUBE_MAP, null ); texture.loaded = true; for( var i=0; i<6; i++ ) { texture.image[i].mId = i; texture.image[i].crossOrigin = ''; texture.image[i].onload = function() { var id = this.mId; gl.bindTexture( gl.TEXTURE_CUBE_MAP, texture.globject ); gl.pixelStorei( gl.UNPACK_FLIP_Y_WEBGL, false ); gl.texImage2D( gl.TEXTURE_CUBE_MAP_POSITIVE_X + id, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, texture.image[id] ); gl.bindTexture( gl.TEXTURE_CUBE_MAP, null ); if( me.mTextureCallbackFun!=null ) me.mTextureCallbackFun( me.mTextureCallbackObj, slot, texture.image[0], true, true, 0, -1.0 ); } texture.image[i].src = url.mSrc.replace( "_0.", "_" + i + "." ); } } else if( url.mType=="webcam" ) { texture = {}; texture.mInfo = url; texture.globject = null; texture.loaded = false; texture.video = document.createElement('video'); texture.video.width = 320; texture.video.height = 240; texture.video.autoplay = true; texture.video.loop = true; texture.video.paused = true; navigator.getUserMedia( { "video": true, "audio": false }, function(stream) { texture.video.src = window.URL.createObjectURL(stream); texture.globject = gl.createTexture(); try { createGLTextureLinear( gl, texture.video, texture.globject ); texture.loaded = true; } catch(e) { alert( 'Your browser can not transfer webcam data to the GPU.'); } }, function(error) { alert( 'Unable to capture WebCam. Please reload the page.' ); } ); } else if( url.mType=="video" ) { texture = {}; texture.mInfo = url; texture.globject = null; texture.loaded = false; texture.video = document.createElement('video'); texture.video.width = 256; texture.video.height = 256; texture.video.loop = true; texture.video.paused = true;//this.mForcePaused; texture.video.mPaused = true;//this.mForcePaused; texture.video.mMuted = this.mForceMuted; texture.video.muted = this.mForceMuted; if( this.mForceMuted==true ) texture.video.volume = 0; texture.video.autoplay = false; texture.video.hasFalled = false; texture.video.addEventListener( "canplay", function(e) { texture.video.play(); texture.video.paused = false; texture.video.mPaused = false; texture.globject = gl.createTexture(); createGLTextureLinear( gl, texture.video, texture.globject ); texture.loaded = true; if( me.mTextureCallbackFun!=null ) me.mTextureCallbackFun( me.mTextureCallbackObj, slot, texture.video, true, true, 1, -1.0 ); } ); texture.video.addEventListener( "error", function(e) { if( texture.video.hasFalled==true ) { alert("Error: cannot load video" ); return; } var str = texture.video.src; str = str.substr(0,str.lastIndexOf('.') ) + ".mp4"; texture.video.src = str; texture.video.hasFalled = true; } ); texture.video.src = url.mSrc; } else if( url.mType=="music" ) { texture = {}; texture.mInfo = url; texture.globject = null; texture.loaded = false; texture.audio = document.createElement('audio'); texture.audio.loop = true; texture.audio.mMuted = this.mForceMuted; texture.audio.mForceMuted = this.mForceMuted; texture.audio.muted = this.mForceMuted; if( this.mForceMuted==true ) texture.audio.volume = 0; texture.audio.autoplay = true; texture.audio.hasFalled = false; texture.audio.paused = true; texture.audio.mPaused = true; texture.audio.mSound = {}; if( this.mForceMuted ) { texture.globject = gl.createTexture(); createAudioTexture( gl, texture.globject ); var num = 512; texture.audio.mSound.mFreqData = new Uint8Array( num ); texture.audio.mSound.mWaveData = new Uint8Array( num ); texture.loaded = true; texture.audio.paused = false; texture.audio.mPaused = false; } texture.audio.addEventListener( "canplay", function() { if( this.mForceMuted ) return; texture.globject = gl.createTexture(); createAudioTexture( gl, texture.globject ); if( me.mAudioContext != null ) { var ctx = me.mAudioContext; texture.audio.mSound.mSource = ctx.createMediaElementSource( texture.audio ); texture.audio.mSound.mAnalyser = ctx.createAnalyser(); texture.audio.mSound.mGain = ctx.createGain(); texture.audio.mSound.mSource.connect( texture.audio.mSound.mAnalyser ); texture.audio.mSound.mAnalyser.connect( texture.audio.mSound.mGain ); texture.audio.mSound.mGain.connect( ctx.destination ); texture.audio.mSound.mFreqData = new Uint8Array( texture.audio.mSound.mAnalyser.frequencyBinCount ); texture.audio.mSound.mWaveData = new Uint8Array( texture.audio.mSound.mAnalyser.frequencyBinCount ); texture.loaded = true; texture.audio.paused = false; texture.audio.mPaused = false; } else { if( me.mNoAudioMessageShowed==false ) { var ve = document.getElementById( "centerScreen" ); doAlert( getCoords(ve), {mX:420,mY:160}, "Error", "Your browser does not support WebAudio.

This shader will not work as the author intended. Please consider using a WebAudio-friendly browser (Chrome).", false, null ); me.mNoAudioMessageShowed = true; } } } ); texture.audio.addEventListener( "error", function(e) { if( this.mForceMuted ) return; if( texture.audio.hasFalled==true ) { /*alert("Error: cannot load music" ); */return; } var str = texture.audio.src; str = str.substr(0,str.lastIndexOf('.') ) + ".ogg"; texture.audio.src = str; texture.audio.hasFalled = true; } ); if( !this.mForceMuted ) { texture.audio.src = url.mSrc; } if( me.mTextureCallbackFun!=null ) me.mTextureCallbackFun( me.mTextureCallbackObj, slot, null, false, true, 2, -1.0 ); } else if( url.mType=="keyboard" ) { texture = {}; texture.mInfo = url; texture.globject = gl.createTexture(); texture.loaded = true; texture.keyboard = {}; texture.keyboard.mImage = new Image(); texture.keyboard.mImage.onload = function() { texture.loaded = true; if( me.mTextureCallbackFun!=null ) me.mTextureCallbackFun( me.mTextureCallbackObj, slot, {mImage:texture.keyboard.mImage,mData:texture.keyboard.mData}, false, false, 4, -1.0 ); } texture.keyboard.mImage.src = "/img/keyboard.png"; texture.keyboard.mNewTextureReady = true; texture.keyboard.mData = new Uint8Array( 256*2 ); createKeyboardTexture( gl, texture.globject ); for( var j=0; j<(256*2); j++ ) { texture.keyboard.mData[j] = 0; } if( me.mTextureCallbackFun!=null ) me.mTextureCallbackFun( me.mTextureCallbackObj, slot, {mImage:texture.keyboard.mImage,mData:texture.keyboard.mData}, false, false, 4, -1.0 ); } else if( url.mType==null ) { if( me.mTextureCallbackFun!=null ) me.mTextureCallbackFun( this.mTextureCallbackObj, slot, null, false, true, 0, -1.0 ); } else { alert( "texture type error" ); return; } this.DestroyInput( slot ); this.mInputs[slot] = texture; this.MakeHeader(); } Effect.prototype.SetKeyDown = function( k ) { for( var i=0; i1 ) { return { mFailed : true, mError : "ShaderToy only supports one-pass shaders at this momment", mShader:null }; } for( var j=0; j