Newer
Older
ubix / src / sys / graphics / objgfx30.cpp
/*******************************************************
$Id$
*******************************************************/

#include "objgfx30.h"
#include <stdlib.h>
#include <string.h>
//#include <math.h>
#include "../include/types.h"
// TGfx0 constructor

TGfx0::TGfx0(void) {
  DataState = og_None;
  Buffer = NULL;
  LineOfs = NULL;
  pal = NULL;
  xRes = 0;
  yRes = 0;
  MaxX = 0;
  MaxY = 0;
  bSize = 0;
  lSize = 0;
  TransparentColor = 0;
  BPP = 0;
  RedShifter = 0;
  GreenShifter = 0;
  BlueShifter = 0;
  RedFieldPosition = 0;
  GreenFieldPosition = 0;
  BlueFieldPosition = 0;
  AntiAlias = TRUE;
  return;
} // TGfx0::TGfx0()

bool
TGfx0::alias(TGfx0& SrcObject, UInt32 x1, UInt32 y1, UInt32 x2, UInt32 y2) {
  UInt32 tmp;
  if (DataState==og_Owner) return FALSE;

  if (x2<x1) {
    tmp= x2;
    x2 = x1;
    x1 = tmp;
  } // if
  if (y2<y1) {
    tmp= y2;
    y2 = y1;
    y1 = tmp;
  } // if 
  Owner = &SrcObject;
  Buffer =((unsigned char *)(SrcObject.Buffer)+x1*((SrcObject.BPP+7) >> 3));
  LineOfs=((UInt32 *)SrcObject.LineOfs)+y1;
  pal = SrcObject.pal;
  xRes = SrcObject.xRes;
  yRes = SrcObject.yRes;
  MaxX = (x2-x1);
  MaxY = (y2-y1);
  bSize = 0;
  lSize = 0;
  TransparentColor = SrcObject.TransparentColor;
  DataState = og_Aliasing;
  BPP = SrcObject.BPP;
  // For 8bpp modes the next part doesn't matter
  RedFieldPosition = SrcObject.RedFieldPosition;
  GreenFieldPosition = SrcObject.GreenFieldPosition;
  BlueFieldPosition = SrcObject.BlueFieldPosition;
  // The next part is only used by 15/16bpp
  RedShifter = SrcObject.RedShifter;
  GreenShifter = SrcObject.GreenShifter;
  BlueShifter = SrcObject.BlueShifter;
  
  AntiAlias = SrcObject.AntiAlias;

  return TRUE;
} // TGfx0::alias

void
TGfx0::arc(UInt32 x_center, UInt32 y_center, UInt32 radius, 
           UInt32 s_angle, UInt32 e_angle, UInt32 colour) {
  Int32 p;
  UInt32 x, y, tmp;
  double alpha;
  
  if (radius==0) {
    putPixel(x_center, y_center, colour);
    return;
  } // if

  s_angle%=361;
  e_angle%=361;

  if (s_angle>e_angle) {
    tmp = s_angle;
    s_angle = e_angle;
    e_angle = tmp;
  } // if
  
  x = 0;
  y = radius;
  p = 3-2*radius;
  
  while (x<=y) {
 // mjikaboom   alpha = RadToDeg(atan(x/y));
    if ((alpha>=s_angle) && (alpha<=e_angle))
      putPixel(x_center-x, y_center-y, colour);
    if ((90-alpha>=s_angle) && (90-alpha<=e_angle))
      putPixel(x_center-y, y_center-x, colour);
    if ((90+alpha>=s_angle) && (90+alpha<=e_angle))
      putPixel(x_center-y, y_center+x,colour);
    if ((180-alpha>=s_angle) && (180-alpha<=e_angle))
      putPixel(x_center-x, y_center+y,colour);
    if ((180+alpha>=s_angle) && (180+alpha<=e_angle))
      putPixel(x_center+x, y_center+y,colour);
    if ((270-alpha>=s_angle) && (270-alpha<=e_angle))
      putPixel(x_center+y, y_center+x,colour);
    if ((270+alpha>=s_angle) && (270+alpha<=e_angle))
      putPixel(x_center+y, y_center-x,colour);
    if ((360-alpha>=s_angle) && (360-alpha<=e_angle))
      putPixel(x_center+x, y_center-y,colour);
    if (p<0) p+=4*x+6;
    else {
      p+=4*(x-y)+10;
      y--;
    }
    x++;
  } // while
} // TGfx0::arc

void 
TGfx0::bar(Int32 x1, Int32 y1, Int32 x2, Int32 y2, UInt32 colour) {
  Int32 yy;
  Int32 tmp;

  if (x2<x1) {
    tmp= x2;
    x2 = x1;
    x1 = tmp;
  } // if
  if (y2<y1) {
    tmp= y2;
    y2 = y1;
    y1 = tmp;
  } // if 

  if ((y2<0) || (y1>(Int32)MaxY)) return;
  if (y1<0) y1=0;
  if (y2>(Int32)MaxY) y2=MaxY;
  for (yy=y1; yy<=y2; yy++)
    hLine(x1,x2,yy,colour);
} // TGfx0::bar

void 
TGfx0::circle(Int32 x_center, Int32 y_center, UInt32 radius, UInt32 colour) {
  Int32 x, y, d;
  x = 0;
  y = radius;
  d = 2*(1-radius);
  while (y>=0) {
    putPixel(x_center+x,y_center+y,colour);
    putPixel(x_center+x,y_center-y,colour);
    putPixel(x_center-x,y_center+y,colour);
    putPixel(x_center-x,y_center-y,colour);
    if (d + y > 0) {
      y--;
      d -= 2*y+1;
    } // if
    if (x > d) {
      x++;
      d += 2*x+1;
    } // if
  } // while
} // TGfx0::circle

void 
TGfx0::clear(UInt32 colour) {
  UInt32 height;
  if ((Buffer==NULL) || (LineOfs==NULL)) return;
  asm("cld\n");
  switch (BPP) {
    case 8:
      asm(
          "  add (%%esi), %%edi  \n"      // add edi, [esi]
          "  mov %%ecx, %%esi    \n"      // mov esi, ecx
          "  inc %%edx           \n"      // inc edx (MaxY)
          "  inc %%ebx           \n"      // inc ebx (MaxX)
          "  sub %%edx, %%esi    \n"      // sub esi, edx
          "  mov %%al, %%ah      \n"      // mov ah, al
          "  mov %%ax, %%cx      \n"      // mov cx, ax
          "  shl $16, %%eax      \n"      // shl eax, 16
          "  mov %%cx, %%ax      \n"      // mov ax, cx
      "loop8:                    \n"
          "  push %%edx          \n"
          "  mov %%edx, %%ecx    \n"      // mov ecx, edx
          "  and $3, %%edx       \n"      // and edx, 3
          "  shr $2, %%ecx       \n"      // shr ecx, 2
          " rep                  \n"
          " stosl                \n"      
          "  mov %%edx, %%ecx    \n"      // mov ecx, edx
          " rep                  \n"
          " stosb                \n"      
          "  pop %%edx           \n"
          "  add %%esi, %%edi    \n"      // add edi, esi
          "  dec %%ebx           \n"
          "   jnz loop8          \n"
        :
        : "D" (Buffer), "S" (LineOfs),           // %0, %1
          "a" (colour), "b" (MaxY),              // %2, %3
          "c" (xRes), "d" (MaxX)                 // %4, %5
      );
      break;
    case 15:
    case 16:
      asm(
          "  add (%%esi), %%edi  \n"      // add edi, [esi]
          "  mov %%ecx, %%esi    \n"      // mov esi, ecx
          "  inc %%edx           \n"      // inc edx (MaxX)
          "  inc %%ebx           \n"      // inc ebx (MaxY)
          "  sub %%edx, %%esi    \n"      // sub esi, edx
          "  sub %%edx, %%esi    \n"      // sub esi, edx // adjust for pix size
          "  mov %%ax, %%cx      \n"      // mov cx, ax
          "  shl $16, %%eax      \n"      // shl eax, 16
          "  mov %%cx, %%ax      \n"      // mov ax, cx
      "loop16:                   \n"
          "  mov %%edx, %%ecx    \n"      // mov ecx, edx
          "  shr $1, %%ecx       \n"      // shr ecx, 1
          " rep                  \n"
          " stosl                \n"      
          "  jnc noc16           \n"
          " stosw                \n"
      "noc16:                    \n"
          "  add %%esi, %%edi    \n"      // add edi, esi
          "  dec %%ebx           \n"
          "   jnz loop16         \n"
        :
        : "D" (Buffer), "S" (LineOfs),           // %0, %1
          "a" (colour), "b" (MaxY),              // %2, %3
          "c" (xRes), "d" (MaxX)                 // %4, %5
      );
      break;
    case 24:
      asm(
          "  add (%%esi), %%edi  \n"      // add edi, [esi]
          "  mov %%ecx, %%esi    \n"      // mov esi, ecx
          "  inc %%edx           \n"      // inc edx (MaxX)
          "  inc %%ebx           \n"      // inc ebx (MaxY)
          "  sub %%edx, %%esi    \n"      // sub esi, edx // adjust for pix size
          "  mov %%ebx, %6       \n"      // mov height, ebx
          "  sub %%edx, %%esi    \n"      // sub esi, edx // adjust for pix size
          "  mov %%eax, %%ebx    \n"      // mov ebx, eax
          "  sub %%edx, %%esi    \n"      // sub esi, edx // adjust for pix size
          "  shr $16, %%ebx      \n"      // shr ebx, 16
      "oloop24:                  \n"
          "  mov %%edx, %%ecx    \n"      // mov ecx, edx
      "iloop24:                  \n"
          "  mov %%ax,(%%edi)    \n"      // mov [edi],ax
          "  movb %%bl,2(%%edi)  \n"      // mov [edi+2],bl
          "  add $3, %%edi       \n"      // add edi, 3
          "  dec %%ecx           \n"      // dec ecx
          "   jnz iloop24        \n"
          "  add %%esi, %%edi    \n"      // add edi, esi
          "  decl %6             \n"      // dec height
          "   jnz oloop24        \n"
        :
        : "D" (Buffer), "S" (LineOfs),           // %0, %1
          "a" (colour), "b" (MaxY),              // %2, %3
          "c" (xRes), "d" (MaxX),                // %4, %5
          "g" (height)                           // %6
        );
      break;
    case 32:
      asm(
          "  add (%%esi), %%edi  \n"      // add edi, [esi]
          "  mov %%ecx, %%esi    \n"      // mov esi, ecx
          "  inc %%edx           \n"      // inc edx (MaxX)
          "  inc %%ebx           \n"      // inc ebx (MaxY)
          "  mov %%edx, %%ecx    \n"      // mov ecx, edx
          "  shl $2, %%ecx       \n"      // shl ecx, 2
          "  sub %%ecx, %%esi    \n"      // sub esi, ecx // adjust for pix size
      "loop32:                   \n"
          "  mov %%edx, %%ecx    \n"      // mov ecx, edx
          " rep                  \n"
          " stosl                \n"      
          "  add %%esi, %%edi    \n"      // add edi, esi
          "  dec %%ebx           \n"
          "   jnz loop32         \n"
        :
        : "D" (Buffer), "S" (LineOfs),           // %0, %1
          "a" (colour), "b" (MaxY),              // %2, %3
          "c" (xRes), "d" (MaxX)                 // %4, %5
     );
  }
} // TGfx0::clear

bool
TGfx0::clipLine(Int32& x1, Int32& y1, Int32& x2, Int32& y2) {
  /*
   *  clipLine()
   *
   *  private method; clips a line to (0,0),(MaxX,MaxY); returns true if
   *  the line segment is in bounds, false if none of the line segment is
   *  on the screen.  Uses HJI's line clipping algorithm.
   */

  Int32 tx1, ty1, tx2, ty2;
  Int32 OutCode;
  UInt32 AndResult, OrResult;
  AndResult = 15;
  OrResult = 0;
  OutCode = 0;
  if (x1<0) OutCode+=8;
  if (x1>(Int32)MaxX) OutCode+=4;
  if (y1<0) OutCode+=2;
  if (y1>(Int32)MaxY) OutCode++;
   
  AndResult &= OutCode;
  OrResult |= OutCode;
  OutCode = 0;
   
  if (x2<0) OutCode+=8;
  if (x2>(Int32)MaxX) OutCode+=4;
  if (y2<0) OutCode+=2;
  if (y2>(Int32)MaxY) OutCode++;
   
  AndResult &= OutCode;
  OrResult |= OutCode;

  if (AndResult>0) return FALSE;
  if (OrResult==0) return TRUE;

   // some clipping is required here.  

  tx1 = x1;
  ty1 = y1;
  tx2 = x2;
  ty2 = y2;

  if (x1<0) {
    ty1 = (x2*y1-x1*y2) / (x2-x1);
    tx1 = 0;
  } // if
  else
    if (x2<0) {
        ty2 = (x2*y1-x1*y2) / (x2-x1);
        tx2 = 0;
    } // elseif

  if (x1>(Int32)MaxX) {
    ty1 = (y1*(x2-MaxX)+y2*(MaxX-x1)) / (x2-x1);
    tx1 = MaxX;
  } // if
  else
    if (x2>(Int32)MaxX) {
      ty2 = (y1*(x2-MaxX)+y2*(MaxX-x1)) / (x2-x1);
      tx2 = MaxX;
    } // elseif

  if (((ty1<0) && (ty2<0)) || 
     ((ty1>(Int32)MaxY) && (ty2>(Int32)MaxY))) return FALSE;

  if (ty1<0) {
    tx1 = (x1*y2-x2*y1) / (y2-y1);
    ty1 = 0;
  } // if
  else
    if (ty2<0) {
      tx2 = (x1*y2-x2*y1) / (y2-y1);
      ty2 = 0;
    } // elseif 

  if (ty1>(Int32)MaxY) {
    tx1 = (x1*(y2-MaxY)+x2*(MaxY-y1)) / (y2-y1);
    ty1 = MaxY;
  } // if
  else
    if (ty2>(Int32)MaxY) {
       tx2 = (x1*(y2-MaxY)+x2*(MaxY-y1)) / (y2-y1);
       ty2 = MaxY;
    } // elseif 

  if (((UInt32)tx1>MaxX) || ((UInt32)tx2>MaxX)) return FALSE;

  x1 = tx1;
  y1 = ty1;
  x2 = tx2;
  y2 = ty2;

  return TRUE;
} // TGfx0::clipLine

void 
TGfx0::clone(TGfx0& SrcObject) {
  TPixelFmt pixfmt;
  if (SrcObject.DataState==og_None) return;
  SrcObject.getPixFmt(pixfmt);
  create(SrcObject.MaxX+1,SrcObject.MaxY+1,pixfmt);
  if (pal!=NULL) memcpy(pal, SrcObject.pal, sizeof(TRGB)*256);
  TransparentColor = SrcObject.TransparentColor;
  AntiAlias = SrcObject.AntiAlias;
  copy(SrcObject);
} // TGfx0::clone

void 
TGfx0::copy(TGfx0& SrcObject) {
  UInt32 count, xCount, yCount;
  UInt32 xx, yy;
  UInt8  r, g, b;
  if ((Buffer==NULL) || (LineOfs==NULL)) return;
  if ((SrcObject.Buffer==NULL) || (SrcObject.LineOfs==NULL)) return;
  xCount = SrcObject.MaxX+1;
  if (xCount>MaxX+1) xCount=MaxX+1;
  yCount = SrcObject.MaxY+1;
  if (yCount>MaxY+1) yCount=MaxY+1;
  if ((BPP!=SrcObject.BPP) || (RedShifter!=SrcObject.RedShifter) ||
      (BlueShifter!=SrcObject.BlueShifter) || 
      (GreenShifter!=SrcObject.GreenShifter)) {
    for (yy=0; yy<=yCount-1; yy++)
      for (xx=0; xx<=xCount-1; xx++) {
        SrcObject.unpackRGB(SrcObject.getPixel(xx,yy),r,g,b);
        putPixel(xx,yy,RGB(r,g,b));
      } // for
  }  // if
  else
  {
    xCount *= ((BPP+7) >> 3); // adjust for bpp 
    for (count=0; count<=yCount-1; count++) ;
      memcpy(((char*)Buffer+LineOfs[count]),                        // dest
             ((char*)SrcObject.Buffer+SrcObject.LineOfs[count]),  // src
             xCount);                                               // len
  } // else
} // TGfx0::copy

void
TGfx0::copyBuf(Int32 DestX, Int32 DestY, 
               TGfx0& SrcObject, Int32 x1, Int32 y1, Int32 x2, Int32 y2) {
  UInt32 pixmap[256];
  Int32 xx,yy,count,xCount, yCount;
  UInt32 bm;        // bit multiplyer
  UInt8 r, g, b;
  
  if ((Buffer==NULL) || (LineOfs==NULL)) return;
  if ((SrcObject.Buffer==NULL) || (SrcObject.LineOfs==NULL)) return;
  
  if ((DestX>(Int32)MaxX) || (DestY>(Int32)MaxY)) return;
  
  if (x1>x2) {
    xx = x1;
    x1 = x2;
    x2 = xx;
  } // if
  if (y1>y2) {
    yy = y1;
    y1 = y2;
    y2 = yy;
  } // if

  xCount = abs(x2-x1)+1;
  yCount = abs(y2-y1)+1;
  
  if (DestX+xCount>(Int32)MaxX+1) xCount=MaxX-DestX+1;
  if (DestY+yCount>(Int32)MaxY+1) yCount=MaxY-DestY+1;

  if (DestX<0) {
    xCount += DestX;
    x1 -= DestX;
    DestX = 0;
  } // if
 
  if (DestY<0) {
    yCount += DestY;
    y1 -= DestY;
    DestY = 0;
  } // if
 
  if ((DestX+xCount<0) || (DestY+yCount<0)) return;

  if ((BPP!=SrcObject.BPP) || (RedShifter!=SrcObject.RedShifter) ||
      (BlueShifter!=SrcObject.BlueShifter) ||
      (GreenShifter!=SrcObject.GreenShifter)) {
    if (SrcObject.BPP==8) {
      for (xx=0; xx<256; xx++) 
        pixmap[xx] = RGB(SrcObject.pal[xx].red,
                         SrcObject.pal[xx].green,
                         SrcObject.pal[xx].blue);
      for (yy=0; yy<=yCount-1; yy++) 
        for (xx=0; xx<=xCount-1; xx++)
          putPixel(DestX+xx,DestY+yy,pixmap[SrcObject.getPixel(x1+xx,y1+yy)]); 
 
    } // if srcobject->bpp
    else
    {
      for (yy=0; yy<=yCount-1; yy++)
        for (xx=0; xx<=xCount-1; xx++) {
          SrcObject.unpackRGB(SrcObject.getPixel(x1+xx,y1+yy),r,g,b);
          putPixel(DestX+xx,DestY+yy,RGB(r,g,b));
        } // for
    } // else
  } // if
  else
  {
    bm = (BPP+7) >> 3;
    x1 *= bm;
    DestX *= bm;
    xCount *= bm;
    for (count=0; count<=yCount-1; count++) {
      memcpy(((char*)Buffer+LineOfs[DestY+count]+DestX),               // dest
             ((char*)SrcObject.Buffer+SrcObject.LineOfs[y1+count]+x1), // src
             xCount);                                                  // len
    
    }
  } // else
} // TGfx0::copyBuf

bool 
TGfx0::create(UInt32 _xRes, UInt32 _yRes,TPixelFmt _pixformat) {
  /*
   *  constructor TGfx0::create()
   *  Allocates memory for a buffer of size _xRes by _yRes with
   *  the pixel format defined in _pixformat.  Allocates memory
   *  for pal and LineOfs.
   */
  UInt32 yy;
  if (DataState==og_Owner) {
    if (Buffer!=NULL) free(Buffer);
    if (LineOfs!=NULL) free(LineOfs);
    if (pal!=NULL) free(pal);
  }  // if datastate
  BPP = _pixformat.BPP;
  bSize=_xRes*_yRes*((BPP+7) >> 3);
  Buffer = malloc(bSize);
  if (Buffer==NULL) return FALSE;
  memset(Buffer,0,bSize);
  lSize = _yRes*sizeof(UInt32);
  LineOfs = (UInt32*)malloc(lSize);
  if (LineOfs == NULL) return FALSE;
  pal = (TRGB*)malloc(256*sizeof(TRGB));
  if (pal == NULL) return FALSE;
  memset(pal,0,sizeof(TRGB)*256);
  MaxX=_xRes-1;
  xRes=_xRes*((BPP+7) >> 3);
  MaxY=_yRes-1;
  yRes=_yRes;
  LineOfs[0]=0;
  for (yy=1; yy<=MaxY; yy++)
    LineOfs[yy]=LineOfs[yy-1]+xRes;
  DataState = og_Owner;
  // For 8bpp modes the next part doesn't matter 
  RedFieldPosition=_pixformat.RedFieldPosition;
  GreenFieldPosition=_pixformat.GreenFieldPosition;
  BlueFieldPosition=_pixformat.BlueFieldPosition;
  // The next part is only used by 15/16hpp 
  RedShifter=8-_pixformat.RedMaskSize;
  GreenShifter=8-_pixformat.GreenMaskSize;
  BlueShifter=8-_pixformat.BlueMaskSize; 
  Owner = this;
  return TRUE;
} // TGfx0::create

UInt8
TGfx0::getBPP(void) {
  return BPP;
} // TGfx0::getBPP

void*
TGfx0::getBufferPtr(void) {
  return Buffer;
} // TGfx0::getBufferPtr

og_DataState
TGfx0::getDataState(void) {
  return DataState;
} // TGfx0::getDataState(void)

UInt32*
TGfx0::getLineOfsPtr(void) {
  return LineOfs;
} // TGfx0::getLineOfsPtr

TRGB *
TGfx0::getPalPtr(void) {
  return pal;
} // TGfx0::getPalPtr
UInt32 

TGfx0::getMaxX(void) {
  return MaxX;
} // TGfx0::getMaxX

UInt32 
TGfx0::getMaxY(void) {
  return MaxY;
} // TGfx0::getMaxY

UInt32 
TGfx0::getPixel(Int32 x, Int32 y) {
  UInt32 result;
  result = 42;
  if ((Buffer==NULL) || (LineOfs==NULL)) return TransparentColor;
  if (((UInt32)x>MaxX) || ((UInt32)y>MaxY)) 
    return TransparentColor;
  switch (BPP) {
  case 8:
    asm(
       "  add  %%esi, %%edi   \n"  // add     edi, esi
       "  add  %%ecx, %%edi   \n"  // add     edi, ecx
       " movzbl (%%edi),%%eax \n"  // movzx   edx,byte ptr [edi]
       "  mov  %%eax, %3      \n"  // mov     result, eax
       :
       : "D" (Buffer), "S" (LineOfs[y]),    // %0, %1
         "c" (x), "m" (result)              // %2, %3  
       );
    break;
  case 15:
  case 16:
    asm(
       "  add  %%esi, %%edi   \n"  // add     edi, esi
       "  add  %%ecx, %%ecx   \n"  // add     ecx, ecx {adjust for pixel size}
       "  add  %%ecx, %%edi   \n"  // add     edi, ecx
       "  movzwl (%%edi),%%eax \n" // movzx   edx,word ptr [edi]
       "  mov  %%eax, %3      \n"  // mov     result, eax
       :
       : "D" (Buffer), "S" (LineOfs[y]),    // %0, %1
         "c" (x), "m" (result)              // %2, %3
       );
    break;
  case 24:
    asm(
       "  mov  %%ecx, %%eax   \n"  // mov     eax, ecx  - adjust for pixel size 
       "  add  %%ecx, %%ecx   \n"  // add     ecx, ecx  - adjust for pixel size
       "  add  %%eax, %%ecx   \n"  // add     ecx, eax  - adjust for pixel size
       "  add  %%esi, %%edi   \n"  // add     edi, esi
    //   "  add  (%%esi,%%ebx,4), %%edi \n" //  add     edi, [esi + ebx*4]
       "  add  %%ecx, %%edi   \n"  // add     edi, ecx
       "  movzwl (%%edi),%%eax \n" // edx,word ptr [edi]
       "  xor  %%eax, %%eax   \n"  
       "  mov  2(%%edi), %%al \n"  // mov     al, [edi+2]
       "  shl  $16, %%eax     \n"  // shl     eax, 16
       "  mov  (%%edi), %%ax  \n"  // mov     ax, [edi]
       "  mov  %%eax, %3      \n"  // mov     result, eax
       :
       : "D" (Buffer), "S" (LineOfs[y]), // %0, %1
         "c" (x), "m" (result)           // %2, %3
       );
    break;
  case 32:
    asm(
       "  shl  $2, %%ecx      \n"  // shl     ecx, 2 {adjust for pixel size}
     //  "  add  (%%esi,%%ebx,4), %%edi \n" //  add     edi, [esi + ebx*4]
       "  add  %%esi, %%edi   \n"  // add     edi, esi
       "  add  %%ecx, %%edi   \n"  // add     edi, ecx
       "  mov  (%%edi),%%eax  \n"  // eax,word ptr [edi]
       "  mov  %%eax, %3      \n"  // mov     result, eax
       :
       : "D" (Buffer), "S" (LineOfs[y]), // %0, %1
         "c" (x), "m" (result)           // %2, %3
       );
  } // switch
  return result;
} // TGfx0::getPixel

void
TGfx0::getPixFmt(TPixelFmt& pixfmt) {
  pixfmt.BPP=BPP;
  pixfmt.RedFieldPosition=RedFieldPosition;
  pixfmt.GreenFieldPosition=GreenFieldPosition;
  pixfmt.BlueFieldPosition=BlueFieldPosition;
  pixfmt.RedMaskSize=8-RedShifter;
  pixfmt.GreenMaskSize=8-GreenShifter;
  pixfmt.BlueMaskSize=8-BlueShifter;
} // TGfx0::getPixFmt

UInt32
TGfx0::getTransparentColor(void) {
  return TransparentColor;
} // TGfx0::getTransparentColor

void
TGfx0::hFlip(void) {
  void * tmpBuf;
  UInt32 xWidth, count;
  if ((Buffer==NULL) || (LineOfs==NULL)) return;
  xWidth = (MaxX+1)*((BPP+7) >> 3);
  tmpBuf = malloc(xWidth);
  if (tmpBuf == NULL) return;
  for (count=0; count<=(MaxY/2); count++) {
    memcpy(tmpBuf,((char*)Buffer+LineOfs[count]),xWidth); 
    memcpy(((char*)Buffer+LineOfs[count]),
           ((char*)Buffer+LineOfs[MaxY-count]),
           xWidth);
    memcpy(((char*)Buffer+LineOfs[MaxY-count]),tmpBuf,xWidth);
  } // for
  free(tmpBuf);
  return;
} // TGfx0::hFlip

void
TGfx0::hLine(Int32 x1, Int32 x2, Int32 y, UInt32 colour) {
  Int32 tmp;

  if ((Buffer==NULL) || (LineOfs==NULL)) return;
  if ((UInt32)y>MaxY) return;
  if (x1>x2) {
    tmp= x1;
    x1 = x2;
    x2 = tmp;
  } // if
  if (x1<0) x1 = 0;
  if (x2>(Int32)MaxX) x1=MaxX;
  if (x2<x1) return;
  asm("cld \n");
  switch (BPP) {
  case 8:
    asm(
        "  add  %%ebx, %%edi  \n"          //  add      edi, ebx
        "  add  %%esi, %%edi  \n"          //  add      edi, esi
        "  and  $0xff, %%eax  \n"          //  and      eax, 0ffh
        "  sub  %%ebx, %%ecx  \n"          //  sub      ecx, ebx
        "  mov  %%al, %%ah    \n"          //  mov	ah, al
        "  inc  %%ecx         \n"          //  inc      ecx
        "  mov  %%eax, %%ebx  \n"          //  mov      ebx, eax
        "  shl  $16, %%ebx    \n"          //  shl      ebx, 16
        "  add  %%ebx, %%eax  \n"          //  add      eax, ebx

        "  mov  %%ecx, %%edx  \n"          //  mov      edx, ecx
        "  mov  $4, %%ecx     \n"          //  mov      ecx, 4
        "  sub  %%edi, %%ecx  \n"          //  sub      ecx, edi
        "  and  $3, %%ecx     \n"          //  and      ecx, 3
        "  sub  %%ecx, %%edx  \n"          //  sub      edx, ecx
        "   jle LEndBytes     \n"
        "  rep                \n"          
        "  stosb              \n"
        "  mov  %%edx, %%ecx  \n"          //  mov      ecx, edx
        "  and  $3, %%edx     \n"          //  and      edx, 3
        "  shr  $2, %%ecx     \n"          //  shr      ecx, 2
        "  rep                \n"
        "  stosl              \n"
    "LEndBytes:               \n"
        "  add  %%edx, %%ecx  \n"          //  add      ecx, edx
        "  rep                \n"
        "  stosb              \n"
        :
        : "D" (Buffer), "S" (LineOfs[y]),           // %0, %1
          "a" (colour), "b" (x1),                   // %2, %3
          "c" (x2) 
       );
    break;
  case 15:
  case 16:
    asm(
        "  sub  %%ebx, %%ecx  \n"          //  sub      ecx, ebx
        "  add  %%ebx, %%ebx  \n"          //  add      ebx, ebx - pix size
        "  inc  %%ecx         \n"          //  inc      ecx
        "  add  %%ebx, %%edi  \n"          //  add      edi, ebx
        "  add  %%esi, %%edi  \n"          //  add      edi, esi
        "  xor  %%edx, %%edx  \n"          //  xor      edx, edx
        "  mov  %%ax, %%dx    \n"          //  mov      dx, ax
        "  shl  $16, %%eax    \n"          //  shl      eax, 16
        "  add  %%edx, %%eax  \n"          //  add      eax, edx

        "  shr  $1, %%ecx     \n"          //  shr      ecx, 1
        "  rep                \n"
        "  stosl              \n"
        "   jnc hLnoc16       \n"
        "  stosw              \n"
        "hLnoc16:             \n"
        :
        : "D" (Buffer), "S" (LineOfs[y]),           // %0, %1
          "a" (colour), "b" (x1),                   // %2, %3
          "c" (x2)                                  // %4
    );
    break;
  case 24:
    asm(
        "  sub  %%ebx, %%ecx  \n"          //  sub      ecx, ebx
        "  add  %%esi, %%edi  \n"          //  add      edi, esi
        "  add  %%ebx, %%ebx  \n"          //  add      ebx, ebx - pix size
        "  inc  %%ecx         \n"          //  inc      ecx
        "  add  %%edx, %%ebx  \n"          //  add      ebx, edx - pix size
        "  add  %%ebx, %%edi  \n"          //  add      edi, ebx
        "  mov  %%eax, %%ebx  \n"          //  mov      ebx, eax
        "  shr	$16, %%ebx    \n"          //  shr      ebx, 16
    "hLlop24:                 \n"          
        "  mov  %%ax, (%%edi) \n"          //  mov      [edi], ax
        "  mov  %%bl, 2(%%edi)\n"          //  mov      [edi+2], bl
        "  add  $3, %%edi     \n"          //  add      edi, 3
        "  dec  %%ecx         \n"          //  dec      ecx
        "   jnz hLlop24       \n"          
        :
        : "D" (Buffer), "S" (LineOfs[y]),           // %0, %1
          "a" (colour), "b" (x1),                   // %2, %3
          "c" (x2), "d" (x1)                        // %4, %5
    );
    break;
  case 32:
    asm(
        "  sub  %%ebx, %%ecx  \n"          //  sub      ecx, ebx
        "  add  %%esi, %%edi  \n"          //  add      edi, esi
        "  inc  %%ecx         \n"
        "  shl  $2, %%ebx     \n"          //  shl      ebx, 2
        "  add  %%ebx, %%edi  \n"          //  add      edi, ebx
        "  rep                \n"
        "  stosl              \n"   
        :
        : "D" (Buffer), "S" (LineOfs[y]),           // %0, %1
          "a" (colour), "b" (x1),                   // %2, %3
          "c" (x2)                                  // %4
    );

    break;
  } // switch
  return;
} // TGfx0::hLine

void
TGfx0::line(Int32 x1, Int32 y1, Int32 x2, Int32 y2, UInt32 colour) {
  if (clipLine(x1,y1,x2,y2)) rawLine(x1,y1,x2,y2,colour);
  return;
} // TGfx0::line

void 
TGfx0::putPixel(UInt32 x, UInt32 y, UInt32 colour) {
  if ((Buffer==NULL) || (LineOfs==NULL)) return;
  if (((UInt32)x>MaxX) || ((UInt32)y>MaxY)) return;
  switch (BPP) {
  case 8:
    asm(
    // { Calculate offset, prepare the pixel to be drawn }
    //    "  add  (%%esi,%%ebx,4), %%edi \n" // add     edi, [esi + ebx * 4]
        "  add  %%esi, %%edi  \n"          // add     edi, esi
        "  mov  %3, %%eax     \n"          // mov     eax, colour
        "  add  %%ecx, %%edi  \n"          // add     edi, ecx
    // { Draw the pixel }
        "  mov  %%al, (%%edi) \n"          // mov     [edi], al
        :
        : "D" (Buffer), "S" (LineOfs[y]),           // %0, %1
          "c" (x), "m" (colour)                     // %2, %3
   );
   break;
   case 15:
   case 16:
     asm(
    // { Calculate offset, prepare the pixel to be drawn }
//        "  add  (%%esi,%%ebx,4), %%edi \n" // add     edi, [esi + ebx * 4]
        "  add  %%ecx, %%ecx  \n"  // add     ecx, ecx {adjust for pixel size}
        "  add  %%esi, %%edi  \n"  // add     edi, esi
        "  mov  %3, %%eax     \n"  // mov     eax, colour
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
    // { Draw the pixel }
        "  mov  %%ax, (%%edi) \n"  // mov     [edi], al
        :
        : "D" (Buffer), "S" (LineOfs[y]),        // %0, %1
          "c" (x), "m" (colour)                  // %2, %3
     );
     break;
   case 24:
     asm(
    // { Calculate offset, prepare the pixel to be drawn }
 //       "  add  (%%esi,%%ebx,4),%%edi \n" // add     edi, [esi + ebx * 4]
        "  add  %%esi, %%edi  \n"  // add     edi, esi
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx {adjust for pixel size}
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx {adjust for pixel size}
    // { Draw the pixel }
        "  mov  %%ax, (%%edi) \n"  // mov     [edi], ax
        "  shr  $16, %%eax    \n"  // shr     eax, 16
        "  mov  %%al, 2(%%edi)\n"  // mov     [edi+2],al
        :
        : "D" (Buffer), "S" (LineOfs[y]),        // %0, %1
          "c" (x), "a" (colour)                  // %2, %3
    );
    break;
  case 32:
     asm(
    // { Calculate offset, prepare the pixel to be drawn }
        "  shl  $2, %%ecx     \n"  // shl     eax, 2 {adjust for pixel size}
        "  add  %%esi, %%edi  \n"  // add     edi, esi
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
    // { Draw the pixel }
        "  mov  %%eax, (%%edi) \n" // mov     [edi], eax
        :
        : "D" (Buffer), "S" (LineOfs[y]),        // %0, %1
          "c" (x), "a" (colour)                  // %2, %3
    );
  } // switch
  return;
} // TGfx0::putPixel

void
TGfx0::rawLine(UInt32 x1, UInt32 y1, UInt32 x2, UInt32 y2, UInt32 colour) {
  /*
   *  TGfx0::rawLine()
   *
   *  private method; draws an unclipped line from (x1,y1) to (x2,y2)
   *
   */
   Int32 tc;
   if ((Buffer==NULL) || (LineOfs==NULL)) return;
   switch (BPP) {
   case 8:
     asm(
        "  mov  $1, %%ecx     \n"  // mov     ecx, 1
        "  bt   $15, %%eax    \n"  // bt      eax, 15
        "   jnc rlxPositive8  \n"  
        "  or   $-1, %%ecx    \n"  // or      ecx, -1
        "  neg  %%eax         \n"  // neg     eax
"rlxPositive8:                \n"
        "  add  %%eax, %%eax  \n"  // add     eax, eax
        "  bt   $15, %%ebx    \n"  // bt      ebx, 15
        "   jnc rlyPositive8  \n" 
        "  neg  %%edx         \n"  // neg     edx
        "  neg  %%ebx         \n"  // neg     ebx
"rlyPositive8:                \n"
        "  add  %%ebx, %%ebx  \n"  // add     ebx, ebx

        "  cmp  %%ebx, %%eax  \n"  // cmp     eax, ebx
        "   jle rlyGreater8   \n"  
        "  push %%ecx         \n"  // push    ecx
        "  mov  %%eax, %%ecx  \n"  // mov     ecx, eax
        "  mov  %%ebx, %6     \n"  // mov     tc, ebx
        "  shr  $1, %%ecx     \n"  // shr     ecx, 1
        "  sub  %%ecx, %6     \n"  // sub     tc, ecx
        "  pop  %%ecx         \n"  // pop     ecx
"rlxTop8:                     \n"
        "  push %%eax         \n"  // push    eax
        "  mov  %5, %%eax     \n"  // mov     eax, colour
        "  mov  %%al, (%%edi) \n"  // mov     [edi], al
        "  pop  %%eax         \n"  // pop     eax
        "  cmp  %%edi, %%esi  \n"  // cmp     esi, edi
        "   je  rlDone8       \n" 
        "  cmp  $0, %6        \n"  // cmp     tc, 0
        "   jl  rlNoAddY8     \n"  
        "  add  %%edx, %%edi  \n"  // add     edi, edx
        "  sub  %%eax, %6     \n"  // sub     tc, eax
"rlNoAddY8:                   \n"
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
        "  add  %%ebx, %6     \n"  // add     tc, ebx
        "   jmp rlxTop8       \n"

"rlyGreater8:                 \n"
        "  push %%ecx         \n"  // push    ecx
        "  mov  %%ebx, %%ecx  \n"  // mov     ecx, ebx
        "  mov  %%eax, %6     \n"  // mov     tc, eax
        "  shr  $1, %%ecx     \n"  // shr     ecx, 1
        "  sub  %%ecx, %6     \n"  // sub     tc, ecx
        "  pop  %%ecx         \n"
"rlyTop8:                     \n"
        "  push %%eax         \n"  // push    eax
        "  mov  %5, %%eax     \n"  // mov     eax, colour
        "  mov  %%al, (%%edi) \n"  // mov     [edi], al
        "  pop  %%eax         \n"  // pop     eax
        "  cmp  %%edi, %%esi  \n"  // cmp     esi, edi
        "   je  rlDone8       \n"
        "  cmp  $0, %6        \n"  // cmp     tc, 0
        "   jl  rlNoAddX8     \n"
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
        "  sub  %%ebx, %6     \n"  // sub     tc, ebx
"rlNoAddX8:                   \n"
        "  add  %%edx, %%edi  \n"  // add     edi, edx
        "  add  %%eax, %6     \n"  // add     tc, eax
        "   jmp rlyTop8       \n"
"rlDone8:                     \n"
        : 
        :  "D" ((UInt8 *)Buffer+LineOfs[y1]+x1),   // %0
           "S" ((UInt8 *)Buffer+LineOfs[y2]+x2),   // %1
           "a" (x2-x1), "b" (y2-y1),               // %2, %3
           "d" (xRes), "g" (colour),               // %4, %5
           "g" (tc)                                // %6
        );
     break;
   case 15:
   case 16:
     asm(
        "  mov  $1, %%ecx     \n"  // mov     ecx, 1
        "  bt   $15, %%eax    \n"  // bt      eax, 15
        "   jnc rlxPositive16 \n"  
        "  or   $-1, %%ecx    \n"  // or      ecx, -1
        "  neg  %%eax         \n"  // neg     eax
"rlxPositive16:               \n"
        "  add  %%eax, %%eax  \n"  // add     eax, eax
        "  bt   $15, %%ebx    \n"  // bt      ebx, 15
        "   jnc rlyPositive16 \n" 
        "  neg  %%edx         \n"  // neg     edx
        "  neg  %%ebx         \n"  // neg     ebx
"rlyPositive16:               \n"
        "  add  %%ebx, %%ebx  \n"  // add     ebx, ebx

        "  cmp  %%ebx, %%eax  \n"  // cmp     eax, ebx
        "   jle rlyGreater16  \n"  
        "  push %%ecx         \n"  // push    ecx
        "  mov  %%eax, %%ecx  \n"  // mov     ecx, eax
        "  mov  %%ebx, %6     \n"  // mov     tc, ebx
        "  shr  $1, %%ecx     \n"  // shr     ecx, 1
        "  sub  %%ecx, %6     \n"  // sub     tc, ecx
        "  pop  %%ecx         \n"  // pop     ecx
"rlxTop16:                    \n"
        "  push %%eax         \n"  // push    eax
        "  mov  %5, %%eax     \n"  // mov     eax, colour
        "  mov  %%ax, (%%edi) \n"  // mov     [edi], ax
        "  pop  %%eax         \n"  // pop     eax
        "  cmp  %%edi, %%esi  \n"  // cmp     esi, edi
        "   je  rlDone16      \n" 
        "  cmp  $0, %6        \n"  // cmp     tc, 0
        "   jl  rlNoAddY16    \n"  
        "  add  %%edx, %%edi  \n"  // add     edi, edx
        "  sub  %%eax, %6     \n"  // sub     tc, eax
"rlNoAddY16:                  \n"
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  - pix size
        "  add  %%ebx, %6     \n"  // add     tc, ebx
        "   jmp rlxTop16      \n"

"rlyGreater16:                \n"
        "  push %%ecx         \n"  // push    ecx
        "  mov  %%ebx, %%ecx  \n"  // mov     ecx, ebx
        "  mov  %%eax, %6     \n"  // mov     tc, eax
        "  shr  $1, %%ecx     \n"  // shr     ecx, 1
        "  sub  %%ecx, %6     \n"  // sub     tc, ecx
        "  pop  %%ecx         \n"
"rlyTop16:                    \n"
        "  push %%eax         \n"  // push    eax
        "  mov  %5, %%eax     \n"  // mov     eax, colour
        "  mov  %%ax, (%%edi) \n"  // mov     [edi], ax
        "  pop  %%eax         \n"  // pop     eax
        "  cmp  %%edi, %%esi  \n"  // cmp     esi, edi
        "   je  rlDone16      \n"
        "  cmp  $0, %6        \n"  // cmp     tc, 0
        "   jl  rlNoAddX16    \n"
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  - pix size
        "  sub  %%ebx, %6     \n"  // sub     tc, ebx
"rlNoAddX16:                  \n"
        "  add  %%edx, %%edi  \n"  // add     edi, edx
        "  add  %%eax, %6     \n"  // add     tc, eax
        "   jmp rlyTop16      \n"
"rlDone16:                    \n"
        : 
        :  "D" ((UInt8 *)Buffer+LineOfs[y1]+(x1 << 1)),   // %0
           "S" ((UInt8 *)Buffer+LineOfs[y2]+(x2 << 1)),   // %1
           "a" (x2-x1), "b" (y2-y1),                      // %2, %3
           "d" (xRes), "g" (colour),                      // %4, %5
           "g" (tc)                                       // %6
        );
     break;
   case 24:
     asm(
        "  mov  $1, %%ecx     \n"  // mov     ecx, 1
        "  bt   $15, %%eax    \n"  // bt      eax, 15
        "   jnc rlxPositive24 \n"  
        "  or   $-1, %%ecx    \n"  // or      ecx, -1
        "  neg  %%eax         \n"  // neg     eax
"rlxPositive24:               \n"
        "  add  %%eax, %%eax  \n"  // add     eax, eax
        "  bt   $15, %%ebx    \n"  // bt      ebx, 15
        "   jnc rlyPositive24 \n" 
        "  neg  %%edx         \n"  // neg     edx
        "  neg  %%ebx         \n"  // neg     ebx
"rlyPositive24:               \n"
        "  add  %%ebx, %%ebx  \n"  // add     ebx, ebx

        "  cmp  %%ebx, %%eax  \n"  // cmp     eax, ebx
        "   jle rlyGreater24  \n"  
        "  push %%ecx         \n"  // push    ecx
        "  mov  %%eax, %%ecx  \n"  // mov     ecx, eax
        "  mov  %%ebx, %6     \n"  // mov     tc, ebx
        "  shr  $1, %%ecx     \n"  // shr     ecx, 1
        "  sub  %%ecx, %6     \n"  // sub     tc, ecx
        "  pop  %%ecx         \n"  // pop     ecx
"rlxTop24:                    \n"
        "  push %%eax         \n"  // push    eax
        "  mov  %5, %%eax     \n"  // mov     eax, colour
        "  mov  %%ax, (%%edi) \n"  // mov     [edi], ax
        "  shr  $16, %%eax    \n"  // shr     eax, 16
        "  mov  %%al, 2(%%edi)\n"  // mov     [edi+2],al
        "  pop  %%eax         \n"  // pop     eax
        "  cmp  %%edi, %%esi  \n"  // cmp     esi, edi
        "   je  rlDone24      \n" 
        "  cmp  $0, %6        \n"  // cmp     tc, 0
        "   jl  rlNoAddY24    \n"  
        "  add  %%edx, %%edi  \n"  // add     edi, edx
        "  sub  %%eax, %6     \n"  // sub     tc, eax
"rlNoAddY24:                  \n"
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  - pix size
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx 
        "  add  %%ebx, %6     \n"  // add     tc, ebx
        "   jmp rlxTop24      \n"

"rlyGreater24:                \n"
        "  push %%ecx         \n"  // push    ecx
        "  mov  %%ebx, %%ecx  \n"  // mov     ecx, ebx
        "  mov  %%eax, %6     \n"  // mov     tc, eax
        "  shr  $1, %%ecx     \n"  // shr     ecx, 1
        "  sub  %%ecx, %6     \n"  // sub     tc, ecx
        "  pop  %%ecx         \n"
"rlyTop24:                    \n"
        "  push %%eax         \n"  // push    eax
        "  mov  %5, %%eax     \n"  // mov     eax, colour
        "  mov  %%ax, (%%edi) \n"  // mov     [edi], ax
        "  shr  $16, %%eax    \n"  // shr     eax, 16
        "  mov  %%al, 2(%%edi)\n"  // mov     [edi+2],al
        "  pop  %%eax         \n"  // pop     eax
        "  cmp  %%edi, %%esi  \n"  // cmp     esi, edi
        "   je  rlDone24      \n"
        "  cmp  $0, %6        \n"  // cmp     tc, 0
        "   jl  rlNoAddX24    \n"
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx 
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  - pix size
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  
        "  sub  %%ebx, %6     \n"  // sub     tc, ebx
"rlNoAddX24:                  \n"
        "  add  %%edx, %%edi  \n"  // add     edi, edx
        "  add  %%eax, %6     \n"  // add     tc, eax
        "   jmp rlyTop24      \n"
"rlDone24:                    \n"
        : 
        :  "D" ((UInt8 *)Buffer+LineOfs[y1]+(x1*3)),   // %0
           "S" ((UInt8 *)Buffer+LineOfs[y2]+(x2*3)),   // %1
           "a" (x2-x1), "b" (y2-y1),                   // %2, %3
           "d" (xRes), "g" (colour),                   // %4, %5
           "g" (tc)                                    // %6
        );
     break;
   case 32:
     asm(
        "  mov  $1, %%ecx     \n"  // mov     ecx, 1
        "  bt   $15, %%eax    \n"  // bt      eax, 15
        "   jnc rlxPositive32 \n"  
        "  or   $-1, %%ecx    \n"  // or      ecx, -1
        "  neg  %%eax         \n"  // neg     eax
"rlxPositive32:               \n"
        "  add  %%eax, %%eax  \n"  // add     eax, eax
        "  bt   $15, %%ebx    \n"  // bt      ebx, 15
        "   jnc rlyPositive32 \n" 
        "  neg  %%edx         \n"  // neg     edx
        "  neg  %%ebx         \n"  // neg     ebx
"rlyPositive32:               \n"
        "  add  %%ebx, %%ebx  \n"  // add     ebx, ebx

        "  cmp  %%ebx, %%eax  \n"  // cmp     eax, ebx
        "   jle rlyGreater32  \n"  
        "  push %%ecx         \n"  // push    ecx
        "  mov  %%eax, %%ecx  \n"  // mov     ecx, eax
        "  mov  %%ebx, %6     \n"  // mov     tc, ebx
        "  shr  $1, %%ecx     \n"  // shr     ecx, 1
        "  sub  %%ecx, %6     \n"  // sub     tc, ecx
        "  pop  %%ecx         \n"  // pop     ecx
"rlxTop32:                    \n"
        "  push %%eax         \n"  // push    eax
        "  mov  %5, %%eax     \n"  // mov     eax, colour
        "  mov  %%eax, (%%edi)\n"  // mov     [edi], eax
        "  pop  %%eax         \n"  // pop     eax
        "  cmp  %%edi, %%esi  \n"  // cmp     esi, edi
        "   je  rlDone32      \n" 
        "  cmp  $0, %6        \n"  // cmp     tc, 0
        "   jl  rlNoAddY32    \n"  
        "  add  %%edx, %%edi  \n"  // add     edi, edx
        "  sub  %%eax, %6     \n"  // sub     tc, eax
"rlNoAddY32:                  \n"
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  - pix size
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  - pix size
        "  add  %%ebx, %6     \n"  // add     tc, ebx
        "   jmp rlxTop32      \n"

"rlyGreater32:                \n"
        "  push %%ecx         \n"  // push    ecx
        "  mov  %%ebx, %%ecx  \n"  // mov     ecx, ebx
        "  mov  %%eax, %6     \n"  // mov     tc, eax
        "  shr  $1, %%ecx     \n"  // shr     ecx, 1
        "  sub  %%ecx, %6     \n"  // sub     tc, ecx
        "  pop  %%ecx         \n"
"rlyTop32:                    \n"
        "  push %%eax         \n"  // push    eax
        "  mov  %5, %%eax     \n"  // mov     eax, colour
        "  mov  %%eax, (%%edi)\n"  // mov     [edi], eax
        "  pop  %%eax         \n"  // pop     eax
        "  cmp  %%edi, %%esi  \n"  // cmp     esi, edi
        "   je  rlDone32      \n"
        "  cmp  $0, %6        \n"  // cmp     tc, 0
        "   jl  rlNoAddX32    \n"
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  - pix size
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx  - pix size
        "  add  %%ecx, %%edi  \n"  // add     edi, ecx
        "  sub  %%ebx, %6     \n"  // sub     tc, ebx
"rlNoAddX32:                  \n"
        "  add  %%edx, %%edi  \n"  // add     edi, edx
        "  add  %%eax, %6     \n"  // add     tc, eax
        "   jmp rlyTop32      \n"
"rlDone32:                    \n"
        : 
        :  "D" ((UInt8 *)Buffer+LineOfs[y1]+(x1 << 2)),   // %0
           "S" ((UInt8 *)Buffer+LineOfs[y2]+(x2 << 2)),   // %1
           "a" (x2-x1), "b" (y2-y1),               // %2, %3
           "d" (xRes), "g" (colour),               // %4, %5
           "g" (tc)                                // %6
        );
     break;
   } // switch
  return;
} // TGfx0::rawLine

UInt32 
TGfx0::RGB(UInt8 red, UInt8 green, UInt8 blue) {
  UInt32 lastclr;
  lastclr=0;
  switch (BPP) {
  case 8:
    asm(
      "  movl  $256,%%ecx     \n"
      "  movl  $256*3+1,%%ebx \n"
      "  xor   %%eax,%%eax    \n"
      "lop:                   \n"
      "  pushl %%eax          \n"
      "  mov   (%%esi),%%al   \n"
      "  incl  %%esi          \n"
      "  sub   %1,%%al        \n"
      "  jns   abs1           \n"
      "  neg   %%al           \n"
      "abs1:                  \n"
      "  movl   %%eax,%%edi   \n"
      "  mov   (%%esi),%%al   \n"
      "  incl  %%esi          \n"
      "  sub   %2,%%al        \n"
      "  jns   abs2           \n"
      "  neg   %%al           \n"
      "abs2:                  \n"
      "  addl  %%eax,%%edi    \n"
      "  mov   (%%esi),%%al   \n"
      "  incl  %%esi          \n"
      "  sub   %3,%%al        \n"
      "  jns   abs3           \n"
      "  neg   %%al           \n"
      "abs3:                  \n"
      "  addl  %%eax,%%edi    \n"
      "  popl  %%eax          \n"
      "  cmpl  %%ebx,%%edi    \n"
      "  jae   no_good_match  \n"
      "  movl  %%edi,%%ebx    \n"
      "  movl  %%eax,%4       \n"
      "no_good_match:         \n"
      "  incl  %%eax          \n"
      "  decl  %%ecx          \n"
      "  jnz   lop            \n"
      : 
      : "S" (pal), "m" (red), "m" (green), "m" (blue), "m" (lastclr)
      );
    break;
  case 15:
  case 16:
    asm(
      "  xor  %%eax, %%eax    \n"
      "  xor  %%ebx, %%ebx    \n"
      "  xor  %%ecx, %%ecx    \n"
      "  mov  %0, %%al        \n"  // mov al, red
      "  mov  %3, %%cl        \n"  // mov cl, RedShifter
      "  shr  %%cl, %%al      \n"  // shr al, cl
      "  mov  %4, %%cl        \n"  // mov cl, RedFieldPosition
      "  shl  %%cl, %%eax     \n"  // shl eax, cl
      "  mov  %%eax, %%ebx    \n"  // mov ebx, eax
      "  xor  %%eax, %%eax    \n"  // xor eax, eax
      "  mov  %1, %%al        \n"  // mov al, green
      "  mov  %5, %%cl        \n"  // mov cl, GreenShifter
      "  shr  %%cl, %%al      \n"  // shr al, cl
      "  mov  %6, %%cl        \n"  // mov cl, GreenFieldPosition
      "  shl  %%cl, %%eax     \n"  // shl eax, cl
      "  or   %%eax, %%ebx    \n"  // or eax, ebx
      "  xor  %%eax, %%eax    \n"  // xor eax, eax
      "  mov  %2, %%al        \n"  // mov al, blue
      "  mov  %7, %%cl        \n"  // mov cl, BlueShifter
      "  shr  %%cl, %%al      \n"  // shr al, cl
      "  mov  %8, %%cl        \n"  // mov cl, BlueFieldPosition
      "  shl  %%cl, %%eax     \n"  // shl eax, cl
      "  or   %%ebx, %%eax    \n"  // or eax, ebx
      "  mov  %%eax, %9       \n"  // mov lastclr, eax
      : 
      : "m" (red), "m" (green), "m" (blue),           // %0, %1, %2
        "m" (RedShifter), "m" (RedFieldPosition),     // %3, %4
        "m" (GreenShifter), "m" (GreenFieldPosition), // %5, %6
        "m" (BlueShifter), "m" (BlueFieldPosition),   // %7, %8
        "m" (lastclr)                                 // %9
    );
    break;
  case 24:
  case 32:
    asm(
      "  xor  %%eax, %%eax    \n"  // xor     eax, eax
      "  xor  %%ebx, %%ebx    \n"  // xor     ebx, ebx
      "  xor  %%ecx, %%ecx    \n"  // xor     ecx, ecx

      "  mov  %0, %%al        \n"  // mov     al, red
      "  mov  %3, %%cl        \n"  // mov    cl, RedFieldPosition
      "  shl  %%cl, %%eax     \n"  // shl     eax, cl
      "  mov  %%eax, %%ebx    \n"  // mov     ebx, eax
      "  xor  %%eax, %%eax    \n"  // xor     eax, eax
      "  mov  %1, %%al        \n"  // mov     al, green
      "  mov  %4, %%cl        \n"  // mov     cl, GreenFieldPosition
      "  shl  %%cl, %%eax     \n"  // shl     eax, cl
      "  or   %%eax, %%ebx    \n"  // or      ebx, eax
      "  xor  %%eax, %%eax    \n"  // xor     eax, eax
      "  mov  %2, %%al        \n"  // mov     al, blue
      "  mov  %5, %%cl        \n"  // mov     cl, BlueFieldPosition
      "  shl  %%cl, %%eax     \n"  // shl     eax, cl
      "  or   %%ebx, %%eax    \n"  // or      eax, ebx
      "  mov  %%eax, %6       \n"  // mov     lastclr, eax
      :
      : "m" (red), "m" (green), "m" (blue),  // %0, %1, %2
        "m" (RedFieldPosition),              // %3
        "m" (GreenFieldPosition),            // %4
        "m" (BlueFieldPosition),             // %5
        "m" (lastclr)                        // %6
    );
  } // switch
  //asm("": "=a" (lastclr));
  return lastclr;
} // TGfx0::RGB

void 
TGfx0::setRGBPalette(UInt8 colour, UInt8 red, UInt8 green, UInt8 blue) {
  if (!pal) return;
  pal[colour].red = red;
  pal[colour].green = green;
  pal[colour].blue = blue;
  return;
} // TGfx0::setRGBPalette

void
TGfx0::rect(Int32 x1, Int32 y1, Int32 x2, Int32 y2, UInt32 colour) {
  hLine(x1,x2,y1,colour);  // Horizline has built in clipping
  vLine(x2,y1,y2,colour);  // vertline has built in clipping too
  vLine(x1,y1,y2,colour);
  hLine(x1,x2,y2,colour);
  return;
} // TGfx0::rectangle

void 
TGfx0::unpackRGB(UInt32 colour, UInt8& red, UInt8& green, UInt8& blue) {
  switch (BPP) {
  case 8:
    if (!pal) {
      red = 0;
      green = 0;
      blue = 0;
      return;
    }
    if (colour>255) colour=colour & 255;
    red   = pal[colour].red;
    green = pal[colour].green;
    blue  = pal[colour].blue; 
    break;
  case 15:
  case 16:
    red   = ((colour >> RedFieldPosition) << RedShifter);
    green = ((colour >> GreenFieldPosition) << GreenShifter);
    blue  = ((colour >> BlueFieldPosition) << BlueShifter);
    if ((red) && (RedShifter)) red+=(1 << RedShifter)-1;
    if ((green) && (GreenShifter)) green+=(1 << GreenShifter)-1;
    if ((blue) && (BlueShifter)) blue+=(1 << BlueShifter)-1;
    break;
  case 24:
  case 32:
    red   = colour >> RedFieldPosition;
    green = colour >> GreenFieldPosition;
    blue  = colour >> BlueFieldPosition;
    break;
  default:
    red   = 0;
    green = 0;
    blue  = 0;
  }
  return;
} // TGfx0::unpackRGB

void
TGfx0::vFlip(void) {
  return;
} // TGfx0::vFlip

void
TGfx0::vLine(Int32 x, Int32 y1, Int32 y2, UInt32 colour) {
  Int32 tmp;
  if ((Buffer==NULL) || (LineOfs==NULL)) return;
  if ((UInt32)x>MaxX) return;
  if (y1>y2) {
    tmp= y1;
    y1 = y2;
    y2 = tmp;
  } // if
  if (y1<0) y1 = 0;
  if (y2>(Int32)MaxY) y2 = MaxY;
  if (y2<y1) return;
  switch (BPP) {
  case 8:
    asm(
        "  add  %%esi, %%edi  \n"          //  add      edi, esi
        "  mov  %6, %%esi     \n"          //  mov      esi, y1
        "  sub  %%esi, %%ecx  \n"          //  sub      ecx, esi
        "  add  %%ebx, %%edi  \n"          //  add      edi, ebx
        "  inc  %%ecx         \n"          //  inc      ecx
        "vLlop8:              \n"          
        "  mov  %%al, (%%edi) \n"          //  mov      [edi], al
        "  add  %%edx, %%edi  \n"          //  add      edi, edx
        "  dec  %%ecx         \n"          //  dec      ecx
        "   jnz vLlop8        \n"
        :
        : "D" (Buffer), "S" (LineOfs[y1]),          // %0, %1
          "a" (colour), "b" (x),                    // %2, %3
          "c" (y2), "d" (xRes),                     // %4, %5
          "m" (y1)                                  // %6
       );
    break;
  case 15:
  case 16:
    asm(
        "  add  %%esi, %%edi  \n"          //  add      edi, esi
        "  add  %%ebx, %%ebx  \n"          //  add      ebx, ebx - pix size
        "  mov  %6, %%esi     \n"          //  mov      esi, y1
        "  sub  %%esi, %%ecx  \n"          //  sub      ecx, esi
        "  add  %%ebx, %%edi  \n"          //  add      edi, ebx
        "  inc  %%ecx         \n"          //  inc      ecx
        "vLlop16:             \n"
        "  mov  %%ax, (%%edi) \n"          //  mov      [edi], ax
        "  add  %%edx, %%edi  \n"          //  add      edi, edx
        "  dec  %%ecx         \n"          //  dec      ecx
        "   jnz vLlop16       \n"
        :
        : "D" (Buffer), "S" (LineOfs[y1]),          // %0, %1
          "a" (colour), "b" (x),                    // %2, %3
          "c" (y2), "d" (xRes),                     // %4, %5
          "m" (y1)                                  // %6
       );
    break;
  case 24:
    asm(
        "  add  %%esi, %%edi  \n"          //  add      edi, esi
        "  mov  %%ebx, %%esi  \n"          //  mov      esi, ebx - pix size
        "  add  %%ebx, %%ebx  \n"          //  add      ebx, ebx - pix size
        "  add  %%esi, %%ebx  \n"          //  add      ebx, esi - pix size
        "  mov  %6, %%esi     \n"          //  mov      esi, y1
        "  sub  %%esi, %%ecx  \n"          //  sub      ecx, esi
        "  add  %%ebx, %%edi  \n"          //  add      edi, ebx
        "  inc  %%ecx         \n"          //  inc      ecx
        "  mov  %%eax, %%ebx  \n"          //  mov      ebx, eax
        "  shr  $16, %%ebx    \n"          //  shr      ebx, 16
        "vLlop24:             \n"
        "  mov  %%ax, (%%edi) \n"          //  mov      [edi], eax
        "  mov  %%bl, 2(%%edi)\n"          //  mov      [edi+2], bl
        "  add  %%edx, %%edi  \n"          //  add      edi, edx
        "  dec  %%ecx         \n"          //  dec      ecx
        "   jnz vLlop24       \n"
        :
        : "D" (Buffer), "S" (LineOfs[y1]),          // %0, %1
          "a" (colour), "b" (x),                    // %2, %3
          "c" (y2), "d" (xRes),                     // %4, %5
          "m" (y1)                                  // %6
       );
    break;
  case 32: 
    asm(
        "  add  %%esi, %%edi  \n"          //  add      edi, esi
        "  shl  $2, %%ebx     \n"          //  shl      ebx, 2  - pix size
        "  mov  %6, %%esi     \n"          //  mov      esi, y1
        "  sub  %%esi, %%ecx  \n"          //  sub      ecx, esi
        "  add  %%ebx, %%edi  \n"          //  add      edi, ebx
        "  inc  %%ecx         \n"          //  inc      ecx
        "vLlop32:             \n"
        "  mov  %%eax, (%%edi)\n"          //  mov      [edi],al
        "  add  %%edx, %%edi  \n"          //  add      edi, edx
        "  dec  %%ecx         \n"          //  dec      ecx
        "   jnz vLlop32       \n"
        :
        : "D" (Buffer), "S" (LineOfs[y1]),          // %0, %1
          "a" (colour), "b" (x),                    // %2, %3
          "c" (y2), "d" (xRes),                     // %4, %5
          "m" (y1)                                  // %6
       );
  } // switch
  return;
} // TGfx0::vLine

TGfx0::~TGfx0(void) {
  if (DataState == og_Owner) {
    if (pal!=NULL) free(pal);
    if (Buffer!=NULL) free(Buffer);
    if (LineOfs!=NULL) free(LineOfs);
  }  // if datastate
  pal    = NULL;
  LineOfs= NULL;
  Buffer = NULL;
  bSize  = 0;
  lSize  = 0;
  DataState = og_None;
  return;
} // TGfx0::~TGfx0

/*
 *
 *              TSCREEN METHODS     
 *
 */

TScreen::TScreen(void) {
  InGraphics = FALSE;
  VESARec = NULL;
  ModeRec = NULL;
  return;
} // TScreen::TScreen

void
TScreen::setupMode(UInt16 mode) {
  UInt32 size, count;
  // IsVesaInstalled();

  if (mode==gm320x200x256) {
    xRes = 320;
    yRes = 200;
    MaxX = 319;
    MaxY = 199;
    BPP  = 8;

    Buffer = (void *)0xA0000;

    RedFieldPosition = 0; 
    GreenFieldPosition = 0;
    BlueFieldPosition = 0;
    
    RedShifter = 0;
    GreenShifter = 0;
    BlueShifter = 0;
  } // if
  else {
    mode |= 0x4000;  // attempt lfb
    // GetModeInfo(mode);
    // mjikaboom
    ModeRec = (TMode_Rec *)0x1000;
    if (ModeRec->PhysBasePtr == 0) return;
    size = ModeRec->yRes*ModeRec->BytesPerLine;
//    Buffer = MapPhysicalToLinear(ModeRec->PhysBasePtr,size);
    
    // mjikaboom
    Buffer = (void *)0x40000000;
    xRes = ModeRec->BytesPerLine;
    yRes = ModeRec->yRes;
    MaxX = ModeRec->xRes-1;
    MaxY = yRes-1;

    RedFieldPosition = ModeRec->RedFieldPosition;
    GreenFieldPosition = ModeRec->GreenFieldPosition;
    BlueFieldPosition = ModeRec->BlueFieldPosition;

    RedShifter = 8-ModeRec->RedMaskSize;
    GreenShifter = 8-ModeRec->GreenMaskSize;
    BlueShifter = 8-ModeRec->BlueMaskSize;
  
    BPP = ModeRec->BitsPerPixel;
  } // else

  Owner = this;
 
  DataState = og_Aliasing;
  InGraphics = TRUE;

  if ((LineOfs!=NULL) && (lSize!=0)) free(LineOfs);
  lSize = yRes*sizeof(UInt32);
  LineOfs = (UInt32*)malloc(lSize);
  if (LineOfs == NULL) return;
  LineOfs[0] = 0;
  for (count=1; count<=yRes-1; count++) 
    LineOfs[count] = LineOfs[count-1]+xRes;
  // InitVESAMode(mode);
  if (pal==NULL) pal = (TRGB*)malloc(256*sizeof(TRGB));
  // getPal();
  return;
} // TScreen::setupMode

TScreen::~TScreen(void) {
  return;
}