Created
August 22, 2016 09:04
-
-
Save MLaszczewski/a22687fe3833acbea57bda3af5a8fd04 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var gfx = require("./gfx.js") | |
var fastMath = require('./fastMath.js') | |
var sintab = fastMath.sintab | |
var costab = fastMath.costab | |
var STNode=function(x,y,width,height) { | |
this.left = null | |
this.right = null | |
this.image = null | |
this.x = x | |
this.y = y | |
this.width = width | |
this.height = height | |
} | |
STNode.prototype.insert = function(image,spacing) { | |
var box_width=image.width + spacing | |
var box_height=image.height + spacing | |
if(this.left && this.right) { | |
return this.left.insert(image,spacing) || this.right.insert(image,spacing) | |
} else { | |
// if there's already a sprite here, return | |
if(this.image) return null; | |
// if we're too small, return | |
if((box_width>this.width) || ((box_height)>this.height)) return null | |
if((box_width==this.width) && ((box_height)==this.height)) { //if we're just right, accept | |
this.image=image | |
return this | |
} else { // otherwise, gotta split this node and create some kids | |
var dw = this.width - (box_width) | |
var dh = this.height - (box_height) | |
if(dw>dh) { | |
this.left = new STNode(this.x, this.y, box_width, this.height) | |
this.right = new STNode(this.x+box_width, this.y, this.width-(box_width), this.height) | |
} else { | |
this.left = new STNode(this.x, this.y, this.width, box_height) | |
this.right = new STNode(this.x, this.y+box_height, this.width, this.height-(box_height)) | |
} | |
// insert into first child we created | |
return this.left.insert(image,spacing) | |
} | |
} | |
} | |
var AutoSpritesTexture = function(gl,size,spacing) { | |
this.gl = gl | |
this.size = size | |
this.canvas = document.createElement('canvas') | |
this.canvas.width = this.size | |
this.canvas.height = this.size | |
this.ctx = this.canvas.getContext('2d') | |
this.sprites = [] | |
this.spacing = spacing | |
this.needUpload = false | |
var gl = this.gl | |
this.texture = gl.createTexture() | |
gl.bindTexture(gl.TEXTURE_2D, this.texture) | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR) | |
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR_MIPMAP_LINEAR) | |
this.shaderProgram = createSpritesShaderProgram(gl) | |
this.shaderProgram3d = create3dSpritesShaderProgram(gl) | |
this.positionBuffer = gl.createBuffer() | |
this.colorBuffer = gl.createBuffer() | |
this.coordBuffer = gl.createBuffer() | |
} | |
AutoSpritesTexture.prototype.tryPack = function(sprites) { | |
var nodes = new Array(sprites.length) | |
var root = new STNode(0,0,this.size,this.size) | |
sprites = sprites.sort((function(a,b) { | |
return Math.max(b.width,b.height)-Math.max(a.width,a.height) | |
}).bind(this)) | |
for(var i=0; i< sprites.length; i++) { | |
var sprite = sprites[i] | |
var node = root.insert(sprite.image,this.spacing*2) | |
if(!node) return false; | |
nodes[i] = node | |
} | |
var fix = -2 | |
for(var i=0; i<sprites.length; i++) { | |
var node = nodes[i] | |
var sprite = sprites[i] | |
sprite.coords = { | |
width: node.width, | |
height: node.height, | |
x: node.x, | |
y: node.y, | |
xmin: (node.x+fix)/this.size, | |
ymin: (node.y+fix)/this.size, | |
xmax: (node.x+node.width-this.spacing+fix)/this.size, | |
ymax: (node.y+node.height-this.spacing+fix)/this.size | |
} | |
} | |
this.sprites = sprites | |
this.needUpload = true | |
return true | |
} | |
AutoSpritesTexture.prototype.tryAddSprite = function(sprite) { | |
if(!this.tryPack(this.sprites.concat([sprite]))) { | |
return false; | |
} else { | |
sprite.spritesTexture = this | |
sprite.loaded = true | |
return true; | |
} | |
} | |
AutoSpritesTexture.prototype.isBigEnough = function(w,h) { | |
return (w<this.size && h<this.size) | |
} | |
AutoSpritesTexture.prototype.upload = function() { | |
if(!this.needUpload) return; | |
var ctx = this.ctx | |
var canvas = this.canvas | |
var gl = this.gl | |
ctx.clearRect(0, 0, canvas.width, canvas.height) | |
/*ctx.fillStyle="#FF00FF" | |
ctx.fillRect(0,0,canvas.width, canvas.height)*/ | |
for(var i=0; i<this.sprites.length; i++) { | |
var sprite = this.sprites[i] | |
ctx.drawImage(sprite.image,sprite.coords.x,sprite.coords.y) | |
} | |
gl.bindTexture(gl.TEXTURE_2D, this.texture) | |
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, canvas) | |
gl.generateMipmap(gl.TEXTURE_2D) | |
for(var i=0; i<this.sprites.length; i++) { | |
var sprite = this.sprites[i] | |
sprite.texture = this.textureId | |
console.log("SPRITE QUAD",sprite.name,sprite.coords) | |
sprite.quad = [ | |
sprite.coords.xmin,sprite.coords.ymin, | |
sprite.coords.xmax,sprite.coords.ymin, | |
sprite.coords.xmax,sprite.coords.ymax, | |
sprite.coords.xmin ,sprite.coords.ymax, | |
sprite.coords.xmin, sprite.coords.ymin, | |
sprite.coords.xmax,sprite.coords.ymax | |
] | |
sprite.loaded = true | |
} | |
this.needUpload = false | |
} | |
AutoSpritesTexture.prototype.removeSprite = function(sprite) { | |
console.log("REMOVE SPRITE",sprite.name) | |
this.sprites.splice(this.sprites.indexOf(sprite),1) | |
} | |
AutoSpritesTexture.prototype.bufferSprite = function(drawBuffer,sprite,x,y,angle,s,r,g,b,a) { | |
if(!sprite) throw new Error("SPRITE "+id+" NOT FOUND!") | |
var quad = sprite.quad | |
if(!quad) return; | |
var ai=Math.floor(angle*10)%3600 | |
var ulX=x+s*sintab[(ai+3150)%3600] | |
var ulY=y-s*costab[(ai+3150)%3600] | |
var urX=x+s*sintab[(ai+450)%3600] | |
var urY=y-s*costab[(ai+450)%3600] | |
var lrX=x+s*sintab[(ai+1350)%3600] | |
var lrY=y-s*costab[(ai+1350)%3600] | |
var llX=x+s*sintab[(ai+2250)%3600] | |
var llY=y-s*costab[(ai+2250)%3600] | |
drawBuffer.addPoint(ulX,ulY,quad[0],quad[1],r,g,b,a) | |
drawBuffer.addPoint(urX,urY,quad[2],quad[3],r,g,b,a) | |
drawBuffer.addPoint(lrX,lrY,quad[4],quad[5],r,g,b,a) | |
drawBuffer.addPoint(llX,llY,quad[6],quad[7],r,g,b,a) | |
drawBuffer.addPoint(ulX,ulY,quad[8],quad[9],r,g,b,a) | |
drawBuffer.addPoint(lrX,lrY,quad[10],quad[11],r,g,b,a) | |
} | |
module.exports = AutoSpritesTexture | |
var create3dSpritesShaderProgram=function(gl) { | |
var vertexShader = gfx.createShader(gl,gl.VERTEX_SHADER, | |
[ "attribute vec3 aVertexPosition;", | |
"attribute vec4 aVertexColor;", | |
"attribute vec2 aTextureCoord;", | |
"uniform mat4 uCameraMatrix;", | |
"varying vec4 vColor;", | |
"varying highp vec2 vTextureCoord;", | |
"void main() {", | |
" gl_Position =uCameraMatrix*vec4(aVertexPosition, 1.0);", | |
" vColor = aVertexColor;", | |
" vTextureCoord = aTextureCoord;", | |
"}" | |
].join('\n')) | |
var fragmentShader = gfx.createShader(gl,gl.FRAGMENT_SHADER, | |
[ "precision mediump float;", | |
"varying vec4 vColor;", | |
"uniform sampler2D uSampler;", | |
"varying highp vec2 vTextureCoord;", | |
"void main() {", | |
" vec4 textureColor = texture2D(uSampler, vTextureCoord);", | |
" gl_FragColor = vColor*textureColor;", | |
"}"].join('\n')) | |
var shaderProgram = gfx.createProgram(gl,vertexShader,fragmentShader) | |
shaderProgram.begin=function(gl) { | |
gl.useProgram(shaderProgram) | |
shaderProgram.aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition") | |
gl.enableVertexAttribArray(shaderProgram.aVertexPosition) | |
shaderProgram.aTextureCoord = gl.getAttribLocation(shaderProgram, "aTextureCoord") | |
gl.enableVertexAttribArray(shaderProgram.aTextureCoord) | |
shaderProgram.aVertexColor = gl.getAttribLocation(shaderProgram,"aVertexColor") | |
gl.enableVertexAttribArray(shaderProgram.aVertexColor) | |
shaderProgram.uCameraMatrix = gl.getUniformLocation(shaderProgram, "uCameraMatrix") | |
shaderProgram.uSampler = gl.getUniformLocation(shaderProgram, "uSampler") | |
} | |
shaderProgram.end=function(gl) { | |
gl.disableVertexAttribArray(shaderProgram.aVertexPosition) | |
gl.disableVertexAttribArray(shaderProgram.aVertexColor) | |
gl.disableVertexAttribArray(shaderProgram.aTextureCoord) | |
} | |
return shaderProgram | |
} | |
AutoSpritesTexture.prototype.beginFastDraw = function(gl,camMatrix) { | |
this.shaderProgram.begin(gl) | |
gl.uniformMatrix4fv(this.shaderProgram.uCameraMatrix, false, camMatrix); | |
gl.activeTexture(gl.TEXTURE0); | |
gl.bindTexture(gl.TEXTURE_2D, this.texture); | |
gl.uniform1i(this.shaderProgram.uSampler, 0) | |
} | |
AutoSpritesTexture.prototype.fastDrawBuffer = function(gl,drawBuffer) { | |
if(drawBuffer.positionsIterator==0) return; | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.positionBuffer) | |
gl.bufferData(gl.ARRAY_BUFFER, new DataView(drawBuffer.positions.buffer,0,drawBuffer.positionsIterator*4), gl.DYNAMIC_DRAW) | |
gl.vertexAttribPointer(this.shaderProgram.aVertexPosition, 2, gl.FLOAT, false, 0, 0) | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.colorBuffer) | |
gl.bufferData(gl.ARRAY_BUFFER, new DataView(drawBuffer.colors.buffer,0,drawBuffer.colorsIterator*4), gl.DYNAMIC_DRAW) | |
gl.vertexAttribPointer(this.shaderProgram.aVertexColor, 4, gl.FLOAT, false, 0, 0) | |
gl.bindBuffer(gl.ARRAY_BUFFER, this.coordBuffer) | |
gl.bufferData(gl.ARRAY_BUFFER, new DataView(drawBuffer.coords.buffer,0,drawBuffer.coordsIterator*4), gl.DYNAMIC_DRAW) | |
gl.vertexAttribPointer(this.shaderProgram.aTextureCoord, 2, gl.FLOAT, false, 0, 0) | |
//console.log("ASDB",drawBuffer.pointsCount,drawBuffer.positions.length,drawBuffer.colors.length, drawBuffer.coords.length) | |
gl.drawArrays(gl.TRIANGLES, 0, drawBuffer.pointsCount); | |
} | |
AutoSpritesTexture.prototype.endFastDraw = function(gl) { | |
this.shaderProgram.end(gl) | |
} | |
var createSpritesShaderProgram=function(gl) { | |
var vertexShader = gfx.createShader(gl,gl.VERTEX_SHADER, | |
[ "attribute vec2 aVertexPosition;", | |
"attribute vec4 aVertexColor;", | |
"attribute vec2 aTextureCoord;", | |
"uniform mat4 uCameraMatrix;", | |
"varying vec4 vColor;", | |
"varying highp vec2 vTextureCoord;", | |
"void main() {", | |
" gl_Position =uCameraMatrix*vec4(aVertexPosition, 0.0, 1.0);", | |
" vColor = aVertexColor;", | |
" vTextureCoord = aTextureCoord;", | |
"}" | |
].join('\n')) | |
var fragmentShader = gfx.createShader(gl,gl.FRAGMENT_SHADER, | |
[ "precision mediump float;", | |
"varying vec4 vColor;", | |
"uniform sampler2D uSampler;", | |
"varying highp vec2 vTextureCoord;", | |
"void main() {", | |
" vec4 textureColor = texture2D(uSampler, vTextureCoord);", | |
" gl_FragColor = vColor*textureColor;", | |
"}"].join('\n')) | |
var shaderProgram = gfx.createProgram(gl,vertexShader,fragmentShader) | |
shaderProgram.begin=function(gl) { | |
gl.useProgram(shaderProgram) | |
shaderProgram.aVertexPosition = gl.getAttribLocation(shaderProgram, "aVertexPosition") | |
gl.enableVertexAttribArray(shaderProgram.aVertexPosition) | |
shaderProgram.aTextureCoord = gl.getAttribLocation(shaderProgram, "aTextureCoord") | |
gl.enableVertexAttribArray(shaderProgram.aTextureCoord) | |
shaderProgram.aVertexColor = gl.getAttribLocation(shaderProgram,"aVertexColor") | |
gl.enableVertexAttribArray(shaderProgram.aVertexColor) | |
shaderProgram.uCameraMatrix = gl.getUniformLocation(shaderProgram, "uCameraMatrix") | |
shaderProgram.uSampler = gl.getUniformLocation(shaderProgram, "uSampler") | |
} | |
shaderProgram.end=function(gl) { | |
gl.disableVertexAttribArray(shaderProgram.aVertexPosition) | |
gl.disableVertexAttribArray(shaderProgram.aVertexColor) | |
gl.disableVertexAttribArray(shaderProgram.aTextureCoord) | |
} | |
return shaderProgram | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment