/
spriteanim.min.js
8 lines (8 loc) · 15.2 KB
/
spriteanim.min.js
1
2
3
4
5
6
7
8
/*******************************************************************************************
* SpriteAnim v0.1.7 (beta)
* Author: Catalin Berta
* E-mail: catalinberta (at) gmail (dot) com
* Documentation: https://github.com/catalinberta/SpriteAnimJS
* Most of the awesome webgl support is from: http://webglsamples.org
*******************************************************************************************/
!function(a){"use strict";var b=function(a,b){this.canvas=document.getElementById(a),this.useCanvas=b||!1,this.init()};b.prototype.init=function(){this.useCanvas?this.context=this.canvas.getContext("2d"):this.webgl_support(this.canvas)?(this.context=this.create3DContext(this.canvas),document.getElementById("spriteAnimFragmentShader")||this.injectShaders()):(this.context=this.canvas.getContext("2d"),this.useCanvas=!0)},b.prototype.start=function(a){return this.spriteObj=a,this.onStart(),a.className&&(this.canvas.className=this.canvas.className?this.canvas.className+" "+a.className:a.className),this.width=this.spriteObj.frameWidth,this.height=this.spriteObj.frameHeight,this.totalWidth=this.spriteObj.image.width,this.totalHeight=this.spriteObj.image.height,this.image=this.spriteObj.image,this.canvas.width=this.width,this.canvas.height=this.height,this.horizontalframeIndex=0,this.verticalFrameIndex=0,this.horizontalFrames=this.totalWidth/a.frameWidth||1,this.verticalFrames=this.totalHeight/a.frameHeight||1,this.fps=this.spriteObj.fps||30,this.timestamp_init=Date.now(),this.interval=1e3/this.fps,this.timestamp_now,this.delta,this.loopSprite=this.spriteObj.loop||!1,this.playSprite=!0,this.useCanvas?(this.canvasTicker(),void 0):(this.webglStart(a),void 0)},b.prototype.stop=function(){return this.playSprite=!1,this.webgl_support(this.canvas)?(this.webglStop(),void 0):(this.context.clearRect(0,0,this.totalWidth,this.totalHeight),void 0)},b.prototype.canvasUpdate=function(){this.horizontalframeIndex<this.horizontalFrames?(this.horizontalframeIndex+=1,this.draw()):this.verticalFrameIndex<this.verticalFrames?(this.verticalFrameIndex+=1,this.horizontalframeIndex=1,this.draw()):(this.loopSprite?(this.verticalFrameIndex=1,this.horizontalframeIndex=1,this.draw()):this.stop(),this.onComplete())},b.prototype.onStart=function(){this.spriteObj.onStart&&this.spriteObj.onStart()},b.prototype.onComplete=function(){this.spriteObj.onComplete&&this.spriteObj.onComplete()},b.prototype.draw=function(){this.context.clearRect(0,0,this.totalWidth,this.totalHeight),this.context.drawImage(this.image,(this.horizontalframeIndex-1)*this.totalWidth/this.horizontalFrames,(this.verticalFrameIndex-1)*this.totalHeight/this.verticalFrames,this.totalWidth/this.horizontalFrames,this.totalHeight,0,0,this.totalWidth/this.horizontalFrames,this.totalHeight)},b.prototype.canvasTicker=function(){this.playSprite&&(a.requestAnimationFrame(this.canvasTicker.bind(this)),this.timestamp_now=Date.now(),this.delta=this.timestamp_now-this.timestamp_init,this.delta>this.interval&&(this.timestamp_init=this.timestamp_now-this.delta%this.interval,this.canvasUpdate()))},b.prototype.injectShaders=function(){var a=document.createElement("script");a.type="x-shader/x-vertex",a.id="spriteAnimVertexShader",a.text="uniform float u_frameOffset; uniform vec4 u_screenDims; attribute vec2 centerPosition; attribute float perSpriteFrameOffset; attribute float spriteWidth; attribute float spriteHeight; attribute vec2 cornerOffset; attribute vec2 spriteTextureSize; attribute float spritesPerRow; attribute float numFrames; attribute vec4 textureWeights; varying vec2 v_texCoord; varying vec4 v_textureWeights; void main() { float frameNumber = mod(u_frameOffset + perSpriteFrameOffset, numFrames); float row = floor(frameNumber / spritesPerRow); vec2 upperLeftTC = vec2(spriteTextureSize.x * (frameNumber - (row * spritesPerRow)), spriteTextureSize.y * row);vec2 tc = upperLeftTC + spriteTextureSize * (cornerOffset + vec2(0.5, 0.5));v_texCoord = tc; v_textureWeights = textureWeights; vec2 scaledOffset = vec2(spriteWidth,spriteHeight) * cornerOffset; vec2 pos = centerPosition + 1.0 * scaledOffset; gl_Position = vec4(pos * u_screenDims.xy + u_screenDims.zw, 1.0, 1.0); }",document.body.appendChild(a);var b=document.createElement("script");b.type="x-shader/x-fragment",b.id="spriteAnimFragmentShader",b.text="precision mediump float; uniform sampler2D u_texture0; uniform sampler2D u_texture1; uniform sampler2D u_texture2; uniform sampler2D u_texture3; varying vec2 v_texCoord; varying vec4 v_textureWeights; void main() { vec4 color; if (v_textureWeights.x > 0.0) color = texture2D(u_texture0, v_texCoord); else if (v_textureWeights.y > 0.0) color = texture2D(u_texture1, v_texCoord); else if (v_textureWeights.z > 0.0) color = texture2D(u_texture2, v_texCoord); else color = texture2D(u_texture3, v_texCoord); gl_FragColor = color; }",document.body.appendChild(b)},b.prototype.webglStart=function(){this.onload=null,this.spriteSheets_=[],this.textures_=[],this.currentTextureUnit_=0,this.context.pixelStorei(this.context.UNPACK_PREMULTIPLY_ALPHA_WEBGL,!0),this.context.enable(this.context.BLEND),this.context.disable(this.context.DEPTH_TEST),this.context.disable(this.context.CULL_FACE),this.context.blendFunc(this.context.ONE,this.context.ONE_MINUS_SRC_ALPHA),this.constantAttributeInfo_=[{size:1,offset:0},{size:1,offset:0},{size:1,offset:0},{size:2,offset:0},{size:2,offset:0},{size:1,offset:0},{size:1,offset:0},{size:4,offset:0}],this.initialize_=function(){if(!this.initialized_){for(var a=this.constantAttributeInfo_,b=0,c=0;c<a.length;++c)a[c].offset=b,b+=a[c].size;this.constantAttributeStride_=b,this.initialized_=!0}},this.constantAttributeStride_=0,this.SPRITE_HEIGHT_INDEX=0,this.PER_SPRITE_FRAME_OFFSET_INDEX=1,this.SPRITE_WIDTH_INDEX=2,this.CORNER_OFFSET_INDEX=3,this.SPRITE_TEXTURE_SIZE_INDEX=4,this.SPRITES_PER_ROW_INDEX=5,this.NUM_FRAMES_INDEX=6,this.TEXTURE_WEIGHTS_INDEX=7,this.initialize_(),this.sysLoadProgram_(this.spriteObj),this.frameOffset_=0,this.spriteBuffer_=this.context.createBuffer(),this.sysClearAllSprites(),this.offsets_=[[-.5,-.5],[-.5,.5],[.5,-.5],[.5,-.5],[-.5,.5],[.5,.5]],this.initialized_=!1,this.screenWidth_=this.width,this.screenHeight_=this.height,this.onload=this.spriteSheetCreateSprite,this.params_={frames:this.horizontalFrames*this.verticalFrames,spritesPerRow:this.horizontalFrames,width:this.width,height:this.height},this.textureUnit_=0,this.perSpriteFrameOffset_=0,this.spriteSheets_.push(this);var c=this.context.createTexture();this.context.bindTexture(this.context.TEXTURE_2D,c),this.context.texParameteri(this.context.TEXTURE_2D,this.context.TEXTURE_MIN_FILTER,this.context.LINEAR),this.context.texParameteri(this.context.TEXTURE_2D,this.context.TEXTURE_MAG_FILTER,this.context.LINEAR),this.context.texParameteri(this.context.TEXTURE_2D,this.context.TEXTURE_WRAP_S,this.context.CLAMP_TO_EDGE),this.context.texParameteri(this.context.TEXTURE_2D,this.context.TEXTURE_WRAP_T,this.context.CLAMP_TO_EDGE),this.context.texImage2D(this.context.TEXTURE_2D,0,this.context.RGBA,this.context.RGBA,this.context.UNSIGNED_BYTE,this.image),this.textureUnit_=this.currentTextureUnit_,this.textureWidth_=this.image.width,this.textureHeight_=this.image.height,this.textures_[this.currentTextureUnit_]=c,++this.currentTextureUnit_,this.onload&&this.onload()},b.prototype.webglStop=function(){this.playSprite=!1,this.sysDraw("clear")},b.prototype.webgl_support=function(){for(var b=["webgl","experimental-webgl"],c=null,d=0;d<b.length;++d){try{c=this.canvas.getContext(b[d])}catch(e){}if(c)break}return c?!0:void 0},b.prototype.create3DContext=function(){for(var b=["webgl","experimental-webgl"],c=null,d=0;d<b.length;++d){try{c=this.canvas.getContext(b[d])}catch(e){}if(c)break}return c&&(this.context=c,this.canvas.tdl||(this.canvas.tdl={}),c.tdl={},c.tdl.depthTexture=this.getExtensionWithKnownPrefixes("WEBGL_depth_texture")),c},b.prototype.getExtensionWithKnownPrefixes=function(a){this.browserPrefixes_=["","MOZ_","OP_","WEBKIT_"];for(var b=0;b<this.browserPrefixes_.length;++b){var c=this.browserPrefixes_[b]+a,d=this.context.getExtension(c);if(d)return d}},b.prototype.spriteSheetCreateSprite=function(){this.canvas.width,this.canvas.height;var c=0,d=0,e=this.perSpriteFrameOffset_++;this.perSpriteFrameOffset_>=this.params_.frames&&(this.perSpriteFrameOffset_=0);var f=this.params_.height,g=this.params_.width,h=1*this.params_.width/this.textureWidth_,i=1*this.params_.height/this.textureHeight_,j=this.params_.spritesPerRow,k=this.params_.frames,l=[0,0,0,0];l[this.textureUnit_]=1;for(var m=0;m<this.offsets_.length;++m)this.sysAddVertex_(c,d,e,f,g,this.offsets_[m][0],this.offsets_[m][1],h,i,j,k,l);this.webglTicker()},b.prototype.sysLoadShader=function(a,b){var c=this.context.createShader(b);return this.context.shaderSource(c,a),this.context.compileShader(c),this.context.getShaderParameter(c,this.context.COMPILE_STATUS),c},b.prototype.sysClearAllSprites=function(){this.sysResizeCapacity_(120,!1),this.frameOffset_=0,this.numVertices_=0,this.precisePositionView_=null},b.prototype.sysLoadProgram_=function(){var b="spriteAnimFragmentShader",c=this.sysLoadShader(document.getElementById("spriteAnimVertexShader").text,this.context.VERTEX_SHADER),d=this.sysLoadShader(document.getElementById(b).text,this.context.FRAGMENT_SHADER),e=this.context.createProgram();this.context.attachShader(e,c),this.context.attachShader(e,d),this.context.linkProgram(e),this.context.getProgramParameter(e,this.context.LINK_STATUS),this.context.deleteShader(c),this.context.deleteShader(d),this.program_=e,this.frameOffsetLoc_=this.context.getUniformLocation(e,"u_frameOffset"),this.screenDimsLoc_=this.context.getUniformLocation(e,"u_screenDims"),this.centerPositionLoc_=this.context.getAttribLocation(e,"centerPosition"),this.spriteHeightLoc_=this.context.getAttribLocation(e,"spriteHeight"),this.perSpriteFrameOffsetLoc_=this.context.getAttribLocation(e,"perSpriteFrameOffset"),this.spriteWidthLoc_=this.context.getAttribLocation(e,"spriteWidth"),this.cornerOffsetLoc_=this.context.getAttribLocation(e,"cornerOffset"),this.spriteTextureSizeLoc_=this.context.getAttribLocation(e,"spriteTextureSize"),this.spritesPerRowLoc_=this.context.getAttribLocation(e,"spritesPerRow"),this.numFramesLoc_=this.context.getAttribLocation(e,"numFrames"),this.textureWeightsLoc_=this.context.getAttribLocation(e,"textureWeights"),this.texture0Loc_=this.context.getUniformLocation(e,"u_texture0"),this.texture1Loc_=this.context.getUniformLocation(e,"u_texture1"),this.texture2Loc_=this.context.getUniformLocation(e,"u_texture2"),this.texture3Loc_=this.context.getUniformLocation(e,"u_texture3")},b.prototype.sysResizeCapacity_=function(a){this.capacity_=a,this.positionData_=new Float32Array(2*a),this.constantData_=new Float32Array(this.constantAttributeStride_*a),this.startPositionData_=new Array(2*a),this.spriteHeightData_=new Array(a),this.spriteWidthData_=new Array(a),this.context.bindBuffer(this.context.ARRAY_BUFFER,this.spriteBuffer_),this.context.bufferData(this.context.ARRAY_BUFFER,Float32Array.BYTES_PER_ELEMENT*(this.positionData_.length+this.constantData_.length),this.context.DYNAMIC_DRAW)},b.prototype.sysSetupConstantLoc_=function(a,b){if(-1!=a){var c=Float32Array.BYTES_PER_ELEMENT*this.positionData_.length,d=this.constantAttributeStride_,e=this.constantAttributeInfo_;this.context.enableVertexAttribArray(a),this.context.vertexAttribPointer(a,e[b].size,this.context.FLOAT,!1,d*Float32Array.BYTES_PER_ELEMENT,c+Float32Array.BYTES_PER_ELEMENT*e[b].offset)}},b.prototype.sysDraw=function(){if(this.frameOffset_==this.spriteSheets_[0].params_.frames){if(!this.loopSprite)return this.playSprite=!1,void 0;this.frameOffset_=-1,this.spriteObj.onComplete&&this.spriteObj.onComplete()}for(var a=this.numVertices_,b=0;a>b;++b)this.positionData_[2*b]=this.width/2,this.positionData_[2*b+1]=this.height/2;this.context.bindBuffer(this.context.ARRAY_BUFFER,this.spriteBuffer_),this.precisePositionView_&&this.precisePositionView_.length==2*a||(this.precisePositionView_=this.positionData_.subarray(0,2*a)),this.context.bufferSubData(this.context.ARRAY_BUFFER,0,this.precisePositionView_);for(var c=0;c<this.currentTextureUnit_;++c)this.context.activeTexture(this.context.TEXTURE0+c),this.context.bindTexture(this.context.TEXTURE_2D,this.textures_[c]);this.context.useProgram(this.program_),this.context.enableVertexAttribArray(this.centerPositionLoc_),this.context.vertexAttribPointer(this.centerPositionLoc_,2,this.context.FLOAT,!1,0,0),this.sysSetupConstantLoc_(this.spriteHeightLoc_,this.SPRITE_HEIGHT_INDEX),this.sysSetupConstantLoc_(this.perSpriteFrameOffsetLoc_,this.PER_SPRITE_FRAME_OFFSET_INDEX),this.sysSetupConstantLoc_(this.spriteWidthLoc_,this.SPRITE_WIDTH_INDEX),this.sysSetupConstantLoc_(this.cornerOffsetLoc_,this.CORNER_OFFSET_INDEX),this.sysSetupConstantLoc_(this.spriteTextureSizeLoc_,this.SPRITE_TEXTURE_SIZE_INDEX),this.sysSetupConstantLoc_(this.spritesPerRowLoc_,this.SPRITES_PER_ROW_INDEX),this.sysSetupConstantLoc_(this.numFramesLoc_,this.NUM_FRAMES_INDEX),this.sysSetupConstantLoc_(this.textureWeightsLoc_,this.TEXTURE_WEIGHTS_INDEX),this.context.uniform1f(this.frameOffsetLoc_,this.frameOffset_++),this.context.uniform4f(this.screenDimsLoc_,2/this.canvas.width,-2/this.canvas.height,-1,1),this.context.uniform1i(this.texture0Loc_,0),this.context.uniform1i(this.texture1Loc_,1),this.context.uniform1i(this.texture2Loc_,2),this.context.uniform1i(this.texture3Loc_,3),this.context.drawArrays(this.context.TRIANGLES,0,this.numVertices_)},b.prototype.sysAddVertex_=function(a,b,c,d,e,f,g,h,i,j,k,l){this.numVertices_==this.capacity_&&this.sysResizeCapacity_(2*this.capacity_,!0);var m=this.numVertices_;++this.numVertices_;var n=this.constantAttributeStride_*m;this.constantData_[n+this.constantAttributeInfo_[this.SPRITE_HEIGHT_INDEX].offset]=d,this.constantData_[n+this.constantAttributeInfo_[this.PER_SPRITE_FRAME_OFFSET_INDEX].offset]=c,this.constantData_[n+this.constantAttributeInfo_[this.SPRITE_WIDTH_INDEX].offset]=e,this.constantData_[n+this.constantAttributeInfo_[this.CORNER_OFFSET_INDEX].offset]=f,this.constantData_[n+this.constantAttributeInfo_[this.CORNER_OFFSET_INDEX].offset+1]=g,this.constantData_[n+this.constantAttributeInfo_[this.SPRITE_TEXTURE_SIZE_INDEX].offset]=h,this.constantData_[n+this.constantAttributeInfo_[this.SPRITE_TEXTURE_SIZE_INDEX].offset+1]=i,this.constantData_[n+this.constantAttributeInfo_[this.SPRITES_PER_ROW_INDEX].offset]=j,this.constantData_[n+this.constantAttributeInfo_[this.NUM_FRAMES_INDEX].offset]=k,this.constantData_[n+this.constantAttributeInfo_[this.TEXTURE_WEIGHTS_INDEX].offset]=l[0],this.constantData_[n+this.constantAttributeInfo_[this.TEXTURE_WEIGHTS_INDEX].offset+1]=l[1],this.constantData_[n+this.constantAttributeInfo_[this.TEXTURE_WEIGHTS_INDEX].offset+2]=l[2],this.constantData_[n+this.constantAttributeInfo_[this.TEXTURE_WEIGHTS_INDEX].offset+3]=l[3],this.context.bindBuffer(this.context.ARRAY_BUFFER,this.spriteBuffer_),this.context.bufferSubData(this.context.ARRAY_BUFFER,Float32Array.BYTES_PER_ELEMENT*(this.positionData_.length+n),this.constantData_.subarray(n,n+this.constantAttributeStride_))},b.prototype.webglTicker=function(){this.playSprite&&(a.requestAnimationFrame(this.webglTicker.bind(this)),this.timestamp_now=Date.now(),this.delta=this.timestamp_now-this.timestamp_init,this.delta>this.interval&&(this.context.viewport(0,0,this.width,this.height),this.context.clearColor(0,0,0,0),this.context.clear(this.context.COLOR_BUFFER_BIT|this.context.DEPTH_BUFFER_BIT),this.sysDraw(),this.timestamp_init=this.timestamp_now-this.delta%this.interval))},a.SpriteAnim=b}(window);