254 lines
6.2 KiB
JavaScript
254 lines
6.2 KiB
JavaScript
"use strict";
|
|
|
|
/**
|
|
* a black/white 2d bitmap for collision detecting
|
|
* @constructor
|
|
*/
|
|
function Bitmap(width, height)
|
|
{
|
|
this.width = width;
|
|
this.height = height;
|
|
this.count = width * height;
|
|
|
|
this.data = new Uint8Array(this.count);
|
|
}
|
|
|
|
// given an image, return a bitmap of pixels
|
|
// where 0 indicates a transparent pixel and 1 non-transparent one
|
|
Bitmap.fromImage = function(image)
|
|
{
|
|
var
|
|
width = image.width,
|
|
height = image.height,
|
|
bitmap = new Bitmap(width, height),
|
|
canvas = document.createElement("canvas"),
|
|
context = canvas.getContext("2d"),
|
|
data;
|
|
|
|
canvas.width = width;
|
|
canvas.height = height;
|
|
|
|
// make sure the canvas is transparent and not white
|
|
context.clearRect(0, 0, width, height);
|
|
|
|
context.drawImage(image, 0, 0);
|
|
|
|
data = context.getImageData(0, 0, width, height).data;
|
|
|
|
for(var i = 0; i < bitmap.count; i++)
|
|
{
|
|
bitmap.data[i] = data[i * 4 + 3] > 0 | 0;
|
|
}
|
|
|
|
return bitmap;
|
|
};
|
|
|
|
|
|
Bitmap.prototype.withOtherRect = function(width, height, dx, dy, f)
|
|
{
|
|
var intersection = this.getIntersection(width, height, dx, dy),
|
|
srcPointer = intersection.otherY * width + intersection.otherX,
|
|
destPointer = intersection.thisY * this.width + intersection.thisX;
|
|
|
|
for(var y = 0; y < intersection.height; y++)
|
|
{
|
|
for(var x = 0; x < intersection.width; x++)
|
|
{
|
|
f(intersection.otherX + x, intersection.otherY + y, this.data[destPointer]);
|
|
|
|
srcPointer++;
|
|
destPointer++;
|
|
}
|
|
|
|
srcPointer += width - intersection.width;
|
|
destPointer += this.width - intersection.width;
|
|
}
|
|
};
|
|
|
|
|
|
Bitmap.prototype.stringify = function()
|
|
{
|
|
var field = "Bitmap width=" + this.width + " height=" + this.height + "\n";
|
|
|
|
for(var y = 0; y < this.height; y++)
|
|
{
|
|
for(var x = 0; x < this.width; x++)
|
|
{
|
|
field += String(this.data[y * this.width + x]);
|
|
}
|
|
|
|
field += "\n";
|
|
}
|
|
|
|
return field;
|
|
};
|
|
|
|
|
|
Bitmap.prototype.set = function(x, y, value)
|
|
{
|
|
if(x >= 0 && y >= 0 && x < this.width && y < this.height)
|
|
{
|
|
this.data[y * this.width + x] = value;
|
|
}
|
|
};
|
|
|
|
Bitmap.prototype.copy = function()
|
|
{
|
|
// hacky, but whatever
|
|
return {
|
|
__proto__: Bitmap.prototype,
|
|
|
|
width : this.width,
|
|
height : this.height,
|
|
count : this.count,
|
|
|
|
data : new Uint8Array(this.data),
|
|
};
|
|
};
|
|
|
|
|
|
/**
|
|
* Calculate the intersection of this bitmap and an area with given size
|
|
* and position
|
|
*/
|
|
Bitmap.prototype.getIntersection = function(width, height, dx, dy)
|
|
{
|
|
dx = dx || 0;
|
|
dy = dy || 0;
|
|
|
|
var thisX = Math.max(0, dx),
|
|
thisY = Math.max(0, dy),
|
|
otherX = Math.max(0, -dx),
|
|
otherY = Math.max(0, -dy);
|
|
|
|
return {
|
|
thisX : thisX,
|
|
thisY : thisY,
|
|
|
|
otherX : otherX,
|
|
otherY : otherY,
|
|
|
|
width : Math.max(0, Math.min(this.width - thisX, width - otherX)),
|
|
height : Math.max(0, Math.min(this.height - thisY, height - otherY)),
|
|
};
|
|
};
|
|
|
|
|
|
/*
|
|
* return a different bitmap that is a slice in the given area
|
|
*/
|
|
Bitmap.prototype.slice = function(width, height, dx, dy)
|
|
{
|
|
var intersection = this.getIntersection(width, height, dx, dy),
|
|
other = new Bitmap(width, height),
|
|
srcPointer = intersection.thisY * this.width + intersection.thisX,
|
|
destPointer = intersection.otherY * width + intersection.otherX;
|
|
|
|
for(var y = 0; y < intersection.height; y++)
|
|
{
|
|
for(var x = 0; x < intersection.width; x++)
|
|
{
|
|
other.data[destPointer] = this.data[srcPointer];
|
|
srcPointer++;
|
|
destPointer++;
|
|
}
|
|
srcPointer += this.width - intersection.width;
|
|
destPointer += width - intersection.width;
|
|
}
|
|
|
|
return other;
|
|
};
|
|
|
|
Bitmap.prototype.isZero = function()
|
|
{
|
|
for(var i = 0; i < this.count; i++)
|
|
{
|
|
if(this.data[i])
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
};
|
|
|
|
|
|
/**
|
|
* @param {Bitmap} other
|
|
* @param {number=} dx an offset, by which the parameter bitmap is moved
|
|
* @param {number=} dy an offset, by which the parameter bitmap is moved
|
|
*/
|
|
Bitmap.prototype.or = function(other, dx, dy)
|
|
{
|
|
var intersection = this.getIntersection(other.width, other.height, dx, dy),
|
|
srcPointer = intersection.otherY * other.width + intersection.otherX,
|
|
destPointer = intersection.thisY * this.width + intersection.thisX;
|
|
|
|
for(var y = 0; y < intersection.height; y++)
|
|
{
|
|
for(var x = 0; x < intersection.width; x++)
|
|
{
|
|
this.data[destPointer] |= other.data[srcPointer];
|
|
srcPointer++;
|
|
destPointer++;
|
|
}
|
|
srcPointer += other.width - intersection.width;
|
|
destPointer += this.width - intersection.width;
|
|
}
|
|
};
|
|
|
|
|
|
// compare this bitmap with a given bitmap, moved by dx and dy,
|
|
// returning true if they have a bit in common
|
|
Bitmap.prototype.compare = function(other, dx, dy)
|
|
{
|
|
var intersection = this.getIntersection(other.width, other.height, dx, dy),
|
|
srcPointer = intersection.otherY * other.width + intersection.otherX,
|
|
destPointer = intersection.thisY * this.width + intersection.thisX;
|
|
|
|
for(var y = 0; y < intersection.height; y++)
|
|
{
|
|
for(var x = 0; x < intersection.width; x++)
|
|
{
|
|
if(this.data[destPointer] && other.data[srcPointer])
|
|
{
|
|
return true;
|
|
}
|
|
|
|
srcPointer++;
|
|
destPointer++;
|
|
}
|
|
|
|
srcPointer += other.width - intersection.width;
|
|
destPointer += this.width - intersection.width;
|
|
}
|
|
|
|
return false;
|
|
};
|
|
|
|
/**
|
|
* Compare this bitmap to a list of bitmaps with x and y value
|
|
* sx and sy indicate, how this bitmap is moved
|
|
*/
|
|
Bitmap.prototype.compareMany = function(bitmaps, sx, sy)
|
|
{
|
|
var self = this;
|
|
|
|
return bitmaps.some(function(obj)
|
|
{
|
|
if(obj.x > sx + self.width ||
|
|
obj.y > sy + self.height ||
|
|
obj.x + obj.bitmap.width < sx ||
|
|
obj.y + obj.bitmap.height < sy)
|
|
{
|
|
// safes us some computations,
|
|
// since this is often the case
|
|
return false;
|
|
}
|
|
|
|
return self.compare(obj.bitmap, obj.x - sx, obj.y - sy);
|
|
});
|
|
};
|
|
|
|
|