bitmap.js.coffee | |
---|---|
@module bitmapDemo | |
= require ./mylibs/Math = require ./mylibs/Polygon = require ./mylibs/collisions | |
@param {Image} bitmap | bitmapDemo = (bitmap) -> |
fetch and save the canvas context | FLIP_Y_AXIS = false
canvas = $("#maincanvas").get(0)
context = canvas.getContext('2d') |
the hidden canvas for alpha testing | hcanvas = $('#hiddencanvas').get(0)
hcontext = hcanvas.getContext('2d') |
save canvas dimensions and bitmap | cw = canvas.width
ch = canvas.height
img = bitmap
imgX = imgY = 0
lastRot = 0
shapePolygons = []
imgPixels = imgBorderMap = null
dragging = false |
translate world for cartesian coordinates if desired | if FLIP_Y_AXIS
context.scale(1, -1)
context.translate(0, -ch)
|
display canvas dimensions | $('#info').html("Canvas: #{cw} x #{ch}<br/>")
describe = (text...) ->
txt = ''
for t in text
txt += '<li>' + t + '</li>'
$('#drawingCommands').html txt
say = (text) ->
drawText text
|
clear the canvas and draw the bitmap | drawScene = ->
imgX = cw/2 - img.width/2
imgY = ch/2 - img.height/2
context.clearRect(0, 0, cw, ch)
context.drawImage(img, imgX, imgY)
describe "clearRect(0, 0, #{cw}, #{ch})", "drawImage(img, #{imgX}, #{imgY})"
|
clear the canvas and draw the bitmap at some point | drawAt = (pt) ->
imgX = pt.x - img.width/2
imgY = pt.y - img.height/2
context.clearRect(0, 0, cw, ch)
context.drawImage(img, imgX, imgY)
imgPixels = null
|
display some text | drawText = (text) ->
tx = cw/2 + 100
ty = ch/2
context.clearRect(tx, ty, 100, 50)
context.fillStyle = '#00f'
context.font = '30px Arial sans-serif'
context.textBaseline = 'top'
context.fillText text, tx, ty
|
scale & draw the bitmap | scale = (x=0.5, y=0.5) ->
context.save()
context.translate(imgX, imgY)
context.scale x, y
context.drawImage(img, imgX, imgY)
context.restore()
|
rotate and draw the bitmap | rotate = ->
lastRot += 45
context.save()
context.translate(imgX, imgY)
context.rotate Math.degreesToRadians(lastRot)
context.drawImage(img, 0, 0)
context.restore() |
scale, rotate, and draw the bitmap | scaleRotate = ->
lastRot += 45
context.save()
context.translate(imgX, imgY)
context.scale 0.5, 0.5
context.rotate Math.degreesToRadians(lastRot)
context.drawImage(img, 0, 0)
context.restore()
|
draw image border rectangle | drawBorder = ->
context.save()
context.strokeStyle = 'black';
context.lineWidth = 3;
context.strokeRect(imgX, imgY, img.width, img.height)
context.restore()
|
Constructs bitmap shape from PhysicsEditor vertices in JSON format @returns {Array} of Polygon objects | shapePolygons = ->
return shapePolygons if shapePolygons.length > 0
shapePoints = (vertices) ->
$V([vertices[2*i], vertices[2*i+1], 0]) for i in [0...vertices.length/2]
new Polygon(shapePoints(vtx.shape)) for vtx in bitmapVertices.Master_Shake
|
fill the bitmap using PhysicsEditor vertices | fillShape = (fill) ->
imgOffx = (x) -> imgX + x
imgOffy = (y) -> imgY + y
drawPoly = (vertices) ->
v1 = vertices[0]
context.beginPath()
context.moveTo(imgOffx(v1.e(1)), imgOffy(v1.e(2)))
for i in [1...vertices.length]
context.lineTo(imgOffx(vertices[i].e(1)), imgOffy(vertices[i].e(2)))
if fill then context.fill() else context.stroke()
context.closePath()
context.save()
context.strokeStyle = 'red';
context.lineWidth = 1;
drawPoly(p.points) for p in shapePolygons()
context.restore()
|
Returns bitmap pixel array using hidden context | imagePixels = ->
hcontext.clearRect(0, 0, cw, ch)
hcontext.drawImage(img, imgX, imgY)
hcontext.getImageData(0, 0, cw, ch).data
|
create the image border index map | makeImageBorderMap = ->
imgPixels ?= imagePixels()
imgBorderMap = []
outside = true
alphaCheck = (i) -> |
if alpha is not 100%, it's an image pixel | if imgPixels[i + 3] > 0 |
outside to inside detection | if outside
outside = false
imgBorderMap.push(i)
else if !outside # inside to outside detection
outside = true
imgBorderMap.push(i) |
horizontal pass | for y in [0...cw]
for x in [0...ch]
idx = ((cw * y) + x) * 4
alphaCheck idx
|
vertical pass | outside = true
for x in [0...cw]
for y in [0...ch]
idx = ((cw * y) + x) * 4
alphaCheck idx
imgBorderMap
|
attempt shape border effect on bitmap | glow = ->
imgBorderMap ?= makeImageBorderMap()
imgd = context.getImageData(0, 0, cw, ch)
pix = imgd.data
applyBorder = (idx) -> |
idx -= 15*4 | pix[idx ] = 255 # red
pix[idx+1] = 0
pix[idx+2] = 0
pix[idx+3] = 255
|
Loop over border pixels and make them red | for idx in imgBorderMap
applyBorder idx
context.putImageData(imgd, 0, 0)
|
invert the bitmaps non-alpha pixel colors | invertColor = -> |
Create an ImageData object. | imgd = context.getImageData(imgX, imgY, img.width, img.height)
pix = imgd.data |
Loop over each pixel and invert the color | for idx in [0...pix.length]
i = idx * 4
pix[i ] = 255 - pix[i ]; # red
pix[i+1] = 255 - pix[i+1]; # green
pix[i+2] = 255 - pix[i+2]; # blue
|
Draw the ImageData object at the given (x,y) coordinates. | context.putImageData(imgd, imgX, imgY)
|
hit testing with polygons | hitTestPoly = (pt) ->
pnt = $V([pt.x-imgX, pt.y-imgY, 0]) |
Use vertices to test for point-in-polygon | for poly in shapePolygons()
return true if collisions.pointInPolygon pnt, poly
|
hit testing with pixel alphas | hitTestAlpha = (pt) -> |
use the hidden canvas context to store the bitmap pixels | imgPixels ?= imagePixels()
idx = 4 * (pt.x + pt.y * cw) + 3;
imgPixels[idx] > 0
testHit = (pt) -> |
use selected hit testing stragegy | test = if $('input[name=hittest]:checked').val() == "1" then hitTestAlpha else hitTestPoly
if test.call(this, pt)
say "hit!"
true
else
say ""
false
|
redirect to display canvas as PNG | toPNG = ->
window.location = canvas.toDataURL 'image/png'
|
mouse coordinates to canvas coordinates | convertEventToCanvas = (evt) -> |
get canvas position | obj = canvas;
top = left = 0
while obj.tagName != 'BODY'
top += obj.offsetTop
left += obj.offsetLeft
obj = obj.offsetParent |
return relative mouse position | mouseX = evt.clientX - left + window.pageXOffset
mouseY = evt.clientY - top + window.pageYOffset
p = {
x: mouseX
y: mouseY
}
p.y = ch - p.y if FLIP_Y_AXIS
p |
mouse event handlers | mouseDown = (evt) ->
cp = convertEventToCanvas evt
console.log "mouseDown #{cp.x}, #{cp.y}"
dragging = testHit cp
mouseUp = (evt) ->
dragging = false
mouseMoved = (evt) ->
cp = convertEventToCanvas evt
if dragging
drawAt cp
else
testHit cp
canvas.addEventListener('mousedown', mouseDown, false)
canvas.addEventListener('mouseup', mouseUp, false)
canvas.addEventListener('mousemove', mouseMoved, false)
|
return public functions | {drawScene,
scale,
rotate,
scaleRotate,
drawBorder,
fillShape,
glow,
invertColor,
drawText,
toPNG}
|
main() | $(document).ready ->
demo = null |
Create image object from url | mshake = new Image()
mshake.onload = ->
demo = bitmapDemo(this)
demo.drawScene()
mshake.src = 'img/Master_Shake.png'
$('#reset').click -> demo.drawScene()
$('#scale').click -> demo.scale()
$('#rotate').click -> demo.rotate()
$('#scaleRotate').click -> demo.scaleRotate()
$('#border').click -> demo.drawBorder()
$('#fill').click -> demo.fillShape(true)
$('#polys').click -> demo.fillShape(false)
$('#glow').click -> demo.glow()
$('#invertColor').click -> demo.invertColor()
$('input').blur -> demo.drawText($('input').val())
$('#export').click -> demo.toPNG()
$("#maincanvas").click -> demo.hitTest
|