// xbminimal.js - XBM image drawing API
// based on xbmDraw.js (see copyright notice below)
// 2005-05-11: stripped down & optimized version by toxi ( info at toxi . co . uk )

// (c)2002 David L. Blackledge
// http://David.Blackledge.com
// Written April, 2002
// You may use this if you keep this copyright notice intact
// See http://David.Blackledge.com/XBMDrawLibrary.html

// usage:
// var myImg = new XBMImage(128,32,"foo");
// var myImg.set(x,y) - set single pixel
// var myImg.line(x1,y1,x2,y2) - draw line between point x1;y1 -> x2;y2
// var myImg.lineH(x1,y,x2) - draw horizontal line x1;y -> x2;y
// var myImg.lineV(x,y1,y2) - draw vertical line x;y1 -> x;y2
//
// <img src="javascript:myImg.getImage();" />

function XBMImage(w,h,name) {
    this._name=name;
    this._width=w;
    this._byteWidth=w>>3;
    this._height=h;
    this._pixels=[];
    this._length=this._byteWidth*h;
    for(var i=0; i<this._length; i++) this._pixels[i]=0;
    this._hex="0123456789abcdef";
}

XBMImage.prototype.set = function(x,y) {
    var bit = x%8;
    var byt = (x-bit)>>3;
    this._pixels[y*this._byteWidth+byt] |= (1<<bit);
};

XBMImage.prototype.lineH = function(x1,y1,x2) {
    if(!(y1 > -1 && y1 < this._height)) return;
    if(x1 > x2){
        var xs = x1;
        x1=Math.max(0,x2);
        x2=Math.min(this._width,xs);
    }
    var filled = 0xff;
    var yoff=y1*this._byteWidth;
    var startbits = x1%8;
    var startbyt = yoff+((x1-x1%8)>>3);
    var endbits = 8-x2%8;
    var endbyt = yoff+((x2-x2%8)>>3);
    if(startbyt == endbyt) {
        this._pixels[startbyt]|=(filled <<startbits)&(filled>>endbits);
        return;
    }
    for(var i = startbyt+1 ; i < endbyt ; ++i) this._pixels[i] = filled;
    for(var j=x1; j < (x1+(8-x1%8)) ; ++j) this.set(j,y1);
    this._pixels[endbyt] |= (filled >>endbits);
};

XBMImage.prototype.lineV = function(x1,y1,y2) {
    if(!(x1 > -1 && x1 < this._width)) return;
    if(y1 > y2){
        var ys = y1;
        y1=Math.max(0,y2);
        y2=Math.min(this._height,ys);
    }
    var bit = x1%8;
    var off = this._byteWidth*y1+((x1-bit)>>3);
    var bitmask = (1<<bit);
    for(var y = y1 ; y <= y2 ; ++y) {
        this._pixels[off] |= bitmask;
        off+=this._byteWidth;
    }
};

XBMImage.prototype.line = function(x1,y1,x2,y2) {
    if(x1 > x2) {
        var xx = x1; x1 = x2; x2 = xx;
        var yy = y1; y1 = y2; y2 = yy;
    }
    var y = y1;
    if(y1 == y2)
        if(x1 == x2)
            return this.set(x1,y1);
    else
        return this.lineH(x1,y1,x2);
    if(x1 == x2) return this.lineV(x1,y1,y2);
    var slope=(y1-y2)/(x1-x2);
    var yint=y1-Math.floor(slope*x1); // y-intercept
    for(var x = x1; x < x2; ++x) {
        var yend=Math.floor(slope*(x+1))+yint;
        if(slope > 0) { //y1<y2 (top to bottom)
            for(y = Math.floor(slope*x)+yint ; y<yend; ++y) this.set(x,y);
            if(Math.floor(slope*x) == Math.floor(slope*(x+1))) this.set(x,y);
            if(x==x2-1) {
                for(y; y<=y2; ++y) this.set(x,y);
            }
        } else { //y1>y2 (bottom to top)
            for(y = Math.floor(slope*x)+yint; y>yend; --y) this.set(x,y);
            if(Math.floor(slope*x) == Math.floor(slope*(x+1))) this.set(x,y);
            if(x==x2-1) {
                for(y; y>=y2; --y)  this.set(x,y);
            }
        }
    }
};

XBMImage.prototype.getImage = function() {
    var xbm = "#define "+this._name+"_width "+this._width+"\n#define "+this._name+"_height "+this._height+"\nstatic char count_bits[] = {";
    var len=this._length-1;
    for(var i=0; i<this._length; i++) {
        b="0x"+this._hex.charAt(this._pixels[i]>>4)+this._hex.charAt(this._pixels[i]&0x0f);
        xbm+=b+(i<len ? ', ' : '};');
    }
    return xbm;
};


