#define BLACK                0
#define BLUE                1
#define GREEN                2
#define CYAN                3
#define RED                4
#define PURPLE                5
#define BROWN                6
#define LTGRAY                7
#define DKGRAY                8
#define LTBLUE                9
#define LTGREEN                10
#define LTCYAN                11
#define LTRED                12
#define LTPURPLE        13
#define YELLOW                14
#define WHITE                15


//Low 8 bits reserved for flags that go into saved bitmaps
#define BMF_COMPRESSED                1


#define BMF_TRANSFORMATION        0x100

//See $LK,"GrSetSymmetry","MN:GrSetSymmetry"$() or $LK,"GrSetSymmetry3","MN:GrSetSymmetry3"$()
#define BMF_SYMMETRY                0x200

//Must be used with BMF_SYMMETRY set also.
//See $LK,"WarGame","FF:::/LT/Apps/WarGame/WarGame.CPZ,BMF_JUST_MIRROR"$
#define BMF_JUST_MIRROR                0x400

#define BMF_LOCATE_NEAREST        0x800
#define BMF_DONT_DRAW                0x1000
#define BMF_ALIAS                0x2000
#define BMF_SCREEN_BITMAP        0x4000
#define BMF_FILL_NOT_COLOR        0x8000
#define BMF_RECORD_EXTENTS        0x10000
#define BMF_ON_TOP                0x20000

#define BMT_COLOR4        1
#define BMT_MONO        2

//This is using a byte plane instead of 4 bit planes.
//It doesn't help performance, however,
//might provide a starting point if anyone
//wants to do 24 bit color.
#define BMT_COLOR4_U1        3

#define BMS_SIGNATURE        0x28768922

public class GrSymStruct
{
 I4 sx,sy,sz,pad2;
 //Normal of symmetry plane
 I8 snx,sny,snz;
};

public class GrBitMap
{
 U0 start_saved_area;
 I4 type,width,width_internal,height;
 U8 flags;
 I8 plane_size;
 I4 left_margin,right_margin,top_margin,bottom_margin;
 U0 end_saved_area;

//public
 I4 color,bkcolor;
 I4 color2,pen_width;
 GrBitMap *brush;

 I8 *r;  //rotation matrix of quads decimal in lo
 I4 x,y,z,pad1;   //translation

 GrSymStruct sym;

//not document num, but num in a GrElems collection
 I8 nearest_grelem_num;

 U8 nearest_dist;

//not document num, but num in a GrElems collection
 I8 cur_grelem_num;

 I4 cur_x,cur_y,cur_z,pad3;
 double speedline_scale;
 U8 collision_cnt;

 //Set by $LK,"BMF_RECORD_EXTENTS","MN:BMF_RECORD_EXTENTS"$
 I8 min_x,max_x,min_y,max_y; //screen coordinates

 U4 bitmap_signature,pad4;
 TssStruct *mem_tss,*win_tss;
 GrBitMap *mask;
 U1 *body;
};


#help_index "Graphics/Bitmaps"

public void GrReset(GrBitMap *base)
{
 base->color=BLACK;
 base->color2=BLACK;
 base->bkcolor=BLACK;
 base->pen_width=1;
 base->flags&=~(BMF_SYMMETRY|BMF_TRANSFORMATION|BMF_JUST_MIRROR);
}

public GrBitMap *GrAlias(GrBitMap *base,TssStruct *tss)
{
 GrBitMap *result;
 if (!base) return NULL;
 result=MAlloc(sizeof(GrBitMap),tss);
 if (base->bitmap_signature!=BMS_SIGNATURE)
     Debugger;
 MemCpy(result,base,sizeof(GrBitMap));
 result->win_tss=tss;
 result->mem_tss=tss;
 result->r=MAlloc(16<<3,tss);
 GrSetIdent(result->r);
 GrReset(result);
 result->flags|=BMF_ALIAS;
 if (base->mask) {
     result->mask=GrAlias(base->mask,tss);
     result->mask->color=base->mask->color;
 }
 return result;
}


public GrBitMap *GrNew(U8 type,U8 width,U8 height,TssStruct *tss=NULL,BoolI1 null_bitmap=FALSE)
{  //This internally only allows widths which are divisible by 8
//$FG,4$Don't forget these$FG$
$MA+A-X+PU,"sizeof(GrBitMap)","Grep(\"sizeof(GrBitMap)\",\"/LT/\"TEXT_FILE_MASK);View;"$.
 GrBitMap *result;
 if (!tss) tss=Fs;
 result=MAllocZ(sizeof(GrBitMap),tss);
 result->win_tss=tss;
 result->mem_tss=tss;
 result->type=type;
 result->width=width;
 result->width_internal=(width+7)&~7;
 result->height=height;
 result->left_margin=0;
 result->right_margin=width;
 result->top_margin=0;
 result->bottom_margin=height;
 switch (type) {
     case BMT_COLOR4:
         result->plane_size=(result->width_internal*result->height)>>3;
         if (!null_bitmap)
             result->body=MAllocZ(result->plane_size<<2,tss);
         break;
     case BMT_COLOR4_U1:
         result->plane_size=result->width_internal*result->height;
         if (!null_bitmap)
             result->body=MAllocZ(result->plane_size,tss);
         break;
     case BMT_MONO:
         result->plane_size=(result->width_internal*result->height)>>3;
         if (!null_bitmap)
             result->body=MAllocZ(result->plane_size,tss);
         break;
     default:
         throw(EXCEPT_GRAPHICS,1);
 }
 if (null_bitmap)
     result->flags|=BMF_DONT_DRAW;
 result->pen_width=1;
 result->r=MAllocZ(16<<3,tss);
 result->r[0].u4[1]=1;
 result->r[5].u4[1]=1;
 result->r[10].u4[1]=1;
 result->r[15].u4[1]=1;
 result->speedline_scale=0.04;
 result->mask=NULL;
 result->bitmap_signature=BMS_SIGNATURE;
 return result;
}

public void GrDel(GrBitMap *base)
{
 if (!base) return;
 if (base->bitmap_signature!=BMS_SIGNATURE)
     Debugger;
 base->bitmap_signature=0;
 Free(base->r);
 if (!(base->flags & BMF_ALIAS))
     Free(base->body);
 GrDel(base->mask);
 Free(base);
}

public GrBitMap *GrCopy(GrBitMap *base,TssStruct *tss=NULL)
{
 GrBitMap *result;
 if (!base) return NULL;
 if (base->bitmap_signature!=BMS_SIGNATURE)
     Debugger;
 result=MAllocIdentical(base,tss);
 result->r=MAllocIdentical(base->r,tss);
 result->mem_tss=tss;
 result->body=MAllocIdentical(base->body,tss);
 result->mask=GrCopy(base->mask,tss);
 return result;
}

/* $AN,"GrBitMaps","GrBitMaps"$
$FG,2$        The format of a stored bitmap includes a
0x30 byte header.  See $LK,"GrBitMap","MN:GrBitMap"$.  The body
consists of bit planes like VGA except bits
in bytes are reversed.  For $LK,"BMT_MONO","MN:BMT_MONO"$, there
is one bit-plane; for $LK,"BMT_COLOR4","MN:BMT_COLOR4"$, there are
four bit-planes.

If you look at the color values ($LK,"BLACK","MN:BLACK"$-$LK,"WHITE","MN:WHITE"$)
you'll see the color of the planes is as follows:

Plane 0: BLUE
Plane 1: GREEN
Plane 2: RED
Plane 3: INTENSITY

If you are unfamiliar with bit planes, all
the blue bits for all the pixels are stored,
for all the green bits for all pixels, etc.  Therefore,
a single pixel's value is spread-out in mem
instead of residing in one location.  This
was done because that is how VGA is stored.
However, I made the order of the bits suitable
for doing $LK,"Bts","MN:Bts"$() or $LK,"Btr","MN:Btr"$() operations instead of
how VGA stores them.


The data for the following bitmap is displayed

width         : 11 pixels
height        :  8 pixels
internal width: 16 pixels (rounded-up to multiple of 8)
plane size    : 16 bytes

$PI,"",1$

#define RED                4
#define YELLOW                14


00000000 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00000010 00 00 00 00 00 00 F0 07 10 00 10 00 10 00 10 00
00000020 01 00 01 00 01 00 F1 07 11 00 11 00 11 00 11 00
00000030 00 00 00 00 00 00 F0 07 10 00 10 00 10 00 10 00

$FG$*/
public U1 *GrSave(GrBitMap *b,U8 *size=NULL,BoolI1 compressed=TRUE)
{ //stores to mem
 U1 *ptr,*body,*result;
 BoolI1 old_preempt;
 ArcCompressStruct *ac;
 I8 i,j,old_flags=b->flags;

 switch (b->type) {
     case BMT_COLOR4:
         i=b->plane_size<<2;
         break;
     case BMT_COLOR4_U1:
     case BMT_MONO:
         i=b->plane_size;
         break;
     default:
         throw(EXCEPT_GRAPHICS,2);
 }
 if (compressed) {
     ac=CompressBuf(b->body,i);
     j=ac->compressed_size;
     body=ac;

 } else {
     ac=NULL;
     j=i;
     body=b->body;
 }

 ptr=result=MAlloc(offset(GrBitMap.end_saved_area)-
         offset(GrBitMap.start_saved_area)+j);

 old_preempt=Preempt(OFF); //in case it is a screen bitmap
 if (compressed) b->flags|=BMF_COMPRESSED;
 b->flags&=BMF_COMPRESSED;
 MemCpy(result,&b->start_saved_area,
         offset(GrBitMap.end_saved_area)-
         offset(GrBitMap.start_saved_area));
 b->flags=old_flags;
 Preempt(old_preempt);

 ptr+=offset(GrBitMap.end_saved_area)-
         offset(GrBitMap.start_saved_area);
 MemCpy(ptr,body,j);
 ptr+=j;

 Free(ac);
 if (size)
     *size=ptr-result;
 return result;
}

public GrBitMap *GrLoad(U1 *src,U8 *size=NULL,TssStruct *tss=NULL)
{ //loads from mem
 I8 i;
 GrBitMap *result;
 U1 *ptr=src;
 ArcCompressStruct *ac;
 if (!tss) tss=Fs;
 result=MAllocZ(sizeof(GrBitMap),tss);
 result->win_tss=tss;
 result->mem_tss=tss;
 MemCpy(&result->start_saved_area,src,
         offset(GrBitMap.end_saved_area)-
         offset(GrBitMap.start_saved_area));
 ptr+=offset(GrBitMap.end_saved_area)-
         offset(GrBitMap.start_saved_area);
 switch (result->type) {
     case BMT_COLOR4:
         i=result->plane_size<<2;
         break;
     case BMT_COLOR4_U1:
     case BMT_MONO:
         i=result->plane_size;
         break;
     default:
         throw(EXCEPT_GRAPHICS,3);
 }
 if (result->flags&BMF_COMPRESSED) {
     result->flags&=~BMF_COMPRESSED;
     ac=ptr;
     result->body=ExpandBuf(ac,tss);
     ptr+=ac->compressed_size;
 } else {
     result->body=MAlloc(i,tss);
     MemCpy(result->body,ptr,i);
 }

 result->pen_width=1;
 result->r=MAllocZ(16<<3,tss);
 result->r[0].u4[1]=1;
 result->r[5].u4[1]=1;
 result->r[10].u4[1]=1;
 result->r[15].u4[1]=1;
 result->speedline_scale=0.04;
 result->bitmap_signature=BMS_SIGNATURE;
 result->mask=NULL;
 if (size)
     *size=ptr-src;
 return result;
}

public U8 WriteLGR(I1 *filename,GrBitMap *base)
{ // LoseThos LGR File
 U8 size;
 U1 *src=GrSave(base,&size);
 WriteFile(filename,src,size);
 Free(src);
 return size;
}

public GrBitMap *ReadLGR(I1 *filename)
{ // LoseThos LGR File
 GrBitMap *base=NULL;
 U1 *src=ReadFile(filename);
 if (src)
     base=GrLoad(src);
 Free(src);
 return base;
}

#help_index "Graphics/Bitmaps;Graphics/Screen"

public GrBitMap *GrCaptureScreen(TssStruct *tss=NULL)
{
 WinSync(TRUE);
 return GrCopy(gr_screen_image,tss);
}

public U8 CaptureScreenLGR(I1 *filename)
{ // LoseThos LGR File
 U8 size;
 GrBitMap *base=GrCaptureScreen;
 size=WriteLGR(filename,base);
 GrDel(base);
 return size;
}

#help_index "Graphics;Graphics/Bitmaps"

public void GrInitExtents(GrBitMap *base)
{//See $LK,"::/LT/Demo/Graphics/Extents.CPZ","FI:::/LT/Demo/Graphics/Extents.CPZ"$
//You should clear the record flag yourself
 base->flags|=BMF_RECORD_EXTENTS;
 base->min_x=MAX_I8;
 base->max_x=MIN_I8;
 base->min_y=MAX_I8;
 base->max_y=MIN_I8;
}

#help_index "Graphics"

public void GrPlot0(GrBitMap *base,I8 x,I8 y)
{  //No clipping or transformation or pen width
 U8 d,c,c2;
 U1 *dst,bit,not_bit;
 U8 color=base->color,bkcolor=base->bkcolor;
 double dist;

 if (base->flags & BMF_LOCATE_NEAREST) {
     dist=DistI8(x,y,base->cur_x,base->cur_y);
     if (dist<=base->nearest_dist) {
         base->nearest_grelem_num=base->cur_grelem_num;
         base->nearest_dist=dist;
     }
 }
 if (base->flags & BMF_RECORD_EXTENTS) {
     if (x<base->min_x) base->min_x=x;
     if (x>base->max_x) base->max_x=x;
     if (y<base->min_y) base->min_y=y;
     if (y>base->max_y) base->max_y=y;
 }
 if (base->flags & BMF_DONT_DRAW)
     return;
 d=base->width_internal*(y+base->top_margin)+x+base->left_margin;
 switch (base->type) {
     case BMT_COLOR4:
         dst=base->body+d>>3;
         d=base->plane_size;
         bit=1<<(x&7);
         not_bit=~bit;
         c=color.u1[0];
         switch (color.u1[3]) {
             case ROPB_EQU:
             case ROPB_CLEAR_MASK_EQU:
             case ROPB_CLEAR_MASK_TRANSPARENT:
             case ROPB_TRANSPARENT:
                 if (c & 1)
                     *dst|=bit;
                 else
                     *dst&=not_bit;
                 dst+=d;
                 if (c & 2)
                     *dst|=bit;
                 else
                     *dst&=not_bit;
                 dst+=d;
                 if (c & 4)
                     *dst|=bit;
                 else
                     *dst&=not_bit;
                 dst+=d;
                 if (c & 8)
                     *dst|=bit;
                 else
                     *dst&=not_bit;
                 break;
             case ROPB_COLLISION:
                 c2=0;
                 if (*dst&bit)
                     c2+=1;
                 dst+=d;
                 if (*dst&bit)
                     c2+=2;
                 dst+=d;
                 if (*dst&bit)
                     c2+=4;
                 dst+=d;
                 if (*dst&bit)
                     c2+=8;
                 if (c2!=bkcolor.u1[0])
                     base->collision_cnt++;
                 break;
             case ROPB_XOR:
                 if (c & 1) *dst^=bit;
                 dst+=d;
                 if (c & 2) *dst^=bit;
                 dst+=d;
                 if (c & 4) *dst^=bit;
                 dst+=d;
                 if (c & 8) *dst^=bit;
                 break;
             case ROPB_OR:
                 if (c & 1) *dst|=bit;
                 dst+=d;
                 if (c & 2) *dst|=bit;
                 dst+=d;
                 if (c & 4) *dst|=bit;
                 dst+=d;
                 if (c & 8) *dst|=bit;
                 break;
             case ROPB_CLEAR_BITS:
                 if (c & 1) *dst&=not_bit;
                 dst+=d;
                 if (c & 2) *dst&=not_bit;
                 dst+=d;
                 if (c & 4) *dst&=not_bit;
                 dst+=d;
                 if (c & 8) *dst&=not_bit;
                 break;
         }
         break;
     case BMT_COLOR4_U1:
         dst=base->body+d;
         c=color.u1[0]&15;
         switch (color.u1[3]) {
             case ROPB_EQU:
             case ROPB_CLEAR_MASK_EQU:
             case ROPB_CLEAR_MASK_TRANSPARENT:
             case ROPB_TRANSPARENT:
                 *dst=c;
                 break;
             case ROPB_COLLISION:
                 if (*dst!=bkcolor.u1[0])
                     base->collision_cnt++;
                 break;
             case ROPB_XOR:
                 *dst^=c;
                 break;
             case ROPB_OR:
                 *dst|=c;
                 break;
             case ROPB_CLEAR_BITS:
                 *dst&=c^15;
                 break;
         }
         break;
     case BMT_MONO:
         c=color&0xFFFFFF;
         switch (color.u1[3]) {
             case ROPB_EQU:
             case ROPB_CLEAR_MASK_EQU:
             case ROPB_CLEAR_MASK_TRANSPARENT:
             case ROPB_TRANSPARENT:
                 AssignBit(base->body,d,c);
                 break;
             case ROPB_COLLISION:
                 if (c) {
                     if (bkcolor&0xFFFFFF)
                         base->collision_cnt+=Bt(base->body,d);
                     else
                         base->collision_cnt+=!Bt(base->body,d);
                 } else {
                     if (bkcolor&0xFFFFFF)
                         base->collision_cnt+=!Bt(base->body,d);
                     else
                         base->collision_cnt+=Bt(base->body,d);
                 }
                 break;
             case ROPB_XOR:
                 if (c)
                     Btc(base->body,d);
                 break;
             case ROPB_OR:
                 if (c)
                     Bts(base->body,d);
                 break;
             case ROPB_CLEAR_BITS:
                 if (c)
                     Btr(base->body,d);
                 break;
         }
         break;
 }
 if (base->mask) {
     base->mask->brush=base->brush;
     base->mask->color=WHITE;
     if (base->color.u1[3]==ROPB_CLEAR_MASK_EQU)
         base->mask->color=ROPB_EQU+BLACK;
     else if (base->color.u1[3]==ROPB_CLEAR_MASK_TRANSPARENT)
         base->mask->color=ROPB_TRANSPARENT+BLACK;
     else
         base->mask->color.u1[3]=base->color.u1[3];
     GrPlot0(base->mask,x,y);
 }
}

public I8 GrPeek0(GrBitMap *base,I8 x,I8 y)
{  //No clipping or transformation
 U8 d,c;
 U1 *src,bit;

 d=base->width_internal*(y+base->top_margin)+
     x+base->left_margin;
 switch (base->type) {
     case BMT_COLOR4:
         if (base->mask && !Bt(base->mask->body,d))
                 return MAX_I4;
         src=base->body+d>>3;
         bit=1<<(x&7);
         d=base->plane_size;
         c=0;
         if (*src & bit)
             c|=1;
         src+=d;
         if (*src & bit)
             c|=2;
         src+=d;
         if (*src & bit)
             c|=4;
         src+=d;
         if (*src & bit)
             c|=8;

         return c;
     case BMT_COLOR4_U1:
         if (base->mask && !Bt(base->mask->body,d))
                 return MAX_I4;
         src=base->body+d;
         return *src;
     case BMT_MONO:
         if (base->mask && !Bt(base->mask->body,d))
                 return MAX_I4;
         return Bt(base->body,d);
 }
}

#help_index "Graphics;Graphics/Bitmaps"

public BoolI8 GrBlot(GrBitMap *base,I8 my_x,I8 my_y,GrBitMap *img)
{  //Clipping but not transformation
 I8 x=my_x,y=my_y,reg i,i1,i2,i3,j,k,k1,kk,kk1,w1,h1,w2,h2,plane,plane1,reg bit_mask,reg
bit_shift,p,p1,dist;
 U1 reg *ptr;
 U2 reg *ptr1;
 I8 color,color2,reg color_byte,c,plane_size,plane_size1,plane_limit,plane_limit1;

 w1=x<0 ?-x:0;
 h1=y<0 ?-y:0;
 w2=img->width;
 h2=img->height;
 if (base->flags & BMF_SCREEN_BITMAP) {
     x+=base->win_tss->win_pixel_left;
     y+=base->win_tss->win_pixel_top;
 }
 if (base->flags & BMF_LOCATE_NEAREST) { //TODO:Untested
     dist=DistI8(x+img->width>>1,y+img->height>>1,base->cur_x,base->cur_y);
     if (dist<=base->nearest_dist) {
         base->nearest_grelem_num=base->cur_grelem_num;
         base->nearest_dist=dist;
     }
 }
 if (base->flags & BMF_SCREEN_BITMAP) {
     if (x+w1<0) w1=-x;
     if (x+w2>base->win_tss->win_pixel_right+1)
         w2=base->win_tss->win_pixel_right+1-x;

     if (y+h1<0) h1=-y;
     if (y+h2>base->win_tss->win_pixel_bottom+1)
         h2=base->win_tss->win_pixel_bottom+1-y;
 }
 x+=base->left_margin;
 y+=base->top_margin;
 if (x+w2>base->right_margin)
     w2=base->right_margin-x;
 if (y+h2>base->bottom_margin)
     h2=base->bottom_margin-y;
 if (w1<w2<=img->width && h1<h2<=img->height &&
         (!(base->flags & BMF_SCREEN_BITMAP) ||
         base->flags&BMF_ON_TOP ||
         (!IsPixelCovered(base->win_tss,x+w1-base->left_margin,y+h1-base->top_margin) &&
         !IsPixelCovered(base->win_tss,x+w2-base->left_margin,y+h2-base->top_margin)))) {
     if (base->flags & BMF_RECORD_EXTENTS) {
         if (x+w1<base->min_x) base->min_x=x+w1;
         if (x+w2-1>base->max_x) base->max_x=x+w2-1;
         if (y+h1<base->min_y) base->min_y=y+h1;
         if (y+h2-1>base->max_y) base->max_y=y+h2-1;
     }
     if (base->flags & BMF_DONT_DRAW)
         return TRUE;
     color=base->color;
     i1=(-w1)&7;
     if (i1>w2) i1=w2;
     i2=w2-w1-i1;
     if (i2<0)
         i2=0;
     else
         i2>>=3;
     i3=w2-w1-i2<<3-i1;
     bit_shift=x&7;
     bit_mask=-1-255<<bit_shift;
     switch (color.u1[3]) {
         case ROPB_COLLISION:
             plane_size=img->plane_size<<3;
             plane_size1=base->plane_size<<3;
             switch (base->type) {
                 case BMT_COLOR4:
                     plane_limit=plane_size*4;
                     plane_limit1=plane_size1*4;
                     break;
                 case BMT_MONO:
                     plane_limit=plane_size;
                     plane_limit1=plane_size1;
                     break;
             }
             color =base->bkcolor&0xFFFFFF;
             color2=img->bkcolor &0xFFFFFF;
             switch (img->type) {
                 case BMT_COLOR4:
                     k=h1*img->width_internal;
                     k1=(h1+y)*base->width_internal+x;
                     for (j=h2-h1;j;j--) {
                         for (i=w1;i<w2;i++) {
                             if (base->type==BMT_COLOR4_U1)
                                 c=base->body><(U1 *)[k1+i];
                             else {
                                 c=0;
                                 for (plane1=0,p=1;plane1<plane_limit1;
                                 plane1+=plane_size1,p<<=1)
                                     if (Bt(base->body,k1+i+plane1))
                                         c+=p;
                                 }
                             if (c!=color) {
                                 c=0;
                                 for (plane=0,p=1;plane<plane_limit;
                                 plane+=plane_size,p<<=1)
                                     if (Bt(img->body,k+i+plane))
                                         c+=p;
                                 if (c!=color2)
                                     base->collision_cnt++;
                             }
                         }
                         k+=img->width_internal;
                         k1+=base->width_internal;
                     }
                     break;
                 case BMT_COLOR4_U1:
                     k=h1*img->width_internal;
                     k1=(h1+y)*base->width_internal+x;
                     for (j=h2-h1;j;j--) {
                         for (i=w1;i<w2;i++) {
                             if (base->type==BMT_COLOR4_U1)
                                 c=base->body><(U1 *)[k1+i];
                             else {
                                 c=0;
                                 for (plane1=0,p=1;plane1<plane_limit1;
                                 plane1+=plane_size1,p<<=1)
                                     if (Bt(base->body,k1+i+plane1))
                                         c+=p;
                                 }
                             if (c!=color) {
                                 if (img->body><(U1 *)[k+i]!=color2)
                                     base->collision_cnt++;
                             }
                         }
                         k+=img->width_internal;
                         k1+=base->width_internal;
                     }
                     break;
                 case BMT_MONO:
                     k=h1*img->width_internal;
                     k1=(h1+y)*base->width_internal+x;
                     for (j=h2-h1;j;j--) {
                         for (i=w1;i<w2;i++) {
                             if (base->type==BMT_COLOR4_U1)
                                 c=base->body><(U1 *)[k1+i];
                             else {
                                 c=0;
                                 for (plane1=0,p=1;plane1<plane_limit1;
                                 plane1+=plane_size1,p<<=1)
                                     if (Bt(base->body,k1+i+plane1))
                                         c+=p;
                                 }
                             if (c!=color) {
                                 if (Bt(img->body,k+i)!=color2)
                                     base->collision_cnt++;
                             }
                         }
                         k+=img->width_internal;
                         k1+=base->width_internal;
                     }
                     break;
             }
             break;
         case ROPB_TRANSPARENT:
         case ROPB_CLEAR_MASK_TRANSPARENT:
             switch (img->type) {
                 case BMT_COLOR4:
                     plane_size=img->plane_size<<3;
                     plane_limit=plane_size*4;
                     color2=img->bkcolor &0xFFFFFF;
                     k=h1*img->width_internal;
                     for (j=h1;j<h2;j++) {
                         for (i=w1;i<w2;i++) {
                             c=0;
                             for (plane=0,p=1;plane<plane_limit;
                             plane+=plane_size,p<<=1)
                                 if (Bt(img->body,k+i+plane))
                                     c+=p;
                             if (c!=color2) {
                                 base->color=c;
                                 GrPlot0(base,x+i-base->left_margin,y+j-base->top_margin);
                             }
                         }
                         k+=img->width_internal;
                     }
                     base->color=color;
                     break;
                 case BMT_COLOR4_U1:
                     color2=img->bkcolor &0xFFFFFF;
                     k=h1*img->width_internal;
                     for (j=h1;j<h2;j++) {
                         for (i=w1;i<w2;i++) {
                             c=img->body><(U1 *)[k+i];
                             if (c!=color2) {
                                 base->color=c;
                                 GrPlot0(base,x+i-base->left_margin,y+j-base->top_margin);
                             }
                         }
                         k+=img->width_internal;
                     }
                     base->color=color;
                     break;
                 default:
                     goto here1;
             }
             break;
         default:
             here1:
         plane_size=img->plane_size<<3;
             plane_size1=base->plane_size<<3;
             switch (base->type) {
                 case BMT_COLOR4:
                     plane_limit=plane_size*4;
                     plane_limit1=plane_size1*4;
                     break;
                 case BMT_COLOR4_U1:
                     if (img->type==BMT_COLOR4)
                         plane_limit=plane_size*4;
                     else
                         plane_limit=plane_size;
                     break;
                 case BMT_MONO:
                     plane_limit=plane_size;
                     plane_limit1=plane_size1;
                     break;
             }
             if (base->type==BMT_COLOR4 ||base->type==BMT_COLOR4_U1 ||img->type==BMT_MONO) {
                 if (base->type==BMT_COLOR4_U1) {
                     switch (img->type) {
                         case BMT_COLOR4:
                             switch (color.u1[3]) {
                                 case ROPB_EQU:
                                 case ROPB_CLEAR_MASK_EQU:
                                     for (p1=0,p=1,plane=0;plane<plane_limit;
                                     plane+=plane_size,p<<=1,p1++) {
                                         kk=h1*img->width_internal+w1;
                                         kk1=(h1+y)*base->width_internal+x+w1;
                                         for (j=h2-h1;j;j--) {
                                             k=kk+plane;
                                             ptr=img->body;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--)
                                                 AssignBit(ptr1><(U1 *)++,p1,Bt(ptr,k++));
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         }
                                     break;
                                 case ROPB_XOR:
                                     for (p1=0,p=1,plane=0;plane<plane_limit;
                                     plane+=plane_size,p<<=1,p1++) {
                                         kk=h1*img->width_internal+w1;
                                         kk1=(h1+y)*base->width_internal+x+w1;
                                         for (j=h2-h1;j;j--) {
                                             k=kk+plane;
                                             ptr=img->body;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--,ptr1><(U1 *)++)
                                                 if (Bt(ptr,k++))
                                                     Btc(ptr1,p1);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         }
                                     break;
                                 case ROPB_OR:
                                     for (p1=0,p=1,plane=0;plane<plane_limit;
                                     plane+=plane_size,p<<=1,p1++) {
                                         kk=h1*img->width_internal+w1;
                                         kk1=(h1+y)*base->width_internal+x+w1;
                                         for (j=h2-h1;j;j--) {
                                             k=kk+plane;
                                             ptr=img->body;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--,ptr1><(U1 *)++)
                                                 if (Bt(ptr,k++))
                                                     Bts(ptr1,p1);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         }
                                     break;
                                 case ROPB_CLEAR_BITS:
                                     for (p1=0,p=1,plane=0;plane<plane_limit;
                                     plane+=plane_size,p<<=1,p1++) {
                                         kk=h1*img->width_internal+w1;
                                         kk1=(h1+y)*base->width_internal+x+w1;
                                         for (j=h2-h1;j;j--) {
                                             k=kk+plane;
                                             ptr=img->body;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--,ptr1><(U1 *)++)
                                                 if (Bt(ptr,k++))
                                                     Btr(ptr1,p1);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         }
                                     break;
                             }
                             break;
                         case BMT_COLOR4_U1:
                             for (p1=0,p=1,plane=0;plane<plane_limit;
                             plane+=plane_size,p<<=1,p1++) {
                                 kk=h1*img->width_internal+w1;
                                 kk1=(h1+y)*base->width_internal+x+w1;
                                 switch (color.u1[3]) {
                                     case ROPB_EQU:
                                     case ROPB_CLEAR_MASK_EQU:
                                         for (j=h2-h1;j;j--) {
                                             ptr=img->body+kk;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--)
                                                 *ptr1><(U1 *)++=*ptr++;
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_XOR:
                                         for (j=h2-h1;j;j--) {
                                             ptr=img->body+kk;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--)
                                                 *ptr1><(U1 *)++^=*ptr++;
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_OR:
                                         for (j=h2-h1;j;j--) {
                                             ptr=img->body+kk;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--)
                                                 *ptr1><(U1 *)++|=*ptr++;
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_CLEAR_BITS:
                                         for (j=h2-h1;j;j--) {
                                             ptr=img->body+kk;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--)
                                                 *ptr1><(U1 *)++&=~*ptr++;
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                 }
                             }
                             break;
                         case BMT_MONO:
                             for (p1=0,p=1,plane=0;plane<plane_limit;
                             plane+=plane_size,p<<=1,p1++) {
                                 kk=h1*img->width_internal+w1;
                                 kk1=(h1+y)*base->width_internal+x+w1;
                                 switch (color.u1[3]) {
                                     case ROPB_EQU:
                                     case ROPB_CLEAR_MASK_EQU:
                                         for (j=h2-h1;j;j--) {
                                             k=kk;
                                             ptr=img->body;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--)
                                                 if (Bt(ptr,k++))
                                                     *ptr1><(U1 *)++=color.u1[0];
                                                 else
                                                     *ptr1><(U1 *)++=0;
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_CLEAR_MASK_TRANSPARENT:
                                     case ROPB_TRANSPARENT:
                                         for (j=h2-h1;j;j--) {
                                             k=kk;
                                             ptr=img->body;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--,ptr1><(U1 *)++)
                                                 if (Bt(ptr,k++))
                                                     *ptr1><(U1 *)=color.u1[0];
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_XOR:
                                         for (j=h2-h1;j;j--) {
                                             k=kk;
                                             ptr=img->body;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--,ptr1><(U1 *)++)
                                                 if (Bt(ptr,k++))
                                                     *ptr1><(U1 *)^=color.u1[0];
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_OR:
                                         for (j=h2-h1;j;j--) {
                                             k=kk;
                                             ptr=img->body;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--,ptr1><(U1 *)++)
                                                 if (Bt(ptr,k++))
                                                     *ptr1><(U1 *)|=color.u1[0];
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_CLEAR_BITS:
                                         for (j=h2-h1;j;j--) {
                                             k=kk;
                                             ptr=img->body;
                                             ptr1=base->body+kk1;
                                             for (i=w2-w1;i;i--,ptr1><(U1 *)++)
                                                 if (Bt(ptr,k++))
                                                     *ptr1><(U1 *)&=~color.u1[0];
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                 }
                                 break;
                             }
                             break;
                     }
                 } else {
                     for (p1=0,p=1,plane=0,plane1=0;plane<plane_limit;
                     plane+=plane_size,plane1+=plane_size1,p<<=1,p1++) {
                         if (Bt(&color,p1))
                             color_byte=255;
                         else
                             color_byte=0;
                         kk=h1*img->width_internal+w1;
                         kk1=(h1+y)*base->width_internal+x+w1;
                         switch (img->type) {
                             case BMT_COLOR4:
                                 switch (color.u1[3]) {
                                     case ROPB_EQU:
                                     case ROPB_CLEAR_MASK_EQU:
                                         for (j=h2-h1;j;j--) {
                                             k=kk+plane;
                                             k1=kk1+plane1;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             for (i=0;i<i1;i++,k1++)
                                                 AssignBit(ptr1,k1,Bt(ptr,k++));
                                             ptr+=k>>3;
                                             ptr1><(U1 *)+=k1>>3;
                                             for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                                 *ptr1=*ptr1 & bit_mask | *ptr++<<bit_shift;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             k+=i2<<3;
                                             k1+=i2<<3;
                                             for (i=0;i<i3;i++,k1++)
                                                 AssignBit(ptr1,k1,Bt(ptr,k++));
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_XOR:
                                         for (j=h2-h1;j;j--) {
                                             k=kk+plane;
                                             k1=kk1+plane1;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             for (i=0;i<i1;i++,k1++)
                                                 if (Bt(ptr,k++))
                                                     Btc(ptr1,k1);
                                             ptr+=k>>3;
                                             ptr1><(U1 *)+=k1>>3;
                                             for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                                 *ptr1^=*ptr++<<bit_shift;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             k+=i2<<3;
                                             k1+=i2<<3;
                                             for (i=0;i<i3;i++,k1++)
                                                 if (Bt(ptr,k++))
                                                     Btc(ptr1,k1);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_OR:
                                         for (j=h2-h1;j;j--) {
                                             k=kk+plane;
                                             k1=kk1+plane1;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             for (i=0;i<i1;i++,k1++)
                                                 if (Bt(ptr,k++))
                                                     Bts(ptr1,k1);
                                             ptr+=k>>3;
                                             ptr1><(U1 *)+=k1>>3;
                                             for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                                 *ptr1|=*ptr++<<bit_shift;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             k+=i2<<3;
                                             k1+=i2<<3;
                                             for (i=0;i<i3;i++,k1++)
                                                 if (Bt(ptr,k++))
                                                     Bts(ptr1,k1);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_CLEAR_BITS:
                                         for (j=h2-h1;j;j--) {
                                             k=kk+plane;
                                             k1=kk1+plane1;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             for (i=0;i<i1;i++,k1++)
                                                 if (Bt(ptr,k++))
                                                     Btr(ptr1,k1);
                                             ptr+=k>>3;
                                             ptr1><(U1 *)+=k1>>3;
                                             for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                                 *ptr1= *ptr1 & (bit_mask | ~(*ptr++<<bit_shift));
                                             ptr=img->body;
                                             ptr1=base->body;
                                             k+=i2<<3;
                                             k1+=i2<<3;
                                             for (i=0;i<i3;i++,k1++)
                                                 if (Bt(ptr,k++))
                                                     Btr(ptr1,k1);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                 }
                                 break;
                             case BMT_COLOR4_U1:
                                 switch (color.u1[3]) {
                                     case ROPB_EQU:
                                     case ROPB_CLEAR_MASK_EQU:
                                         for (j=h2-h1;j;j--) {
                                             k1=kk1+plane1;
                                             ptr=img->body+kk;
                                             ptr1=base->body;
                                             for (i=w2-w1;i;i--)
                                                 AssignBit(ptr1,k1++,*ptr++&p);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_XOR:
                                         for (j=h2-h1;j;j--) {
                                             k1=kk1+plane1;
                                             ptr=img->body+kk;
                                             ptr1=base->body;
                                             for (i=w2-w1;i;i--,k1++)
                                                 if (*ptr++&p)
                                                     Btc(ptr1,k1);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_OR:
                                         for (j=h2-h1;j;j--) {
                                             k1=kk1+plane1;
                                             ptr=img->body+kk;
                                             ptr1=base->body;
                                             for (i=w2-w1;i;i--,k1++)
                                                 if (*ptr++&p)
                                                     Bts(ptr1,k1);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_CLEAR_BITS:
                                         for (j=h2-h1;j;j--) {
                                             k1=kk1+plane1;
                                             ptr=img->body+kk;
                                             ptr1=base->body;
                                             for (i=w2-w1;i;i--,k1++)
                                                 if (*ptr++&p)
                                                     Btr(ptr1,k1);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                 }
                                 break;
                             case BMT_MONO:
                                 switch (color.u1[3]) {
                                     case ROPB_EQU:
                                     case ROPB_CLEAR_MASK_EQU:
                                         for (j=h2-h1;j;j--) {
                                             k=kk;
                                             k1=kk1+plane1;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             for (i=0;i<i1;i++,k1++)
                                                 AssignBit(ptr1,k1,color_byte&&Bt(ptr,k++));
                                             ptr+=k>>3;
                                             ptr1><(U1 *)+=k1>>3;
                                             for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                                 *ptr1=*ptr1 & bit_mask | (*ptr++ &
color_byte)<<bit_shift;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             k+=i2<<3;
                                             k1+=i2<<3;
                                             for (i=0;i<i3;i++,k1++)
                                                 AssignBit(ptr1,k1,color_byte && Bt(ptr,k++));
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_CLEAR_MASK_TRANSPARENT:
                                     case ROPB_TRANSPARENT:
                                         for (j=h2-h1;j;j--) {
                                             k=kk;
                                             k1=kk1+plane1;
                                             ptr=img->body;
                                             ptr1=base->body;
                                             for (i=0;i<i1;i++,k1++)
                                                 if (Bt(ptr,k++))
                                                     AssignBit(ptr1,k1,color_byte);
                                             ptr+=k>>3;
                                             ptr1><(U1 *)+=k1>>3;
                                             for (i=0;i<i2;i++,ptr1><(U1 *)++) {
                                                 bit_mask=~(*ptr<<bit_shift);
                                                 *ptr1=*ptr1 & bit_mask | (*ptr++ &
color_byte)<<bit_shift;
                                             }
                                             ptr=img->body;
                                             ptr1=base->body;
                                             k+=i2<<3;
                                             k1+=i2<<3;
                                             for (i=0;i<i3;i++,k1++)
                                                 if (Bt(ptr,k++))
                                                     AssignBit(ptr1,k1,color_byte);
                                             kk+=img->width_internal;
                                             kk1+=base->width_internal;
                                         }
                                         break;
                                     case ROPB_XOR:
                                         if (color_byte) {
                                             for (j=h2-h1;j;j--) {
                                                 k=kk;
                                                 k1=kk1+plane1;
                                                 ptr=img->body;
                                                 ptr1=base->body;
                                                 for (i=0;i<i1;i++,k1++)
                                                     if (Bt(ptr,k++))
                                                         Btc(ptr1,k1);
                                                 ptr+=k>>3;
                                                 ptr1><(U1 *)+=k1>>3;
                                                 for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                                     *ptr1^=*ptr++<<bit_shift;
                                                 ptr=img->body;
                                                 ptr1=base->body;
                                                 k+=i2<<3;
                                                 k1+=i2<<3;
                                                 for (i=0;i<i3;i++,k1++)
                                                     if (Bt(ptr,k++))
                                                         Btc(ptr1,k1);
                                                 kk+=img->width_internal;
                                                 kk1+=base->width_internal;
                                             }
                                             }
                                         break;
                                     case ROPB_OR:
                                         if (color_byte) {
                                             for (j=h2-h1;j;j--) {
                                                 k=kk;
                                                 k1=kk1+plane1;
                                                 ptr=img->body;
                                                 ptr1=base->body;
                                                 for (i=0;i<i1;i++,k1++)
                                                     if (Bt(ptr,k++))
                                                         Bts(ptr1,k1);
                                                 ptr+=k>>3;
                                                 ptr1><(U1 *)+=k1>>3;
                                                 for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                                     *ptr1|=*ptr++<<bit_shift;
                                                 ptr=img->body;
                                                 ptr1=base->body;
                                                 k+=i2<<3;
                                                 k1+=i2<<3;
                                                 for (i=0;i<i3;i++,k1++)
                                                     if (Bt(ptr,k++))
                                                         Bts(ptr1,k1);
                                                 kk+=img->width_internal;
                                                 kk1+=base->width_internal;
                                             }
                                             }
                                         break;
                                     case ROPB_CLEAR_BITS:
                                         if (color_byte) {
                                             for (j=h2-h1;j;j--) {
                                                 k=kk;
                                                 k1=kk1+plane1;
                                                 ptr=img->body;
                                                 ptr1=base->body;
                                                 for (i=0;i<i1;i++,k1++)
                                                     if (Bt(ptr,k++))
                                                         Btr(ptr1,k1);
                                                 ptr+=k>>3;
                                                 ptr1><(U1 *)+=k1>>3;
                                                 for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                                     *ptr1= *ptr1 & (bit_mask |
~(*ptr++<<bit_shift));
                                                 ptr=img->body;
                                                 ptr1=base->body;
                                                 k+=i2<<3;
                                                 k1+=i2<<3;
                                                 for (i=0;i<i3;i++,k1++)
                                                     if (Bt(ptr,k++))
                                                         Btr(ptr1,k1);
                                                 kk+=img->width_internal;
                                                 kk1+=base->width_internal;
                                             }
                                             }
                                         break;
                                 }
                                 break;
                         }
                     }
                     }
             } else {
                 switch (img->type) {
                     case BMT_COLOR4:
                         plane_limit=plane_size*4;
                         k=h1*img->width_internal;
                         kk1=(h1+y)*base->width_internal+x;
                         for (j=h2-h1;j;j--) {
                             k1=kk1+w1;
                             for (i=w1;i<w2;i++) {
                                 c=0;
                                 for (plane=0,p=1;plane<plane_limit;
                                 plane+=plane_size,p<<=1)
                                     if (Bt(img->body,k+i+plane))
                                         c+=p;
                                 if (c!=img->bkcolor) {
                                     if (color.u1[3]==ROPB_CLEAR_BITS)
                                         Btr(base->body,k1);
                                     else
                                         Bts(base->body,k1);
                                 }
                                 k1++;
                             }
                             k+=img->width_internal;
                             kk1+=base->width_internal;
                         }
                         break;
                     case BMT_COLOR4_U1:
                         k=h1*img->width_internal;
                         kk1=(h1+y)*base->width_internal+x;
                         for (j=h2-h1;j;j--) {
                             k1=kk1+w1;
                             for (i=w1;i<w2;i++) {
                                 ptr=img->body+k+i;
                                 if (*ptr!=img->bkcolor) {
                                     if (color.u1[3]==ROPB_CLEAR_BITS)
                                         Btr(base->body,k1);
                                     else
                                         Bts(base->body,k1);
                                 }
                                 k1++;
                             }
                             k+=img->width_internal;
                             kk1+=base->width_internal;
                         }
                         break;
                 }
             }
             break;
     }
     if (base->mask) {
         if (color.u1[3]!=ROPB_COLLISION &&
                 (!(color.u1[3]==ROPB_TRANSPARENT ||
                 color.u1[3]==ROPB_CLEAR_MASK_TRANSPARENT) ||
                 img->type==BMT_MONO)) {
             base->mask->brush=base->brush;
             base->mask->color=WHITE;
             if (base->color.u1[3]==ROPB_CLEAR_MASK_EQU)
                 base->mask->color=ROPB_EQU+BLACK;
             else if (base->color.u1[3]==ROPB_CLEAR_MASK_TRANSPARENT)
                 base->mask->color=ROPB_TRANSPARENT+BLACK;
             else
                 base->mask->color.u1[3]=base->color.u1[3];
             GrBlot(base->mask,my_x,my_y,img);
         }
     }
     return TRUE;
 } else
     return FALSE;
}

public GrBitMap *GrExtractBitMap(GrBitMap *b,I8 x1,I8 y1,I8 x2,I8 y2)
{
 I8 i;
 GrBitMap *result;
 if (x1>x2) {i=x1; x1=x2; x2=i;}
 if (y1>y2) {i=y1; y1=y2; y2=i;}
 if (b->flags & BMF_SCREEN_BITMAP) {
     x1+=b->win_tss->win_pixel_left;
     y1+=b->win_tss->win_pixel_top;
     x2+=b->win_tss->win_pixel_left;
     y2+=b->win_tss->win_pixel_top;
 }
 result=GrNew(b->type,x2-x1+1,y2-y1+1);
 GrBlot(result,-x1,-y1,b);
 return result;
}

#help_index "Graphics"

public BoolI8 GrPutS(GrBitMap *base,I8 my_x,I8 my_y,U1 *my_s)
{  //Clipping but not transformation
 U1 *s=my_s;
 I8 x=my_x,y=my_y,len=StrLen(s),ch,reg i,i1,i2,i3,j,k1,kk1,w1,h1,w2,h2,plane1,reg bit_mask,reg
bit_shift,p,p1,dist,l,l1;
 U1 reg *ptr,*font_ptr,*s1;
 U2 reg *ptr1,*ptr2;
 I8 color,reg color_byte,c,plane_size1,plane_limit1;

 if (!my_s) return;

 w1=x<0 ?-x:0;
 h1=y<0 ?-y:0;
 w2=len*FONT_WIDTH;
 h2=FONT_HEIGHT;

 if (base->flags & BMF_SCREEN_BITMAP) {
     x+=base->win_tss->win_pixel_left;
     y+=base->win_tss->win_pixel_top;
 }
 if (base->flags & BMF_LOCATE_NEAREST) { //TODO:Untested
     dist=DistI8(x+w2>>1,y+h2>>1,base->cur_x,base->cur_y);
     if (dist<=base->nearest_dist) {
         base->nearest_grelem_num=base->cur_grelem_num;
         base->nearest_dist=dist;
     }
 }
 if (base->flags & BMF_SCREEN_BITMAP) {
     if (x+w1<0) w1=-x;
     if (x+w2>base->win_tss->win_pixel_right+1)
         w2=base->win_tss->win_pixel_right+1-x;

     if (y+h1<0) h1=-y;
     if (y+h2>base->win_tss->win_pixel_bottom+1)
         h2=base->win_tss->win_pixel_bottom+1-y;
 }
 x+=base->left_margin;
 y+=base->top_margin;
 if (x+w2>base->right_margin)
     w2=base->right_margin-x;
 if (y+h2>base->bottom_margin)
     h2=base->bottom_margin-y;
 if (w1<w2<=len*FONT_WIDTH && h1<h2<=FONT_HEIGHT &&
         (!(base->flags & BMF_SCREEN_BITMAP) ||
         base->flags&BMF_ON_TOP ||
         (!IsPixelCovered(base->win_tss,x+w1-base->left_margin,y+h1-base->top_margin) &&
         !IsPixelCovered(base->win_tss,x+w2-base->left_margin,y+h2-base->top_margin)))) {
     if (base->flags & BMF_RECORD_EXTENTS) {
         if (x+w1<base->min_x) base->min_x=x+w1;
         if (x+w2-1>base->max_x) base->max_x=x+w2-1;
         if (y+h1<base->min_y) base->min_y=y+h1;
         if (y+h2-1>base->max_y) base->max_y=y+h2-1;
     }
     if (base->flags & BMF_DONT_DRAW)
         return TRUE;
     color=base->color;
     plane_size1=base->plane_size<<3;
     switch (base->type) {
         case BMT_COLOR4:
             plane_limit1=plane_size1*4;
             break;
         case BMT_MONO:
             plane_limit1=plane_size1;
             break;
     }
     i1=(-w1)&7;
     if (i1>w2) i1=w2;
     i2=w2-w1-i1;
     if (i2<0)
         i2=0;
     else
         i2>>=3;
     i3=w2-w1-i2<<3-i1;
     bit_shift=x&7;
     bit_mask=-1-255<<bit_shift;
     s+=w1/FONT_WIDTH;
     l=w1%FONT_WIDTH;
     if (color.u1[3]==ROPB_COLLISION) {
         color =base->bkcolor&0xFFFFFF;
         ch=*s++;
         font_ptr=&grfont[(FONT_WIDTH*(FONT_HEIGHT*ch+h1))>>3];
         for (i=w1;i<w2;i++) {
             k1=(h1+y)*base->width_internal+x;
             ptr=font_ptr;
             for (j=h2-h1;j;j--) {
                 if (base->type==BMT_COLOR4_U1)
                     c=base->body><(U1 *)[k1+i];
                 else {
                     c=0;
                     for (plane1=0,p=1;plane1<plane_limit1;
                     plane1+=plane_size1,p<<=1)
                         if (Bt(base->body,k1+i+plane1))
                             c+=p;
                     }
                 if (c!=color) {
                     if (Bt(ptr,l))
                         base->collision_cnt++;
                 }
                 k1+=base->width_internal;
                 ptr++;
             }
             if (++l==FONT_WIDTH) {
                 ch=*s++;
                 font_ptr=&grfont[(FONT_WIDTH*(FONT_HEIGHT*ch+h1))>>3];
                 l=0;
             }
         }
         } else {
         if (base->type==BMT_COLOR4_U1) {
             s1=s;
             l1=l;
             ptr2=base->body;
             kk1=(h1+y)*base->width_internal+x+w1;
             ch=*s1++;
             font_ptr=&grfont[(FONT_WIDTH*(FONT_HEIGHT*ch+h1))>>3];
             for (i=w2-w1;i;i--,kk1++) {
                 k1=kk1;
                 ptr=font_ptr;
                 switch (color.u1[3]) {
                     case ROPB_EQU:
                     case ROPB_CLEAR_MASK_EQU:
                     case ROPB_CLEAR_MASK_TRANSPARENT:
                     case ROPB_TRANSPARENT:
                         for (j=h2-h1;j;j--) {
                             if (Bt(ptr++,l1))
                                 ptr2><(U1 *)[k1]=color.u1[0];
                             k1+=base->width_internal;
                         }
                         break;
                     case ROPB_XOR:
                         for (j=h2-h1;j;j--) {
                             if (Bt(ptr++,l1))
                                 ptr2><(U1 *)[k1]^=color.u1[0];
                             k1+=base->width_internal;
                         }
                         break;
                     case ROPB_OR:
                         for (j=h2-h1;j;j--) {
                             if (Bt(ptr++,l1))
                                 ptr2><(U1 *)[k1]|=color.u1[0];
                             k1+=base->width_internal;
                         }
                         break;
                     case ROPB_CLEAR_BITS:
                         for (j=h2-h1;j;j--) {
                             if (Bt(ptr++,l1))
                                 ptr2><(U1 *)[k1]&=~color.u1[0];
                             k1+=base->width_internal;
                         }
                         break;
                 }
                 if (++l1==FONT_WIDTH) {
                     ch=*s1++;
                     font_ptr=&grfont[(FONT_WIDTH*(FONT_HEIGHT*ch+h1))>>3];
                     l1=0;
                 }
             }
             } else {
             for (p1=0,plane1=0;plane1<plane_limit1;plane1+=plane_size1,p1++) {
                 s1=s;
                 l1=l;
                 if (Bt(&color,p1))
                     color_byte=255;
                 else
                     color_byte=0;
                 ptr2=base->body+plane1>>3;
                 kk1=(h1+y)*base->width_internal+x+w1;
                 ch=*s1++;
                 font_ptr=&grfont[(FONT_WIDTH*(FONT_HEIGHT*ch+h1))>>3];
                 for (i=0;i<i1;i++) {
                     k1=kk1;
                     ptr=font_ptr;
                     switch (color.u1[3]) {
                         case ROPB_EQU:
                         case ROPB_CLEAR_MASK_EQU:
                         case ROPB_CLEAR_MASK_TRANSPARENT:
                         case ROPB_TRANSPARENT:
                             for (j=h2-h1;j;j--) {
                                 if (Bt(ptr++,l1))
                                     AssignBit(ptr2,k1,color_byte);
                                 k1+=base->width_internal;
                             }
                             break;
                         case ROPB_XOR:
                             if (color_byte)
                                 for (j=h2-h1;j;j--) {
                                     if (Bt(ptr++,l1))
                                         Btc(ptr2,k1);
                                     k1+=base->width_internal;
                                 }
                             break;
                         case ROPB_OR:
                             if (color_byte)
                                 for (j=h2-h1;j;j--) {
                                     if (Bt(ptr++,l1))
                                         Bts(ptr2,k1);
                                     k1+=base->width_internal;
                                 }
                             break;
                         case ROPB_CLEAR_BITS:
                             if (color_byte)
                                 for (j=h2-h1;j;j--) {
                                     if (Bt(ptr++,l1))
                                         Btr(ptr2,k1);
                                     k1+=base->width_internal;
                                 }
                             break;
                     }
                     if (++l1==FONT_WIDTH) {
                         ch=*s1++;
                         font_ptr=&grfont[(FONT_WIDTH*(FONT_HEIGHT*ch+h1))>>3];
                         l1=0;
                     }
                 }
                 kk1+=i1;
                 ptr2><(U1 *)+=kk1>>3;
                 for (i=0;i<i2;i++) {
                     ptr1=ptr2;
                     ptr=font_ptr;
                     switch (color.u1[3]) {
                         case ROPB_EQU:
                         case ROPB_CLEAR_MASK_EQU:
                         case ROPB_CLEAR_MASK_TRANSPARENT:
                         case ROPB_TRANSPARENT:
                             for (j=h2-h1;j;j--) {
                                 bit_mask=~(*ptr<<bit_shift);
                                 *ptr1=*ptr1 & bit_mask | (*ptr++ & color_byte)<<bit_shift;
                                 ptr1><(U1 *)+=base->width_internal>>3;
                             }
                             break;
                         case ROPB_XOR:
                             if (color_byte)
                                 for (j=h2-h1;j;j--) {
                                     *ptr1^=*ptr++<<bit_shift;
                                     ptr1><(U1 *)+=base->width_internal>>3;
                                 }
                             break;
                         case ROPB_OR:
                             if (color_byte)
                                 for (j=h2-h1;j;j--) {
                                     *ptr1|=*ptr++<<bit_shift;
                                     ptr1><(U1 *)+=base->width_internal>>3;
                                 }
                             break;
                         case ROPB_CLEAR_BITS:
                             if (color_byte)
                                 for (j=h2-h1;j;j--) {
                                     *ptr1= *ptr1 & (bit_mask | ~(*ptr++<<bit_shift));
                                     ptr1><(U1 *)+=base->width_internal>>3;
                                 }
                             break;
                     }
                     ptr2><(U1 *)++;
                     ch=*s1++;
                     font_ptr=&grfont[(FONT_WIDTH*(FONT_HEIGHT*ch+h1))>>3];
                 }
                 kk1+=i2<<3;
                 ptr1=base->body+plane1>>3;
                 for (i=0;i<i3;i++) {
                     ptr=font_ptr;
                     k1=kk1+i;
                     switch (color.u1[3]) {
                         case ROPB_EQU:
                         case ROPB_CLEAR_MASK_EQU:
                         case ROPB_CLEAR_MASK_TRANSPARENT:
                         case ROPB_TRANSPARENT:
                             for (j=h2-h1;j;j--) {
                                 if (Bt(ptr++,l1))
                                     AssignBit(ptr1,k1,color_byte);
                                 k1+=base->width_internal;
                             }
                             break;
                         case ROPB_XOR:
                             if (color_byte)
                                 for (j=h2-h1;j;j--) {
                                     if (Bt(ptr++,l1))
                                         Btc(ptr1,k1);
                                     k1+=base->width_internal;
                                 }
                             break;
                         case ROPB_OR:
                             if (color_byte)
                                 for (j=h2-h1;j;j--) {
                                     if (Bt(ptr++,l1))
                                         Bts(ptr1,k1);
                                     k1+=base->width_internal;
                                 }
                             break;
                         case ROPB_CLEAR_BITS:
                             if (color_byte)
                                 for (j=h2-h1;j;j--) {
                                     if (Bt(ptr++,l1))
                                         Btr(ptr1,k1);
                                     k1+=base->width_internal;
                                 }
                             break;
                     }
                     if (++l1==FONT_WIDTH) {
                         ch=*s1++;
                         font_ptr=&grfont[(FONT_WIDTH*(FONT_HEIGHT*ch+h1))>>3];
                         l1=0;
                     }
                 }
                 }
             }
     }
     if (base->mask) {
         base->mask->brush=base->brush;
         base->mask->color=WHITE;
         if (base->color.u1[3]==ROPB_CLEAR_MASK_EQU)
             base->mask->color=ROPB_EQU+BLACK;
         else if (base->color.u1[3]==ROPB_CLEAR_MASK_TRANSPARENT)
             base->mask->color=ROPB_TRANSPARENT+BLACK;
         else
             base->mask->color.u1[3]=base->color.u1[3];
         GrPutS(base->mask,my_x,my_y,my_s);
     }
     return TRUE;
 } else
     return FALSE;
}

public BoolI8 GrVPutS(GrBitMap *base,I8 my_x,I8 my_y,U1 *my_s)
{ //Vertical text
 I1 buf[2];
 BoolI1 result=FALSE,first=TRUE;
 buf[1]=0;
 while (buf[0]=*my_s++) {
     if (first) {
         result=GrPutS(base,my_x,my_y,buf);
         first=FALSE;
     } else
         GrPutS(base,my_x,my_y,buf);
     my_y+=FONT_HEIGHT;
 }
 return result;
}

public void GrPrintF(GrBitMap *base,I8 x,I8 y,I1 *fmt,...)
{
 I1 *buf=SPrintFJoin(NULL,fmt,argc,argv);
 GrPutS(base,x,y,buf);
 Free(buf);
}

public void GrVPrintF(GrBitMap *base,I8 x,I8 y,I1 *fmt,...)
{ //Vertical text
 I1 *buf=SPrintFJoin(NULL,fmt,argc,argv);
 GrVPutS(base,x,y,buf);
 Free(buf);
}

public BoolI8 GrBox(GrBitMap *base,I8 my_x,I8 my_y,I8 w,I8 h)
{  //Clipping but not transformation
 I8 x=my_x,y=my_y;
 I8 i,i1,i2,i3,j,k1,kk1,w1,h1,w2,h2,plane1,bit_mask,bit_shift,p,p1,dist;
 U2 *ptr1;
 I8 color,color_byte,c,plane_size1,plane_limit1;

 w1=x<0 ?-x:0;
 h1=y<0 ?-y:0;
 w2=w;
 h2=h;

 if (base->flags & BMF_SCREEN_BITMAP) {
     x+=base->win_tss->win_pixel_left;
     y+=base->win_tss->win_pixel_top;
 }
 if (base->flags & BMF_LOCATE_NEAREST) { //TODO:Untested
     if (base->cur_x>=x && base->cur_y>=y &&
             base->cur_x<=x+w && base->cur_y<=y+h) {
         base->nearest_grelem_num=base->cur_grelem_num;
         base->nearest_dist=0;
     } else {
         dist=DistI8(x+w>>1,y+h>>1,base->cur_x,base->cur_y);
         if (dist<=base->nearest_dist) {
             base->nearest_grelem_num=base->cur_grelem_num;
             base->nearest_dist=dist;
         }
     }
 }
 if (base->flags & BMF_SCREEN_BITMAP) {
     if (x+w1<0) w1=-x;
     if (x+w2>base->win_tss->win_pixel_right+1)
         w2=base->win_tss->win_pixel_right+1-x;

     if (y+h1<0) h1=-y;
     if (y+h2>base->win_tss->win_pixel_bottom+1)
         h2=base->win_tss->win_pixel_bottom+1-y;
 }
 x+=base->left_margin;
 y+=base->top_margin;
 if (x+w2>base->right_margin)
     w2=base->right_margin-x;
 if (y+h2>base->bottom_margin)
     h2=base->bottom_margin-y;
 if (w1<w2<=w && h1<h2<=h &&
         (!(base->flags & BMF_SCREEN_BITMAP) ||
         base->flags&BMF_ON_TOP ||
         (!IsPixelCovered(base->win_tss,x+w1-base->left_margin,y+h1-base->top_margin) &&
         !IsPixelCovered(base->win_tss,x+w2-base->left_margin,y+h2-base->top_margin)))) {
     if (base->flags & BMF_RECORD_EXTENTS) {
         if (x+w1<base->min_x) base->min_x=x+w1;
         if (x+w2-1>base->max_x) base->max_x=x+w2-1;
         if (y+h1<base->min_y) base->min_y=y+h1;
         if (y+h2-1>base->max_y) base->max_y=y+h2-1;
     }
     if (base->flags & BMF_DONT_DRAW)
         return TRUE;
     color=base->color;
     plane_size1=base->plane_size<<3;
     switch (base->type) {
         case BMT_COLOR4:
             plane_limit1=plane_size1*4;
             break;
         case BMT_COLOR4_U1:
         case BMT_MONO:
             plane_limit1=plane_size1;
             break;
     }
     i1=(-w1)&7;
     if (i1>w2) i1=w2;
     i2=w2-w1-i1;
     if (i2<0)
         i2=0;
     else
         i2>>=3;
     i3=w2-w1-i2<<3-i1;
     bit_shift=x&7;
     bit_mask=-1-255<<bit_shift;
     if (color.u1[3]==ROPB_COLLISION) {
         color =base->bkcolor&0xFFFFFF;
         k1=(h1+y)*base->width_internal+x;
         for (j=h2-h1;j;j--) {
             for (i=w1;i<w2;i++) {
                 if (base->type==BMT_COLOR4_U1)
                     c=base->body><(U1 *)[k1+i];
                 else {
                     c=0;
                     for (plane1=0,p=1;plane1<plane_limit1;
                     plane1+=plane_size1,p<<=1)
                         if (Bt(base->body,k1+i+plane1))
                             c+=p;
                     }
                 if (c!=color)
                     base->collision_cnt++;
             }
             k1+=base->width_internal;
         }
         } else if (base->type==BMT_COLOR4_U1) {
         kk1=(h1+y)*base->width_internal+x+w1;
         for (j=h2-h1;j;j--) {
             ptr1=base->body><(U1 *)+kk1;
             switch (color.u1[3]) {
                 case ROPB_EQU:
                 case ROPB_CLEAR_MASK_EQU:
                 case ROPB_CLEAR_MASK_TRANSPARENT:
                 case ROPB_TRANSPARENT:
                     for (i=w2-w1;i;i--)
                         *ptr1><(U1 *)++=color.u1[0];
                     break;
                 case ROPB_XOR:
                     for (i=w2-w1;i;i--)
                         *ptr1><(U1 *)++^=color.u1[0];
                     break;
                 case ROPB_OR:
                     for (i=w2-w1;i;i--)
                         *ptr1><(U1 *)++|=color.u1[0];
                     break;
                 case ROPB_CLEAR_BITS:
                     for (i=w2-w1;i;i--)
                         *ptr1><(U1 *)++&=~color.u1[0];
                     break;
             }
             kk1+=base->width_internal;
         }
         } else
         for (p1=0,plane1=0;plane1<plane_limit1;
         plane1+=plane_size1,p1++) {
             if (Bt(&color,p1))
                 color_byte=255<<bit_shift;
             else
                 color_byte=0;
             kk1=(h1+y)*base->width_internal+x+w1+plane1;
             switch (color.u1[3]) {
                 case ROPB_EQU:
                 case ROPB_CLEAR_MASK_EQU:
                 case ROPB_CLEAR_MASK_TRANSPARENT:
                 case ROPB_TRANSPARENT:
                     for (j=h2-h1;j;j--) {
                         k1=kk1;
                         for (i=0;i<i1;i++,k1++)
                             AssignBit(base->body,k1,color_byte);
                         ptr1=k1>>3+base->body;
                         for (i=0;i<i2;i++,ptr1><(U1 *)++)
                             *ptr1=*ptr1 & bit_mask | color_byte;
                         k1+=i2<<3;
                         for (i=0;i<i3;i++,k1++)
                             AssignBit(base->body,k1,color_byte);
                         kk1+=base->width_internal;
                     }
                     break;
                 case ROPB_XOR:
                     if (color_byte)
                         for (j=h2-h1;j;j--) {
                             k1=kk1;
                             for (i=0;i<i1;i++,k1++)
                                 Btc(base->body,k1);
                             ptr1=k1>>3+base->body;
                             for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                 *ptr1^=color_byte;
                             k1+=i2<<3;
                             for (i=0;i<i3;i++,k1++)
                                 Btc(base->body,k1);
                             kk1+=base->width_internal;
                         }
                         break;
                 case ROPB_OR:
                     if (color_byte)
                         for (j=h2-h1;j;j--) {
                             k1=kk1;
                             for (i=0;i<i1;i++,k1++)
                                 Bts(base->body,k1);
                             ptr1=k1>>3+base->body;
                             for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                 *ptr1|=color_byte;
                             k1+=i2<<3;
                             for (i=0;i<i3;i++,k1++)
                                 Bts(base->body,k1);
                             kk1+=base->width_internal;
                         }
                         break;
                 case ROPB_CLEAR_BITS:
                     if (color_byte)
                         for (j=h2-h1;j;j--) {
                             k1=kk1;
                             for (i=0;i<i1;i++,k1++)
                                 Btr(base->body,k1);
                             ptr1=k1>>3+base->body;
                             for (i=0;i<i2;i++,ptr1><(U1 *)++)
                                 *ptr1= *ptr1 & (bit_mask | ~color_byte);
                             k1+=i2<<3;
                             for (i=0;i<i3;i++,k1++)
                                 Btr(base->body,k1);
                             kk1+=base->width_internal;
                         }
                         break;
             }
         }
         if (base->mask) {
         base->mask->brush=base->brush;
         base->mask->color=WHITE;
         if (base->color.u1[3]==ROPB_CLEAR_MASK_EQU)
             base->mask->color=ROPB_EQU+BLACK;
         else if (base->color.u1[3]==ROPB_CLEAR_MASK_TRANSPARENT)
             base->mask->color=ROPB_TRANSPARENT+BLACK;
         else
             base->mask->color.u1[3]=base->color.u1[3];
         GrBox(base->mask,my_x,my_y,w,h);
     }
     return TRUE;
 } else
     return FALSE;
}


I8 GrRayLenMinus(GrBitMap *base,I8 x,I8 y)
{
 I8 cnt=0,c,x3=x,y3=y,d;
 U1 *dst,bit,*dst2,*mask_dst;
 BoolI1 not_color=base->flags&BMF_FILL_NOT_COLOR ?TRUE:FALSE;

 if (x3<0 || y3<0)
     goto done;
 if (base->flags & BMF_SCREEN_BITMAP) {
     x3+=base->win_tss->win_pixel_left;
     if (x3>base->win_tss->win_pixel_right)
         goto done;

     y3+=base->win_tss->win_pixel_top;
     if (y3>base->win_tss->win_pixel_bottom)
         goto done;
     if (!(base->flags&BMF_ON_TOP) &&
             IsPixelCovered(base->win_tss,x3,y3))
         goto done;
 }
 if (x3+base->left_margin>=base->right_margin ||
         y3+base->top_margin>=base->bottom_margin)
     goto done;

 d=base->left_margin+(y3+base->top_margin)*base->width_internal;
 switch (base->type) {
     case BMT_COLOR4:
         if (base->mask)
             mask_dst=base->mask->body-base->body;
         else
             mask_dst=NULL;
         dst2=base->body+d>>3;
         d=base->plane_size;

         while (TRUE) {
             x3=x;
             if (x3&(FONT_WIDTH-1)==FONT_WIDTH-1) {
                 if (base->flags & BMF_SCREEN_BITMAP) {
                     if (x3<0) break;
                     x3+=base->win_tss->win_pixel_left;
                     if (x3>base->win_tss->win_pixel_right) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                     if (!(base->flags&BMF_ON_TOP) &&
                             IsPixelCovered(base->win_tss,x3,y3)) break;
                 } else {
                     if (x3<0) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                 }
             } else if (base->flags & BMF_SCREEN_BITMAP)
                     x3+=base->win_tss->win_pixel_left;

             dst=dst2+x3>>3;
             bit=1<<(x3&7);

             if (mask_dst)
                 if (!(mask_dst[dst]&bit)) {
                     c=MAX_I4;
                     goto here1a;
                 }

             c=0;
             if (*dst & bit)
                 c|=1;
             dst+=d;
             if (*dst & bit)
                 c|=2;
             dst+=d;
             if (*dst & bit)
                 c|=4;
             dst+=d;
             if (*dst & bit)
                 c|=8;

here1a:
             if (not_color) {
                 if (c!=base->color2) {
                     cnt++;
                     x--;
                 } else
                     break;
             } else {
                 if (c==base->color2) {
                     cnt++;
                     x--;
                 } else
                     break;
             }
         }
         return cnt;
     case BMT_COLOR4_U1:
         while (TRUE) {
             x3=x;
             if (x3&(FONT_WIDTH-1)==FONT_WIDTH-1) {
                 if (base->flags & BMF_SCREEN_BITMAP) {
                     if (x3<0) break;
                     x3+=base->win_tss->win_pixel_left;
                     if (x3>base->win_tss->win_pixel_right) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                     if (!(base->flags&BMF_ON_TOP) &&
                             IsPixelCovered(base->win_tss,x3,y3)) break;
                 } else {
                     if (x3<0) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                 }
             } else if (base->flags & BMF_SCREEN_BITMAP)
                     x3+=base->win_tss->win_pixel_left;
             if (base->mask)
                 if (!Bt(base->mask->body,d+x3)) {
                     c=MAX_I4;
                     goto here1b;
                 }
             c=base->body><(U1 *)[d+x3];
here1b:
             if (not_color) {
                 if (c!=base->color2) {
                     cnt++;
                     x--;
                 } else
                     break;
             } else {
                 if (c==base->color2) {
                     cnt++;
                     x--;
                 } else
                     break;
             }
         }
         return cnt;
     case BMT_MONO:
         while (TRUE) {
             x3=x;
             if (x3&(FONT_WIDTH-1)==FONT_WIDTH-1) {
                 if (base->flags & BMF_SCREEN_BITMAP) {
                     if (x3<0) break;
                     x3+=base->win_tss->win_pixel_left;
                     if (x3>base->win_tss->win_pixel_right) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                     if (!(base->flags&BMF_ON_TOP) &&
                             IsPixelCovered(base->win_tss,x3,y3)) break;
                 } else {
                     if (x3<0) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                 }
             } else if (base->flags & BMF_SCREEN_BITMAP)
                     x3+=base->win_tss->win_pixel_left;
             c=1;
             if (base->mask)
                 c=Bt(base->mask->body,d+x3);
             if (not_color) {
                 if (!c || Bt(base->body,d+x3)!=base->color2) {
                     cnt++;
                     x--;
                 } else
                     break;
             } else {
                 if (c && Bt(base->body,d+x3)==base->color2) {
                     cnt++;
                     x--;
                 } else
                     break;
             }
         }
         return cnt;
 }
done:
 return 0;
}

I8 GrRayLen(GrBitMap *base,I8 *x1,I8 y)
{
 I8 cnt=0,d,c,c2,x=*x1,x2=x,x3=x,y3=y;
 BoolI1 not_color=base->flags&BMF_FILL_NOT_COLOR ?TRUE:FALSE;
 U1 *dst,bit,not_bit,*dst2,*mask_dst;
 U8 color=base->color,bkcolor=base->bkcolor;
 double dist;

 if (x3<0 || y3<0)
     goto done;
 if (base->flags & BMF_SCREEN_BITMAP) {
     x3+=base->win_tss->win_pixel_left;
     if (x3>base->win_tss->win_pixel_right)
         goto done;

     y3+=base->win_tss->win_pixel_top;
     if (y3>base->win_tss->win_pixel_bottom)
         goto done;
     if (!(base->flags&BMF_ON_TOP) &&
             IsPixelCovered(base->win_tss,x3,y3))
         goto done;
 }
 if (x3+base->left_margin>=base->right_margin ||
         y3+base->top_margin>=base->bottom_margin)
     goto done;

 d=base->width_internal*(y3+base->top_margin)+base->left_margin;
 switch (base->type) {
     case BMT_COLOR4:
         if (base->mask)
             mask_dst=base->mask->body-base->body;
         else
             mask_dst=NULL;
         dst2=base->body+d>>3;
         d=base->plane_size;
         while (TRUE) {
             x3=x;
             if (!(x3&(FONT_WIDTH-1))) {
                 if (base->flags & BMF_SCREEN_BITMAP) {
                     if (x3<0) break;
                     x3+=base->win_tss->win_pixel_left;
                     if (x3>base->win_tss->win_pixel_right) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                     if (!(base->flags&BMF_ON_TOP) &&
                             IsPixelCovered(base->win_tss,x3,y3)) break;
                 } else {
                     if (x3<0) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                 }
             } else if (base->flags & BMF_SCREEN_BITMAP)
                 x3+=base->win_tss->win_pixel_left;

             dst=dst2+x3>>3;
             bit=1<<(x3&7);
             not_bit=~bit;

             if (mask_dst)
                 if (!(mask_dst[dst]&bit)) {
                     c=MAX_I4;
                     goto here3a;
                 }

             c=0;
             if (*dst & bit)
                 c|=1;
             dst+=d;
             if (*dst & bit)
                 c|=2;
             dst+=d;
             if (*dst & bit)
                 c|=4;
             dst+=d;
             if (*dst & bit)
                 c|=8;

here3a:
             if (not_color && c!=base->color2 ||
                     !not_color && c==base->color2) {
                 if (base->flags & BMF_LOCATE_NEAREST) {
                     dist=DistI8(x3,y3,base->cur_x,base->cur_y);
                     if (dist<=base->nearest_dist) {
                         base->nearest_grelem_num=base->cur_grelem_num;
                         base->nearest_dist=dist;
                     }
                 }
                 if (base->flags & BMF_RECORD_EXTENTS) {
                     if (x3<base->min_x) base->min_x=x3;
                     if (x3>base->max_x) base->max_x=x3;
                     if (y3<base->min_y) base->min_y=y3;
                     if (y3>base->max_y) base->max_y=y3;
                 }
                 dst=dst2+x3>>3;

                 c=color.u1[0];
                 switch (color.u1[3]) {
                     case ROPB_CLEAR_MASK_EQU:
                     case ROPB_CLEAR_MASK_TRANSPARENT:
                         if (mask_dst)
                             mask_dst[dst]&=not_bit;
                         goto here1a;
                     case ROPB_EQU:
                     case ROPB_TRANSPARENT:
                         if (mask_dst)
                             mask_dst[dst]|=bit;
here1a:
                         if (c & 1)
                             *dst|=bit;
                         else
                             *dst&=not_bit;
                         dst+=d;
                         if (c & 2)
                             *dst|=bit;
                         else
                             *dst&=not_bit;
                         dst+=d;
                         if (c & 4)
                             *dst|=bit;
                         else
                             *dst&=not_bit;
                         dst+=d;
                         if (c & 8)
                             *dst|=bit;
                         else
                             *dst&=not_bit;
                         break;
                     case ROPB_COLLISION:
                         c2=0;
                         if (*dst&bit)
                             c2+=1;
                         dst+=d;
                         if (*dst&bit)
                             c2+=2;
                         dst+=d;
                         if (*dst&bit)
                             c2+=4;
                         dst+=d;
                         if (*dst&bit)
                             c2+=8;
                         if (c2!=bkcolor.u1[0])
                             base->collision_cnt++;
                         break;
                     case ROPB_XOR:
                         if (mask_dst)
                             mask_dst[dst]|=bit;
                         if (c & 1) *dst^=bit;
                         dst+=d;
                         if (c & 2) *dst^=bit;
                         dst+=d;
                         if (c & 4) *dst^=bit;
                         dst+=d;
                         if (c & 8) *dst^=bit;
                         break;
                     case ROPB_OR:
                         if (mask_dst)
                             mask_dst[dst]|=bit;
                         if (c & 1) *dst|=bit;
                         dst+=d;
                         if (c & 2) *dst|=bit;
                         dst+=d;
                         if (c & 4) *dst|=bit;
                         dst+=d;
                         if (c & 8) *dst|=bit;
                         break;
                     case ROPB_CLEAR_BITS:
                         if (mask_dst)
                             mask_dst[dst]|=bit;
                         if (c & 1) *dst&=not_bit;
                         dst+=d;
                         if (c & 2) *dst&=not_bit;
                         dst+=d;
                         if (c & 4) *dst&=not_bit;
                         dst+=d;
                         if (c & 8) *dst&=not_bit;
                         break;
                 }
                 cnt++;
                 x++;
             } else
                 break;
         }
         *x1=x-1;
         x=x2-1;
         while (TRUE) {
             x3=x;
             if (x3&(FONT_WIDTH-1)==FONT_WIDTH-1) {
                 if (base->flags & BMF_SCREEN_BITMAP) {
                     if (x3<0) break;
                     x3+=base->win_tss->win_pixel_left;
                     if (x3>base->win_tss->win_pixel_right) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                     if (!(base->flags&BMF_ON_TOP) &&
                             IsPixelCovered(base->win_tss,x3,y3)) break;
                 } else {
                     if (x3<0) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                 }
             } else if (base->flags & BMF_SCREEN_BITMAP)
                 x3+=base->win_tss->win_pixel_left;

             dst=dst2+x3>>3;
             bit=1<<(x3&7);
             not_bit=~bit;

             if (mask_dst)
                 if (!(mask_dst[dst]&bit)) {
                     c=MAX_I4;
                     goto here4a;
                 }

             c=0;
             if (*dst & bit)
                 c|=1;
             dst+=d;
             if (*dst & bit)
                 c|=2;
             dst+=d;
             if (*dst & bit)
                 c|=4;
             dst+=d;
             if (*dst & bit)
                 c|=8;

here4a:
             if (not_color && c!=base->color2 ||
                     !not_color && c==base->color2) {
                 if (base->flags & BMF_LOCATE_NEAREST) {
                     dist=DistI8(x3,y3,base->cur_x,base->cur_y);
                     if (dist<=base->nearest_dist) {
                         base->nearest_grelem_num=base->cur_grelem_num;
                         base->nearest_dist=dist;
                     }
                 }
                 if (base->flags & BMF_RECORD_EXTENTS) {
                     if (x3<base->min_x) base->min_x=x3;
                     if (x3>base->max_x) base->max_x=x3;
                     if (y3<base->min_y) base->min_y=y3;
                     if (y3>base->max_y) base->max_y=y3;
                 }
                 dst=dst2+x3>>3;

                 c=color.u1[0];
                 switch (color.u1[3]) {
                     case ROPB_CLEAR_MASK_EQU:
                     case ROPB_CLEAR_MASK_TRANSPARENT:
                         if (mask_dst)
                             mask_dst[dst]&=not_bit;
                         goto here2a;
                     case ROPB_EQU:
                     case ROPB_TRANSPARENT:
                         if (mask_dst)
                             mask_dst[dst]|=bit;
here2a:
                         if (c & 1)
                             *dst|=bit;
                         else
                             *dst&=not_bit;
                         dst+=d;
                         if (c & 2)
                             *dst|=bit;
                         else
                             *dst&=not_bit;
                         dst+=d;
                         if (c & 4)
                             *dst|=bit;
                         else
                             *dst&=not_bit;
                         dst+=d;
                         if (c & 8)
                             *dst|=bit;
                         else
                             *dst&=not_bit;
                         break;
                     case ROPB_COLLISION:
                         c2=0;
                         if (*dst&bit)
                             c2+=1;
                         dst+=d;
                         if (*dst&bit)
                             c2+=2;
                         dst+=d;
                         if (*dst&bit)
                             c2+=4;
                         dst+=d;
                         if (*dst&bit)
                             c2+=8;
                         if (c2!=bkcolor.u1[0])
                             base->collision_cnt++;
                         break;
                     case ROPB_XOR:
                         if (mask_dst)
                             mask_dst[dst]|=bit;
                         if (c & 1) *dst^=bit;
                         dst+=d;
                         if (c & 2) *dst^=bit;
                         dst+=d;
                         if (c & 4) *dst^=bit;
                         dst+=d;
                         if (c & 8) *dst^=bit;
                         break;
                     case ROPB_OR:
                         if (mask_dst)
                             mask_dst[dst]|=bit;
                         if (c & 1) *dst|=bit;
                         dst+=d;
                         if (c & 2) *dst|=bit;
                         dst+=d;
                         if (c & 4) *dst|=bit;
                         dst+=d;
                         if (c & 8) *dst|=bit;
                         break;
                     case ROPB_CLEAR_BITS:
                         if (mask_dst)
                             mask_dst[dst]|=bit;
                         if (c & 1) *dst&=not_bit;
                         dst+=d;
                         if (c & 2) *dst&=not_bit;
                         dst+=d;
                         if (c & 4) *dst&=not_bit;
                         dst+=d;
                         if (c & 8) *dst&=not_bit;
                         break;
                 }
                 cnt++;
                 x--;
             } else
                 break;
         }
         return cnt;
     case BMT_COLOR4_U1:
         dst2=base->body+d;
         while (TRUE) {
             x3=x;
             if (!(x3&(FONT_WIDTH-1))) {
                 if (base->flags & BMF_SCREEN_BITMAP) {
                     if (x3<0) break;
                     x3+=base->win_tss->win_pixel_left;
                     if (x3>base->win_tss->win_pixel_right) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                     if (!(base->flags&BMF_ON_TOP) &&
                             IsPixelCovered(base->win_tss,x3,y3)) break;
                 } else {
                     if (x3<0) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                 }
             } else if (base->flags & BMF_SCREEN_BITMAP)
                 x3+=base->win_tss->win_pixel_left;

             if (base->mask)
                 if (!Bt(base->mask->body,d+x3)) {
                     c=MAX_I4;
                     goto here3b;
                 }
             c=base->body><(U1 *)[d+x3];

here3b:
             if (not_color && c!=base->color2 ||
                     !not_color && c==base->color2) {
                 if (base->flags & BMF_LOCATE_NEAREST) {
                     dist=DistI8(x3,y3,base->cur_x,base->cur_y);
                     if (dist<=base->nearest_dist) {
                         base->nearest_grelem_num=base->cur_grelem_num;
                         base->nearest_dist=dist;
                     }
                 }
                 if (base->flags & BMF_RECORD_EXTENTS) {
                     if (x3<base->min_x) base->min_x=x3;
                     if (x3>base->max_x) base->max_x=x3;
                     if (y3<base->min_y) base->min_y=y3;
                     if (y3>base->max_y) base->max_y=y3;
                 }
                 dst=dst2+x3;

                 c=color.u1[0];
                 switch (color.u1[3]) {
                     case ROPB_CLEAR_MASK_EQU:
                     case ROPB_CLEAR_MASK_TRANSPARENT:
                         if (base->mask)
                             Btr(base->mask->body,dst);
                         goto here1b;
                     case ROPB_EQU:
                     case ROPB_TRANSPARENT:
                         if (base->mask)
                             Bts(base->mask->body,dst);
here1b:
                         *dst=c;
                         break;
                     case ROPB_COLLISION:
                         if (*dst!=bkcolor.u1[0])
                             base->collision_cnt++;
                         break;
                     case ROPB_XOR:
                         if (base->mask)
                             Bts(base->mask->body,dst);
                         *dst^=c;
                         break;
                     case ROPB_OR:
                         if (base->mask)
                             Bts(base->mask->body,dst);
                         *dst|=c;
                         break;
                     case ROPB_CLEAR_BITS:
                         if (base->mask)
                             Bts(base->mask->body,dst);
                         *dst&=~c;
                         break;
                 }
                 cnt++;
                 x++;
             } else
                 break;
         }
         *x1=x-1;
         x=x2-1;
         while (TRUE) {
             x3=x;
             if (x3&(FONT_WIDTH-1)==FONT_WIDTH-1) {
                 if (base->flags & BMF_SCREEN_BITMAP) {
                     if (x3<0) break;
                     x3+=base->win_tss->win_pixel_left;
                     if (x3>base->win_tss->win_pixel_right) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                     if (!(base->flags&BMF_ON_TOP) &&
                             IsPixelCovered(base->win_tss,x3,y3)) break;
                 } else {
                     if (x3<0) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                 }
             } else if (base->flags & BMF_SCREEN_BITMAP)
                 x3+=base->win_tss->win_pixel_left;

             if (base->mask)
                 if (!Bt(base->mask->body,d+x3)) {
                     c=MAX_I4;
                     goto here4b;
                 }
             c=base->body><(U1 *)[d+x3];
here4b:
             if (not_color && c!=base->color2 ||
                     !not_color && c==base->color2) {
                 if (base->flags & BMF_LOCATE_NEAREST) {
                     dist=DistI8(x3,y3,base->cur_x,base->cur_y);
                     if (dist<=base->nearest_dist) {
                         base->nearest_grelem_num=base->cur_grelem_num;
                         base->nearest_dist=dist;
                     }
                 }
                 if (base->flags & BMF_RECORD_EXTENTS) {
                     if (x3<base->min_x) base->min_x=x3;
                     if (x3>base->max_x) base->max_x=x3;
                     if (y3<base->min_y) base->min_y=y3;
                     if (y3>base->max_y) base->max_y=y3;
                 }
                 dst=dst2+x3;

                 c=color.u1[0];
                 switch (color.u1[3]) {
                     case ROPB_CLEAR_MASK_EQU:
                     case ROPB_CLEAR_MASK_TRANSPARENT:
                         if (base->mask)
                             Btr(base->mask->body,dst);
                         goto here2b;
                     case ROPB_EQU:
                     case ROPB_TRANSPARENT:
                         if (base->mask)
                             Bts(base->mask->body,dst);
here2b:
                         *dst=c;
                         break;
                     case ROPB_COLLISION:
                         if (*dst!=bkcolor.u1[0])
                             base->collision_cnt++;
                         break;
                     case ROPB_XOR:
                         if (base->mask)
                             Bts(base->mask->body,dst);
                         *dst^=c;
                         break;
                     case ROPB_OR:
                         if (base->mask)
                             Bts(base->mask->body,dst);
                         *dst|=c;
                         break;
                     case ROPB_CLEAR_BITS:
                         if (base->mask)
                             Bts(base->mask->body,dst);
                         *dst&=~c;
                         break;
                 }
                 cnt++;
                 x--;
             } else
                 break;
         }
         return cnt;
     case BMT_MONO:
         while (TRUE) {
             x3=x;
             if (!(x3&(FONT_WIDTH-1))) {
                 if (base->flags & BMF_SCREEN_BITMAP) {
                     if (x3<0) break;
                     x3+=base->win_tss->win_pixel_left;
                     if (x3>base->win_tss->win_pixel_right) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                     if (!(base->flags&BMF_ON_TOP) &&
                             IsPixelCovered(base->win_tss,x3,y3)) break;
                 } else {
                     if (x3<0) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                 }
             } else if (base->flags & BMF_SCREEN_BITMAP)
                 x3+=base->win_tss->win_pixel_left;
             c=Bt(base->body,d+x3);
             if (base->mask)
                 if (!Bt(base->mask->body,d+x3))
                     c=MAX_I4;

             if (not_color && c!=base->color2 ||
                     !not_color && c==base->color2) {
                 if (base->flags & BMF_LOCATE_NEAREST) {
                     dist=DistI8(x3,y3,base->cur_x,base->cur_y);
                     if (dist<=base->nearest_dist) {
                         base->nearest_grelem_num=base->cur_grelem_num;
                         base->nearest_dist=dist;
                     }
                 }
                 if (base->flags & BMF_RECORD_EXTENTS) {
                     if (x3<base->min_x) base->min_x=x3;
                     if (x3>base->max_x) base->max_x=x3;
                     if (y3<base->min_y) base->min_y=y3;
                     if (y3>base->max_y) base->max_y=y3;
                 }
                 c=color&0xFFFFFF;
                 switch (color.u1[3]) {
                     case ROPB_CLEAR_MASK_EQU:
                     case ROPB_CLEAR_MASK_TRANSPARENT:
                         AssignBit(base->body,d+x3,c);
                         if (base->mask)
                             Btr(base->mask->body,d+x3);
                         break;
                     case ROPB_EQU:
                     case ROPB_TRANSPARENT:
                         AssignBit(base->body,d+x3,c);
                         if (base->mask)
                             Bts(base->mask->body,d+x3);
                         break;
                     case ROPB_COLLISION:
                         if (c) {
                             if (bkcolor&0xFFFFFF)
                                 base->collision_cnt+=Bt(base->body,d+x3);
                             else
                                 base->collision_cnt+=!Bt(base->body,d+x3);
                         } else {
                             if (bkcolor&0xFFFFFF)
                                 base->collision_cnt+=!Bt(base->body,d+x3);
                             else
                                 base->collision_cnt+=Bt(base->body,d+x3);
                         }
                         break;
                     case ROPB_XOR:
                         if (c)
                             Btc(base->body,d+x3);
                         if (base->mask)
                             Bts(base->mask->body,d+x3);
                         break;
                     case ROPB_OR:
                         if (c)
                             Bts(base->body,d+x3);
                         if (base->mask)
                             Bts(base->mask->body,d+x3);
                         break;
                     case ROPB_CLEAR_BITS:
                         if (c)
                             Btr(base->body,d+x3);
                         if (base->mask)
                             Bts(base->mask->body,d+x3);
                         break;
                 }
                 cnt++;
                 x++;
             } else
                 break;
         }
         *x1=x-1;
         x=x2-1;
         while (TRUE) {
             x3=x;
             if (x3&(FONT_WIDTH-1)==FONT_WIDTH-1) {
                 if (base->flags & BMF_SCREEN_BITMAP) {
                     if (x3<0) break;
                     x3+=base->win_tss->win_pixel_left;
                     if (x3>base->win_tss->win_pixel_right) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                     if (!(base->flags&BMF_ON_TOP) &&
                             IsPixelCovered(base->win_tss,x3,y3)) break;
                 } else {
                     if (x3<0) break;
                     if (x3>=base->right_margin-base->left_margin) break;
                 }
             } else if (base->flags & BMF_SCREEN_BITMAP)
                 x3+=base->win_tss->win_pixel_left;

             c=Bt(base->body,d+x3);
             if (base->mask)
                 if (!Bt(base->mask->body,d+x3))
                     c=MAX_I4;
             if (not_color && c!=base->color2 ||
                     !not_color && c==base->color2) {
                 if (base->flags & BMF_LOCATE_NEAREST) {
                     dist=DistI8(x3,y3,base->cur_x,base->cur_y);
                     if (dist<=base->nearest_dist) {
                         base->nearest_grelem_num=base->cur_grelem_num;
                         base->nearest_dist=dist;
                     }
                 }
                 if (base->flags & BMF_RECORD_EXTENTS) {
                     if (x3<base->min_x) base->min_x=x3;
                     if (x3>base->max_x) base->max_x=x3;
                     if (y3<base->min_y) base->min_y=y3;
                     if (y3>base->max_y) base->max_y=y3;
                 }
                 c=color&0xFFFFFF;
                 switch (color.u1[3]) {
                     case ROPB_CLEAR_MASK_EQU:
                     case ROPB_CLEAR_MASK_TRANSPARENT:
                         AssignBit(base->body,d+x3,c);
                         if (base->mask)
                             Btr(base->mask->body,d+x3);
                         break;
                     case ROPB_EQU:
                     case ROPB_TRANSPARENT:
                         AssignBit(base->body,d+x3,c);
                         if (base->mask)
                             Bts(base->mask->body,d+x3);
                         break;
                     case ROPB_COLLISION:
                         if (c) {
                             if (bkcolor&0xFFFFFF)
                                 base->collision_cnt+=Bt(base->body,d+x3);
                             else
                                 base->collision_cnt+=!Bt(base->body,d+x3);
                         } else {
                             if (bkcolor&0xFFFFFF)
                                 base->collision_cnt+=!Bt(base->body,d+x3);
                             else
                                 base->collision_cnt+=Bt(base->body,d+x3);
                         }
                         break;
                     case ROPB_XOR:
                         if (c)
                             Btc(base->body,d+x3);
                         if (base->mask)
                             Bts(base->mask->body,d+x3);
                         break;
                     case ROPB_OR:
                         if (c)
                             Bts(base->body,d+x3);
                         if (base->mask)
                             Bts(base->mask->body,d+x3);
                         break;
                     case ROPB_CLEAR_BITS:
                         if (c)
                             Btr(base->body,d+x3);
                         if (base->mask)
                             Bts(base->mask->body,d+x3);
                         break;
                 }
                 cnt++;
                 x--;
             } else
                 break;
         }
         return cnt;
 }
done:
 return 0;
}
Home

Kernel
StartUp
Scheduler
Memory
MultiCore
Interrupts
BitMaps
Screen
Plot
Compiler Frontend
Compiler Mid
Compiler Backend
Graphical Bit Maps
Historical capture: 2008-10-15. Home | Power on LoseThos | Sources and changes