/* $Id: bbtsub.c,v 1.3 2001/12/24 01:08:59 sybalsky Exp $ (C) Copyright Venue, All Rights Reserved
 */

/************************************************************************/
/*                                                                      */
/*                      File:   bbtsub.c                                */
/*                                                                      */
/*      Subroutines to support BITBLT, \BLTCHAR, and \TEDIT.BLTCHAR     */
/*      lisp functions, providing performance improvement.              */
/*                                                                      */
/*                                                                      */
/*                                                                      */
/*                                                                      */
/*                                                                      */
/*                                                                      */
/************************************************************************/

/************************************************************************/
/*									*/
/*	(C) Copyright 1989-99 Venue. All Rights Reserved.		*/
/*	Manufactured in the United States of America.			*/
/*									*/
/************************************************************************/

#include "version.h"

#include <stdio.h>
#include <stdlib.h>

#ifdef XWINDOW
#ifndef DOS
#include <sys/ioctl.h>
#endif /* DOS */
#include <sys/types.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include "xdefs.h"
#endif /* XWINDOW */


#include "lispemul.h"
#include "lspglob.h"
#include "lispmap.h"
#include "lsptypes.h"
#include "emlglob.h"
#include "adr68k.h"
#include "address.h"
#include "arith.h"
#include "stack.h"
#include "return.h"
#include "cell.h"
#include "gcdata.h"
#include "iopage.h"

#include "bbtsubdefs.h"
#include "car-cdrdefs.h"
#include "commondefs.h"
#include "gcarraydefs.h"
#include "initdspdefs.h"
#include "kprintdefs.h"
#include "llstkdefs.h"
#include "returndefs.h"

extern IOPAGE *IOPage68K;

#include "bb.h"
#include "bitblt.h"
#include "pilotbbt.h"
#include "dspdata.h"
#include "display.h"
#include "dbprint.h"

#ifdef INIT
#include "initkbddefs.h"
extern int  kbd_for_makeinit;

#define init_kbd_startup   \
  if (!kbd_for_makeinit) { \
    init_keyboard(0);      \
    kbd_for_makeinit = 1;  \
  };
#endif

#include "devif.h"
extern DspInterface currentdsp;

#ifdef COLOR
extern int MonoOrColor;
#endif /* COLOR */

/*******************************************/
/*  REALCURSOR is defined iff we need to   */
/*  take care of cursor movement & hiding  */
/*  (during bitblts to screen) ourselves.  */
/*******************************************/
#if defined(SUNDISPLAY) || defined(DOS)
#define REALCURSOR
#else
#undef REALCURSOR
#endif

/* same definition is in my.h */
#ifdef BIGVM
#define IsNumber(address) ((GETWORD(MDStypetbl + (((address)&0x0fffff00) >> 9))) & 0x1000)
#else
#define IsNumber(address) ((GETWORD(MDStypetbl + (((address)&0x0ffff00) >> 9))) & 0x1000)
#endif

#define BITSPERWORD (16) /* temp definition      */

#ifndef BYTESWAP
#ifdef BIGVM
typedef struct {
  unsigned nil1 : 4;
  unsigned pilotbbt : 28;
  unsigned nil2 : 4;
  unsigned displaydata : 28;
  unsigned nil3 : 16;
  unsigned char8code : 16;
  unsigned nil4 : 16;
  unsigned curx : 16;
  unsigned nil5 : 16;
  unsigned left : 16;
  unsigned nil6 : 16;
  unsigned right : 16;
} BLTC;
#else
typedef struct {
  unsigned nil1 : 8;
  unsigned pilotbbt : 24;
  unsigned nil2 : 8;
  unsigned displaydata : 24;
  unsigned nil3 : 16;
  unsigned char8code : 16;
  unsigned nil4 : 16;
  unsigned curx : 16;
  unsigned nil5 : 16;
  unsigned left : 16;
  unsigned nil6 : 16;
  unsigned right : 16;
} BLTC;
#endif /* BIGVM */
#else
#ifdef BIGVM
typedef struct {
  unsigned pilotbbt : 28;
  unsigned nil1 : 4;
  unsigned displaydata : 28;
  unsigned nil2 : 4;
  unsigned char8code : 16;
  unsigned nil3 : 16;
  unsigned curx : 16;
  unsigned nil4 : 16;
  unsigned left : 16;
  unsigned nil5 : 16;
  unsigned right : 16;
  unsigned nil6 : 16;
} BLTC;
#else
typedef struct {
  unsigned pilotbbt : 24;
  unsigned nil1 : 8;
  unsigned displaydata : 24;
  unsigned nil2 : 8;
  unsigned char8code : 16;
  unsigned nil3 : 16;
  unsigned curx : 16;
  unsigned nil4 : 16;
  unsigned left : 16;
  unsigned nil5 : 16;
  unsigned right : 16;
  unsigned nil6 : 16;
} BLTC;
#endif /* BIGVM */
#endif /* BYTESWAP */

/****************************************/
/*                                      */
/*      Arguments to NEWBLTCHAR                 */
/*                                      */
/****************************************/
#ifndef BYTESWAP
typedef struct {
  DLword nil;             /* Unused word */
  unsigned charset : 8;   /* High 8 bits of character code */
  unsigned char8code : 8; /* Low 8 bits of character code  */
  LispPTR displaystream;  /* The display stream to print on */
  LispPTR displaydata;    /* The image data (margins, etc)  */
} BLTARG;
#else
typedef struct {
  unsigned char8code : 8; /* Low 8 bits of character code  */
  unsigned charset : 8;   /* High 8 bits of character code */
  DLword nil;             /* Unused word */
  LispPTR displaystream;  /* The display stream to print on */
  LispPTR displaydata;    /* The image data (margins, etc)  */
} BLTARG;
#endif /* BYTESWAP */

#ifndef BYTESWAP
typedef struct tbta {
  DLword nil;
  unsigned charset : 8;
  unsigned char8code : 8;
  LispPTR displaystream;
  unsigned int nil2 : 16;
  unsigned int current_x : 16; /* this is always positive */
  LispPTR displaydata;
  LispPTR ddpilotbitblt;
  unsigned int nil3 : 16;
  unsigned int clipright : 16; /* this is always positive */
} TBLTARG;
#else
typedef struct tbta {
  unsigned char8code : 8;
  unsigned charset : 8;
  DLword nil;
  LispPTR displaystream;
  unsigned int current_x : 16; /* this is always positive */
  unsigned int nil2 : 16;
  LispPTR displaydata;
  LispPTR ddpilotbitblt;
  unsigned int clipright : 16; /* this is always positive */
  unsigned int nil3 : 16;
} TBLTARG;
#endif /* BYTESWAP */

extern int LispWindowFd;
extern int ScreenLocked; /* for mouse tracking */
/*****************************************************************
(PUTPROPS \SETPBTFUNCTION MACRO
        (OPENLAMBDA (BBT SourceType Operation)
                (PROGN (replace (PILOTBBT PBTOPERATION) of BBT with
                                (SELECTQ Operation
                                        (ERASE 1)
                                        (PAINT 2)
                                        (INVERT 3)
                                        0))
                       (replace (PILOTBBT PBTSOURCETYPE) of BBT with
                            (COND ((EQ (EQ SourceType (QUOTE INVERT))
                                       (EQ Operation (QUOTE ERASE))) 0)
                                  (T 1))))))
*****************************************************************/
#define PixOperationLisp(SRCTYPE, OPERATION)                                                       \
  ((SRCTYPE) == INVERT_atom                                                                        \
       ? ((OPERATION) == REPLACE_atom                                                              \
              ? PIX_NOT(PIX_SRC)                                                                   \
              : ((OPERATION) == PAINT_atom                                                         \
                     ? PIX_NOT(PIX_SRC) | PIX_DST                                                  \
                     : ((OPERATION) == ERASE_atom                                                  \
                            ? PIX_SRC & PIX_DST                                                    \
                            : ((OPERATION) == INVERT_atom ? PIX_NOT(PIX_SRC) ^ PIX_DST : ERROR)))) \
       : /*  SRCTYPE == INPUT, TEXTURE */                                                          \
       ((OPERATION) == REPLACE_atom                                                                \
            ? PIX_SRC                                                                              \
            : ((OPERATION) == PAINT_atom                                                           \
                   ? PIX_SRC | PIX_DST                                                             \
                   : ((OPERATION) == ERASE_atom                                                    \
                          ? PIX_NOT(PIX_SRC) & PIX_DST                                             \
                          : ((OPERATION) == INVERT_atom ? PIX_SRC ^ PIX_DST : ERROR)))))

#define bbop(SRCTYPE, OPERATION)                \
  ((OPERATION) == PAINT_atom                    \
       ? op_fn_or                               \
       : ((OPERATION) == ERASE_atom ? op_fn_and \
                                    : ((OPERATION) == INVERT_atom ? op_fn_xor : op_repl_src)))

/********************************************************/
/*                                                      */
/*                  b b s r c _ t y p e                         */
/*                                                      */
/*      Returns 1 if the source bits must be inverted   */
/*      as part of the BITBLT.  This is true if the     */
/*      OPERATION argument to BITBLT is 'ERASE, or      */
/*      if the SOURCETYPE argument is 'INVERT.          */
/*                                                      */
/********************************************************/

#define bbsrc_type(SRCTYPE, OPERATION)                                                             \
  ((SRCTYPE) == INVERT_atom ? ((OPERATION) == ERASE_atom ? 0 : 1) /*  SRCTYPE == INPUT, TEXTURE */ \
                          : ((OPERATION) == ERASE_atom ? 1 : 0))

extern struct pixrect *SrcePixRect, *DestPixRect, *TexturePixRect;
extern struct pixrect *BlackTexturePixRect, *WhiteTexturePixRect;
extern DLword TEXTURE_atom;
extern DLword MERGE_atom;
extern DLword INPUT_atom;
extern DLword INVERT_atom;
extern DLword ERASE_atom;
extern DLword PAINT_atom;
extern DLword REPLACE_atom;

/************************************************************************/
/*                                                                      */
/*                         b i t b l t s u b                            */
/*                                                                      */
/*      Implements the lisp function \BITBLTSUB, which is where                 */
/*      all BITBLT & BLTSHADE calls bottom out.  This is distinct       */
/*      from the PILOTBITBLT opcode, which is implemented in bitblt.c.  */
/*                                                                      */
/*                                                                      */
/*      args[0] :       PILOTBBT                                        */
/*      args[1] :       SOURCEBITMAP                                    */
/*      args[2] :       SLX (SourceLeftX)               sx              */
/*      args[3] :       STY (SourceTopY)                sty             */
/*      args[4] :       DESTINATIONBITMAP                               */
/*      args[5] :       DLX (DestinationLeftX)          dx              */
/*      args[6] :       DTY (DestinationTopY)           dty             */
/*      args[7] :       HEIGHT                                          */
/*      args[8] :       SourceType                                      */
/*      args[9] :       Operation                                       */
/*      args[10] :      Texture                                                 */
/*      args[11] :      WindowXOffset                                   */
/*      args[12] :      WindowYOffset                                   */
/*                                                                      */
/*                                                                      */
/*                                                                      */
/*                                                                      */
/*                                                                      */
/*                                                                      */
/************************************************************************/

void bitbltsub(LispPTR *argv) {
  int sourcetype, operation;
  int sty, dty, texture, wxoffset, wyoffset;
  int h, w;
#ifdef REALCURSOR
  int displayflg = 0;
#endif
  int backwardflg = 0, sx, dx, srcbpl=2147483647, dstbpl, src_comp, op;
  register DLword *srcbase, *dstbase;
  int gray = 0, num_gray = 0, curr_gray_line = 0;
  DLword grayword[4];

  { /* Initialization code, in a block so it optimizes independently */
    register LispPTR *args = argv;
    register PILOTBBT *pbt;
    register BITMAP *srcebm, *destbm;
    BITMAP *texture68k;
    register DLword *base;

#ifdef INIT
    init_kbd_startup;
#endif

    pbt = (PILOTBBT *)Addr68k_from_LADDR(args[0]);
    srcebm = (BITMAP *)Addr68k_from_LADDR(args[1]);
    sx = (args[2] & 0xFFFF);
    sty = (args[3] & 0xFFFF);
    destbm = (BITMAP *)Addr68k_from_LADDR(args[4]);
    dx = (args[5] & 0xFFFF);
    dty = (args[6] & 0xFFFF);
    sourcetype = (args[8] == NIL_PTR ? INPUT_atom : args[8]);
    operation = (args[9] == NIL_PTR ? REPLACE_atom : args[9]);

    w = pbt->pbtwidth;
    h = pbt->pbtheight;
    if ((h <= 0) || (w <= 0)) return;
    src_comp = bbsrc_type(sourcetype, operation);
    op = bbop(sourcetype, operation);

    dstbpl = destbm->bmrasterwidth << 4;

    if (sourcetype == TEXTURE_atom) {
      texture = args[10];
      wxoffset = (args[11] == NIL_PTR ? 0 : args[11] & 0xFFFF);
      wyoffset = (args[12] == NIL_PTR ? 0 : args[12] & 0xFFFF);
      sx = ((wxoffset) ? (dx - wxoffset) : dx) % BITSPERWORD;
      dstbase = (DLword *)Addr68k_from_LADDR(ADDBASE(destbm->bmbase, destbm->bmrasterwidth * dty));
      gray = 1;
      if (texture == NIL_PTR) { /* White Shade */
        grayword[0] = 0;
        srcbase = &grayword[0];
        num_gray = 1;
        curr_gray_line = 0;
        goto do_it_now;
      } else if (IsNumber(texture)) {
        if ((texture &= 0xffff) == 0) { /* White Shade */
          grayword[0] = 0;
          srcbase = &grayword[0];
          num_gray = 1;
          curr_gray_line = 0;
          goto do_it_now;
        } else if (texture == 0xffff) { /* Black Shade */
          grayword[0] = 0xFFFF;
          srcbase = &grayword[0];
          num_gray = 1;
          curr_gray_line = 0;
          goto do_it_now;
        } else { /* 4x4 */
          srcbase = base = (DLword *)(&grayword[0]);
          GETWORD(base++) = Expand4Bit(((texture >> 12) & 0xf));
          GETWORD(base++) = Expand4Bit(((texture >> 8) & 0xf));
          GETWORD(base++) = Expand4Bit(((texture >> 4) & 0xf));
          GETWORD(base++) = Expand4Bit((texture & 0xf));
          num_gray = 4;
          curr_gray_line = (dty + wyoffset) & 3;
          srcbase += curr_gray_line;
          goto do_it_now;
        }
      } else { /* A bitmap that is 16 bits wide. */
        texture68k = (BITMAP *)Addr68k_from_LADDR(texture);
        srcbase = (DLword *)Addr68k_from_LADDR(texture68k->bmbase);
        num_gray = min(texture68k->bmheight, 16);
        curr_gray_line = (dty + wyoffset) % num_gray;
        srcbase += curr_gray_line;
        goto do_it_now;
      }
    }
    /* ; INPUT or INVERT      */
    srcbpl = srcebm->bmrasterwidth << 4;

    /* compute flags */
    /* out for now
    if(srcebm == destbm)
    if(sty <= dty)
    if(dty <= (sty + h))
    if((sty != dty) || ((sx < dx) && (dx < (sx + w))))
                      backwardflg = T;
    out for now */
    /* compute flags */
    if (srcebm != destbm)
      ;
    else if (sty > dty)
      ;
    else if (dty > (sty + h))
      ;
    else if ((sty != dty) || ((sx < dx) && (dx < (sx + w))))
      backwardflg = T;

    if (backwardflg) {
      srcbase = (DLword *)Addr68k_from_LADDR(
          ADDBASE(srcebm->bmbase, srcebm->bmrasterwidth * (sty + h - 1)));
      dstbase = (DLword *)Addr68k_from_LADDR(
          ADDBASE(destbm->bmbase, destbm->bmrasterwidth * (dty + h - 1)));
      srcbpl = 0 - srcbpl;
      dstbpl = 0 - dstbpl;
    } else {
      srcbase = (DLword *)Addr68k_from_LADDR(ADDBASE(srcebm->bmbase, srcebm->bmrasterwidth * sty));
      dstbase = (DLword *)Addr68k_from_LADDR(ADDBASE(destbm->bmbase, destbm->bmrasterwidth * dty));
    }
#ifdef REALCURSOR
    displayflg = n_new_cursorin(srcbase, sx, sty, w, h);
#endif /* REALCURSOR */
  }

do_it_now:
#ifdef DOS
  currentdsp->device.locked++;
#else
  ScreenLocked = T;
#endif /* DOS */

#ifdef REALCURSOR
  displayflg |= n_new_cursorin(dstbase, dx, dty, w, h);
  if (displayflg) HideCursor;
#endif /* REALCURSOR */

#ifdef NEWBITBLT
  bitblt(srcbase, dstbase, sx, dx, w, h, srcbpl, dstbpl, backwardflg, src_comp, op, gray, num_gray,
         curr_gray_line);
#else
  new_bitblt_code;
#endif

#ifdef DISPLAYBUFFER
#ifdef COLOR
  if (MonoOrColor == MONO_SCREEN)
#endif /* COLOR */

    /* Copy the changed section of display bank to the frame buffer */
    if (in_display_segment(dstbase)) {
      /*      DBPRINT(("bltsub: x %d, y %d, w %d, h %d.\n",dx, dty, w,h)); */
      flush_display_region(dx, dty, w, h);
    }
#endif

#ifdef XWINDOW
  if (in_display_segment(dstbase)) flush_display_region(dx, dty, w, h);
#endif /* XWINDOW */

#ifdef DOS
  /* Copy the changed section of display bank to the frame buffer */
  if (in_display_segment(dstbase)) {
    /*      DBPRINT(("bltsub: x %d, y %d, w %d, h %d.\n",dx, dty, w,h)); */
    flush_display_region(dx, dty, w, h);
  }
#endif /* DOS */

#ifdef REALCURSOR
  if (displayflg) ShowCursor;
#endif /* REALCURSOR */

#ifdef DOS
  currentdsp->device.locked--;
#else
  ScreenLocked = NIL;
#endif /* DOS */

} /* end of bitbltsub */

/************************************************************************/
/*                                                                      */
/*                      n _ n e w _ c u r s o r i n                     */
/*                                                                      */
/*      Is the cursor over the spot we're about to change on the        */
/*      screen?                                                                 */
/*                                                                      */
/*      This version takes a native address for the bitmap base,        */
/*      plus x, y, width, and height for the intended change area.      */
/*      Returns T if the cursor overlaps the intended change, NIL       */
/*      otherwise.                                                      */
/*                                                                      */
/************************************************************************/

#ifndef COLOR

/********************************************************/
/*                                                      */
/*              Monochrome-only version                         */
/*                                                      */
/********************************************************/

LispPTR n_new_cursorin(DLword *baseaddr, int dx, int dy, int w, int h) {
  extern DLword *DisplayRegion68k;

#ifdef INIT
  init_kbd_startup; /* MUST START KBD FOR INIT BEFORE FIRST BITBLT */
#endif

  if ((DisplayRegion68k <= baseaddr) && (baseaddr <= DISP_MAX_Address)) {
    if ((dx < MOUSEXR) && (dx + w > MOUSEXL) && (dy < MOUSEYH) && (dy + h > MOUSEYL))
      return (T);
    else
      return (NIL);
  } else
    return (NIL);
}
#else
/********************************************************/
/*                                                      */
/*                 Mono / color version                         */
/*                                                      */
/********************************************************/
extern DLword *DisplayRegion68k, *ColorDisplayRegion68k;
extern int MonoOrColor;

LispPTR n_new_cursorin(DLword *baseaddr, int dx, int dy, int w, int h) {
#ifdef INIT
  init_kbd_startup; /* MUST START KBD FOR INIT BEFORE FIRST BITBLT */
#endif

  if (MonoOrColor == MONO_SCREEN) { /* in MONO screen */
    if ((DisplayRegion68k <= baseaddr) && (baseaddr <= DISP_MAX_Address)) {
      if ((dx < MOUSEXR) && (dx + w > MOUSEXL) && (dy < MOUSEYH) && (dy + h > MOUSEYL)) {
        return (T);
      } else {
        return (NIL);
      }
    } else
      return (NIL);
  }      /* if for MONO end */
  else { /* in COLOR screen */
    if ((ColorDisplayRegion68k <= baseaddr) && (baseaddr <= COLOR_MAX_Address)) {
      dx = dx >> 3;
      /*printf("new_c in COLOR mx=%d my=%d x=%d y=%d\n"
      ,*EmMouseX68K,*EmMouseY68K,dx,dy);*/
      if ((dx < MOUSEXR) && (dx + w > MOUSEXL) && (dy < MOUSEYH) &&
          (dy + h > MOUSEYL)) { /*  printf("new_c T\n");*/
        return (T);
      } else {
        return (NIL);
      }
    } else
      return (NIL);
  }
}
#endif /* COLOR */

#define BITBLTBITMAP_argnum 14
#define PUNT_TO_BITBLTBITMAP                                                                  \
  {                                                                                           \
    if (BITBLTBITMAP_index == 0xffffffff) {                                                   \
      BITBLTBITMAP_index = get_package_atom("\\PUNT.BITBLT.BITMAP", 19, "INTERLISP", 9, NIL); \
      if (BITBLTBITMAP_index == 0xffffffff) {                                                 \
        error("BITBLTBITMAP install failed");                                                 \
        return (NIL);                                                                         \
      }                                                                                       \
    }                                                                                         \
    CurrentStackPTR += (BITBLTBITMAP_argnum - 1) * DLWORDSPER_CELL;                           \
    ccfuncall(BITBLTBITMAP_index, BITBLTBITMAP_argnum, 3);                                    \
    return (ATOM_T);                                                                               \
  }

LispPTR BITBLTBITMAP_index;
/************************************************************************/
/*                                                                      */
/*                      b i t b l t _ b i t m a p                       */
/*                                                                      */
/*      C implementation of the Lisp function \BITBLT.BITMAP,           */
/*      which does bitmap-to-bitmap cases of BITBLT, after BITBLT       */
/*      does some setup and massaging first.                            */
/*                                                                      */
/*      args[0]:  SourceBitmap                                          */
/*      args[1]:  SourceLeft            Must be a SMALLPOSP             */
/*      args[2]:  SourceBottom          Must be a SMALLPOSP             */
/*      args[3]:  DestBitmap                                            */
/*      args[4]:  DestLeft              Must be a SMALLPOSP             */
/*      args[5]:  DestBottom            Must be a SMALLPOSP             */
/*      args[6]:  Width                 Must be a SMALLPOSP             */
/*      args[7]:  Height                Must be a SMALLPOSP             */
/*      args[8]:  SourceType            [May be NIL]                    */
/*      args[9]:  Operation             [May be NIL]                    */
/*      args[10]: Texture               [May be NIL]                    */
/*      args[11]: ClippingRegion        [May be NIL]                    */
/*      args[12]: ClippedSrcLeft        Must be a SMALLPOSP             */
/*      args[13]: ClippedSrcBottom      Must be a SMALLPOSP             */
/*                                                                      */
/*                                                                      */
/*      SourceType must not be MERGE, which should be handled by        */
/*      the lisp code in \BITBLT.BITMAP.                                */
/*      This function can't handle COLOR & sourcetype == MERGE case.    */
/*      It causes punting to \\PUNT.BITBLT.BITMAP.                      */
/*      Therefore SYSOUT must contain \\PUNT.BITBLT.BITMAP.             */
/*                                                                      */
/************************************************************************/

LispPTR bitblt_bitmap(LispPTR *args) {
  BITMAP *SourceBitmap, *DestBitmap;
  int sleft, sbottom, dleft, dbottom, width, height, clipleft, clipbottom;
  LispPTR clipreg;
  int stodx, stody, right, top, destbits, sourcebits, left, bottom;
  LispPTR sourcetype, operation, texture;
  DLword *srcbase, *dstbase;
  int dlx, dty, slx, sty, srcbpl, dstbpl, op, src_comp, backwardflg = 0, displayflg = 0;

  extern DLword MERGE_atom;

#ifdef INIT
  init_kbd_startup;
#endif

  /* Get arguments  and check the possibilities of PUNT */
  SourceBitmap = (BITMAP *)Addr68k_from_LADDR(args[0]);
  DestBitmap = (BITMAP *)Addr68k_from_LADDR(args[3]);
  /* It does not handle COLOR ..... maybe later */
  destbits = DestBitmap->bmbitperpixel;
  sourcebits = SourceBitmap->bmbitperpixel;
  if ((destbits != 1) || (sourcebits != 1)) {
    PUNT_TO_BITBLTBITMAP;
  }
  sourcetype = args[8];
  /* sourcetype == MERGE_atom case must be handled in Lisp function \\PUNT.BITBLT.BITMAP */
  if (sourcetype == MERGE_atom) { PUNT_TO_BITBLTBITMAP; }

  N_GETNUMBER(args[1], sleft, bad_arg);
  N_GETNUMBER(args[2], sbottom, bad_arg);
  N_GETNUMBER(args[4], dleft, bad_arg);
  N_GETNUMBER(args[5], dbottom, bad_arg);
  N_GETNUMBER(args[6], width, bad_arg);
  N_GETNUMBER(args[7], height, bad_arg);
  operation = args[9];
  texture = args[10];
  clipreg = args[11];
  N_GETNUMBER(args[12], clipleft, bad_arg);
  N_GETNUMBER(args[13], clipbottom, bad_arg);

  left = bottom = 0;
  top = DestBitmap->bmheight;
  right = DestBitmap->bmwidth;

  if (clipreg != NIL_PTR) {
    /* clip the BITBLT using the clipping region supplied */
    register LispPTR clipvalue;
    register int temp, cr_left, cr_bot;

    clipvalue = car(clipreg);
    N_GETNUMBER(clipvalue, cr_left, bad_arg);
    left = max(left, cr_left);

    clipreg = cdr(clipreg);
    clipvalue = car(clipreg);
    N_GETNUMBER(clipvalue, cr_bot, bad_arg);
    bottom = max(bottom, cr_bot);

    clipreg = cdr(clipreg);
    clipvalue = car(clipreg);
    N_GETNUMBER(clipvalue, temp, bad_arg);
    right = min(right, cr_left + temp);

    clipreg = cdr(clipreg);
    clipvalue = car(clipreg);
    N_GETNUMBER(clipvalue, temp, bad_arg);
    top = min(top, cr_bot + temp);
  }

  left = max(left, dleft);
  right = min(right, dleft + width);
  bottom = max(bottom, dbottom);
  top = min(top, dbottom + height);
  stody = dbottom - sbottom;
  stodx = dleft - sleft;

  {
    register int temp;
    left = max(clipleft, max(0, left - stodx));
    bottom = max(clipbottom, max(0, bottom - stody));
    temp = SourceBitmap->bmwidth;
    right = min(temp, min(right - stodx, clipleft + width));
    temp = SourceBitmap->bmheight;
    top = min(temp, min(top - stody, clipbottom + height));
  }

  if ((right <= left) || (top <= bottom)) return (NIL);

  /*** PUT SOURCETYPE MERGE special code HERE ***/
  /**** See above, earlier in this code check sourcetype and punting. *****/
  /**** sourcebits CANNOT be unequal to destbits from earlier check */

  if (sourcebits != destbits) {
    /* DBPRINT(("BITBLT between bitmaps of different sizes, unimplemented.")); */
      return NIL;
  }
  /* if not 1-bit-per-pixel adjust limits by pixel size */
  switch (sourcebits) {
  case 1:
      break;
  case 4:
      left = left * 4;
      right = right * 4;
      stodx = stodx * 4;
      /* Put color texture merge case here */
      break;

  case 8:
      left = left * 8;
      right = right * 8;
      stodx = stodx * 8;
      /* Put color texture merge case here */
      break;

  case 24:
      left = left * 24;
      right = right * 24;
      stodx = stodx * 24;
      /* Put color texture merge case here */
      break;
  }

  height = top - bottom;
  width = right - left;
  dty = DestBitmap->bmheight - (top + stody);
  dlx = left + stodx;
  sty = SourceBitmap->bmheight - top;
  slx = left;

  /*** Stolen from bitbltsub, to avoid the call overhead: ***/
  src_comp = bbsrc_type(sourcetype, operation);
  op = bbop(sourcetype, operation);

  dstbpl = DestBitmap->bmrasterwidth << 4;

  /* Sourcetype guaranteed not to be TEXTURE by BITBLT fn */
  srcbpl = SourceBitmap->bmrasterwidth << 4;

  /* compute flags */
  if (SourceBitmap != DestBitmap)
    ;
  else if (sty > dty)
    ;
  else if (dty > (sty + height))
    ;
  else if ((sty != dty) || ((slx < dlx) && (dlx < (slx + width))))
    backwardflg = T;

  if (backwardflg) {
    srcbase = (DLword *)Addr68k_from_LADDR(
        ADDBASE(SourceBitmap->bmbase, SourceBitmap->bmrasterwidth * (sty + height - 1)));
    dstbase = (DLword *)Addr68k_from_LADDR(
        ADDBASE(DestBitmap->bmbase, DestBitmap->bmrasterwidth * (dty + height - 1)));
    srcbpl = 0 - srcbpl;
    dstbpl = 0 - dstbpl;
  } else {
    srcbase = (DLword *)Addr68k_from_LADDR(
        ADDBASE(SourceBitmap->bmbase, SourceBitmap->bmrasterwidth * sty));
    dstbase =
        (DLword *)Addr68k_from_LADDR(ADDBASE(DestBitmap->bmbase, DestBitmap->bmrasterwidth * dty));
  }

  displayflg = n_new_cursorin(srcbase, slx, sty, width, height);

do_it_now:
  LOCKSCREEN;

#ifdef REALCURSOR
  displayflg |= n_new_cursorin(dstbase, dlx, dty, width, height);
  if (displayflg) HideCursor;
#endif /*  REALCURSOR */

#ifdef NEWBITBLT
  bitblt(srcbase, dstbase, slx, dlx, width, height, srcbpl, dstbpl, backwardflg, src_comp, op, 0, 0,
         0);
#else
#define gray 0
#define dx dlx
#define sx slx
#define w width
#define h height
#define curr_gray_line dx
#define num_gray 0
  new_bitblt_code;
#undef gray
#undef dx
#undef sx
#undef w
#undef h
#undef curr_gray_line
#undef num_gray
#endif

#ifdef DISPLAYBUFFER
#ifdef COLOR
  if (MonoOrColor == MONO_SCREEN)
#endif /* COLOR */

    /* Copy the changed section of display bank to the frame buffer */
    if (in_display_segment(dstbase)) {
      /*      DBPRINT(("bltsub: x %d, y %d, w %d, h %d.\n",dlx, dty, width,height));*/
      flush_display_region(dlx, dty, width, height);
    }
#endif

#ifdef XWINDOW
  if (in_display_segment(dstbase)) flush_display_region(dlx, dty, width, height);
#endif /* XWINDOW */

#ifdef DOS
  /* Copy the changed section of display bank to the frame buffer */
  if (in_display_segment(dstbase)) {
    /*      DBPRINT(("bltsub: x %d, y %d, w %d, h %d.\n",dx, dty, w,h)); */
    flush_display_region(dlx, dty, width, height);
  }
#endif /* DOS */

#ifdef REALCURSOR
  if (displayflg) ShowCursor;
#endif /* REALCURSOR */

  UNLOCKSCREEN;

  return (ATOM_T);

bad_arg:
  return (NIL);
} /* end of bitblt_bitmap */

#define BLTSHADEBITMAP_argnum 8
#define PUNT_TO_BLTSHADEBITMAP                                                                    \
  {                                                                                               \
    if (BLTSHADEBITMAP_index == 0xffffffff) {                                                     \
      BLTSHADEBITMAP_index = get_package_atom("\\PUNT.BLTSHADE.BITMAP", 21, "INTERLISP", 9, NIL); \
      if (BLTSHADEBITMAP_index == 0xffffffff) {                                                   \
        error("BLTSHADEBITMAP install failed");                                                   \
        return (NIL);                                                                             \
      }                                                                                           \
    }                                                                                             \
    CurrentStackPTR += (BLTSHADEBITMAP_argnum - 1) * DLWORDSPER_CELL;                             \
    ccfuncall(BLTSHADEBITMAP_index, BLTSHADEBITMAP_argnum, 3);                                    \
    return (ATOM_T);                                                                                   \
  }

LispPTR BLTSHADEBITMAP_index;

/************************************************************************/
/*                                                                      */
/*                  b i t s h a d e _ b i t m a p                       */
/*                                                                      */
/*      C implementation of the Lisp function \BITSHADE.BITMAP,                 */
/*      which does bitmap-to-bitmap cases of BITSHADE, after BITSHADE   */
/*      does some setup and massaging first.                            */
/*      This func. can't handle TEXTURE == LISTP or LITATOM case.       */
/*      It causes punting to \\PUNT.BLTSHADE.BITMAP.                    */
/*      Therefore SYSOUT must contain \\PUNT.BLTSHADE.BITMAP.           */
/*                                                                      */
/*      args[0]: Texture                                                */
/*      args[1]: DestBitmap                                             */
/*      args[2]: DestLeft               Must be a SMALLPOSP             */
/*      args[3]: DestBottom             Must be a SMALLPOSP             */
/*      args[4]: Width                  Must be a SMALLPOSP             */
/*      args[5]: height                         Must be a SMALLPOSP             */
/*      args[6]: Operation                                              */
/*      args[7]: ClippingRegion                                                 */
/*                                                                      */
/*      The numeric arguments are assumed to be SMALLPOSPs;             */
/*      the result with anything else isn't guaranteed correct.                 */
/*       This Func should punt if TEXTURE==LITATOM(NOT NIL) or LISTP    */
/*              or DestBitmap's BPP !=1                                         */
/*                                                                      */
/*                                                                      */
/************************************************************************/

LispPTR bitshade_bitmap(LispPTR *args) {
  BITMAP *DestBitmap, *texture68k;
  int dleft, dbottom, width, height;
  LispPTR clipreg;
  int right, top, destbits, left, bottom;
  LispPTR operation, texture;
  DLword *srcbase, *dstbase, *base;
  int dty, slx, dstbpl, op, src_comp;
#ifdef REALCURSOR
  int displayflg = 0;
#endif
  int rasterwidth;
  int num_gray, curr_gray_line;
  DLword grayword[4];

  texture = args[0];
  {
    register int temp;
    temp = GetTypeNumber(texture);
    if (((temp == TYPE_LITATOM) && (texture != NIL_PTR)) || (temp == TYPE_LISTP)) {
      PUNT_TO_BLTSHADEBITMAP;
    }
  }

  DestBitmap = (BITMAP *)Addr68k_from_LADDR(args[1]);
  if ((destbits = DestBitmap->bmbitperpixel) != 1) { PUNT_TO_BLTSHADEBITMAP; }

  N_GETNUMBER(args[2], dleft, bad_arg);
  N_GETNUMBER(args[3], dbottom, bad_arg);
  operation = args[6];
  clipreg = args[7];

  rasterwidth = DestBitmap->bmrasterwidth;
  top = DestBitmap->bmheight;
  left = bottom = 0;
  right = DestBitmap->bmwidth;
  if (clipreg != NIL_PTR) { /* clip the BITBLT using the clipping region supplied */
    register LispPTR clipvalue;
    register int temp, cr_left, cr_bot;

    clipvalue = car(clipreg);
    N_GETNUMBER(clipvalue, cr_left, bad_arg);
    left = max(left, cr_left);

    clipreg = cdr(clipreg);
    clipvalue = car(clipreg);
    N_GETNUMBER(clipvalue, cr_bot, bad_arg);
    bottom = max(bottom, cr_bot);

    clipreg = cdr(clipreg);
    clipvalue = car(clipreg);
    N_GETNUMBER(clipvalue, temp, bad_arg);
    right = min(right, cr_left + temp);

    clipreg = cdr(clipreg);
    clipvalue = car(clipreg);
    N_GETNUMBER(clipvalue, temp, bad_arg);
    top = min(top, cr_bot + temp);
  }

  left = max(left, dleft);
  bottom = max(bottom, dbottom);
  if (args[4] != NIL_PTR) {
    N_GETNUMBER(args[4], width, bad_arg);
    right = min(right, dleft + width);
  }
  if (args[5] != NIL_PTR) {
    N_GETNUMBER(args[5], height, bad_arg);
    top = min(top, dbottom + height);
  }

  if ((right <= left) || (top <= bottom)) return (NIL);

  height = top - bottom;
  width = right - left;
  dty = DestBitmap->bmheight - top;

  if ((dty < 0) || ((dty + height) > DestBitmap->bmheight)) error("dty bad.");
  if ((bottom < 0)) error("bottom bad.");
  if ((bottom > 2048)) error("bottom suspicious");

  /*** Stolen from bitbltsub, to avoid the call overhead: ***/
  src_comp = bbsrc_type(0, operation);
  op = bbop(0, operation);

  dstbpl = rasterwidth << 4;

  if ((left < 0) || (right > dstbpl)) error("left/right bad.");

  slx = left % BITSPERWORD;

  dstbase = (DLword *)Addr68k_from_LADDR(ADDBASE(DestBitmap->bmbase, (rasterwidth * dty)));

  if (GetTypeNumber(texture) == TYPE_LITATOM) {
    if (texture == NIL_PTR) { /* White Shade */
      grayword[0] = 0;
      srcbase = &grayword[0];
      num_gray = 1;
      curr_gray_line = 0;
      goto do_it_now;
    }
    /* temp DEBUFG stuff */
    else {
      print(texture);
      error("Should not!");
    }
  } else if (IsNumber(texture)) {
    if ((texture &= 0xffff) == 0) { /* White Shade */
      grayword[0] = 0;
      srcbase = &grayword[0];
      num_gray = 1;
      curr_gray_line = 0;
    } else if (texture == 0xffff) { /* Black Shade */
      grayword[0] = 0xFFFF;
      srcbase = &grayword[0];
      num_gray = 1;
      curr_gray_line = 0;
    } else { /* 4x4 */
      srcbase = base = (DLword *)(&grayword[0]);
      GETWORD(base++) = Expand4Bit(((texture >> 12) & 0xf));
      GETWORD(base++) = Expand4Bit(((texture >> 8) & 0xf));
      GETWORD(base++) = Expand4Bit(((texture >> 4) & 0xf));
      GETWORD(base++) = Expand4Bit((texture & 0xf));
      num_gray = 4;
      curr_gray_line = (dty)&3;
      srcbase += curr_gray_line;
    }
  } else /**** Need to handle texture = listp case, too ***/
  /* Listp case alway punt to LISP */
  { /* A bitmap that is 16 bits wide. */
    texture68k = (BITMAP *)Addr68k_from_LADDR(texture);
    srcbase = (DLword *)Addr68k_from_LADDR(texture68k->bmbase);
    num_gray = min(texture68k->bmheight, 16);
    curr_gray_line = (dty) % num_gray;
    srcbase += curr_gray_line;
  }

do_it_now:
  LOCKSCREEN;

#ifdef REALCURSOR
  displayflg |= n_new_cursorin(dstbase, left, dty, width, height);
  if (displayflg) HideCursor;
#endif /* REALCURSOR */

#ifdef NEWBITBLT
  bitblt(srcbase, dstbase, slx, left, width, height, 0, dstbpl, 0, src_comp, op, 1, num_gray,
         curr_gray_line);
#else
#define gray 1
#define backwardflg 0
#define srcbpl 0
#define w width
#define h height
#define dx left
#define sx slx
  new_bitblt_code;
#undef gray
#undef backwardflg
#undef srcbpl
#undef w
#undef h
#undef dx
#undef sx
#endif

#ifdef DISPLAYBUFFER
#ifdef COLOR
  if (MonoOrColor == MONO_SCREEN)
#endif /* COLOR */

    /* Copy the changed section of display bank to the frame buffer */
    if (in_display_segment(dstbase)) {
      /*      DBPRINT(("bltsub: x %d, y %d, w %d, h %d.\n",left, dty, width,height));*/
      flush_display_region(left, dty, width, height);
    }
#endif

#ifdef XWINDOW
  if (in_display_segment(dstbase)) flush_display_region(left, dty, width, height);
#endif /* XWINDOW */

#ifdef DOS
  /* Copy the changed section of display bank to the frame buffer */
  if (in_display_segment(dstbase)) {
    /*      DBPRINT(("bltsub: x %d, y %d, w %d, h %d.\n",dx, dty, w,h)); */
    flush_display_region(left, dty, width, height);
  }
#endif /* DOS */

#ifdef REALCURSOR
  if (displayflg) ShowCursor;
#endif /*  REALCURSOR */

  UNLOCKSCREEN;

  return (ATOM_T);

bad_arg:
  return (NIL);
} /* end of bitshade_bitmap */

/*
 *
 *
 ********       BLTCHAR         BLTCHAR         BLTCHAR         BLTCHAR         *********
 *
 */

/** \BLTCHAR ****
(freplace (PILOTBBT PBTDESTBIT) of LOCAL1 with LEFT)
(freplace (PILOTBBT PBTWIDTH) of LOCAL1 with (IDIFFERENCE RIGHT LEFT))
(freplace (PILOTBBT PBTSOURCEBIT) of LOCAL1 with
    (IDIFFERENCE
        (IPLUS (\GETBASE
                    (ffetch (\DISPLAYDATA DDOFFSETSCACHE) of DISPLAYDATA)
                    CHAR8CODE)
                LEFT)
        CURX))
(\PILOTBITBLT LOCAL1 0)
*********/


/************************************************************************/
/*                                                                      */
/*                              b l t c h a r                           */
/*                                                                      */
/*      BITBLT character images onto a display stream.                  */
/*                                                                      */
/*                                                                      */
/************************************************************************/
/********************************************************/
/*             Non-PIXRECT version of the code          */
/********************************************************/

void bltchar(LispPTR *args)
/*      args[0] :       PILOTBBT
 *      args[1] :       DISPLAYDATA
 *      args[2] :       CHAR8CODE
 *      args[3] :       CURX
 *      args[4] :       LEFT
 *      args[5] :       RIGHT
 */
{
  register PILOTBBT *pbt;
  register DISPLAYDATA *dspdata;
  int base;
#ifdef REALCURSOR
  register int displayflg;
#endif
  int w, h;
  int backwardflg = 0, sx, dx, srcbpl, dstbpl, src_comp, op;
  DLword *srcbase, *dstbase;
  int gray = 0;
#ifdef NEWBITBLT
  int num_gray = 0, curr_gray_line = 0;
#endif

  pbt = (PILOTBBT *)Addr68k_from_LADDR(((BLTC *)args)->pilotbbt);
  dspdata = (DISPLAYDATA *)Addr68k_from_LADDR(((BLTC *)args)->displaydata);

  srcbase = (DLword *)Addr68k_from_LADDR(VAG2(pbt->pbtsourcehi, pbt->pbtsourcelo));

  dstbase = (DLword *)Addr68k_from_LADDR(VAG2(pbt->pbtdesthi, pbt->pbtdestlo));

  srcbpl = abs(pbt->pbtsourcebpl);
  dstbpl = abs(pbt->pbtdestbpl);
  h = pbt->pbtheight;
  w = ((BLTC *)args)->right - ((BLTC *)args)->left;
  if ((h <= 0) || (w <= 0)) return;

  base = GETWORD(Addr68k_from_LADDR(dspdata->ddoffsetscache + ((BLTC *)args)->char8code));
  sx = base + ((BLTC *)args)->left - ((BLTC *)args)->curx;
  dx = ((BLTC *)args)->left;

#ifdef REALCURSOR
  /* if displayflg != 0 then source or destination is DisplayBitMap
   * Now we consider about only destination
   */
  displayflg = cursorin(pbt->pbtdesthi, (pbt->pbtdestlo + (((BLTC *)args)->left >> 4)),
                        (((BLTC *)args)->right - ((BLTC *)args)->left), pbt->pbtheight, pbt->pbtbackward);
#endif /* REALCURSOR */

  op = pbt->pbtoperation;
  src_comp = pbt->pbtsourcetype;

  LOCKSCREEN;

#ifdef REALCURSOR
  if (displayflg) HideCursor;
#endif /* REALCURSOR */

#ifdef NEWBITBLT
  bitblt(srcbase, dstbase, sx, dx, w, h, srcbpl, dstbpl, backwardflg, src_comp, op, gray, num_gray,
         curr_gray_line);
#else
  new_char_bitblt_code
#endif

#ifdef DISPLAYBUFFER
#ifdef COLOR
  if (MonoOrColor == MONO_SCREEN)
#endif /* COLOR */

    if (in_display_segment(dstbase)) { flush_display_lineregion(dx, dstbase, w, h); }
#endif

#ifdef XWINDOW
  if (in_display_segment(dstbase)) flush_display_lineregion(dx, dstbase, w, h);
#endif /* XWINDOW */

#ifdef DOS
  if (in_display_segment(dstbase)) flush_display_lineregion(dx, dstbase, w, h);
#endif /* DOS */

#ifdef REALCURSOR
  if (displayflg) ShowCursor;
#endif /* REALCURSOR */

  UNLOCKSCREEN;
}


/************************************************************************/
/*                                                                      */
/*                          n e w b l t c h a r                         */
/*                                                                      */
/*      BITBLT character images onto a display stream.  This version    */
/*      handles clipping in the C code, and checks for changes of       */
/*      character set and hitting the right margin.  In either of       */
/*      those cases, it punts to the old LISP code for BLTCHAR. It      */
/*      also punts if the display stream we're writing to isn't for     */
/*      the top window on the screen's window stack.                    */
/*                                                                      */
/************************************************************************/

#define BLTCHAR_argnum 3
#ifndef INIT
#define PUNT_TO_BLTCHAR                                                                 \
  {                                                                                     \
    if ((BLTCHAR_index == 0)) {                                                         \
      BLTCHAR_index = get_package_atom("\\MAIKO.PUNTBLTCHAR", 18, "INTERLISP", 9, NIL); \
      if (BLTCHAR_index == 0xffffffff) {                                                \
        error("\\MAIKO.PUNTBLTCHAR install failed");                                    \
        return;                                                                         \
      }                                                                                 \
    }                                                                                   \
    CurrentStackPTR += (BLTCHAR_argnum - 1) * DLWORDSPER_CELL;                          \
    ccfuncall(BLTCHAR_index, BLTCHAR_argnum, 3);                                        \
    return;                                                                             \
  }
#else
#define PUNT_TO_BLTCHAR                                                                 \
  { /* Version that is silent instead of erroring for init */                           \
    if ((BLTCHAR_index == 0)) {                                                         \
      BLTCHAR_index = get_package_atom("\\MAIKO.PUNTBLTCHAR", 18, "INTERLISP", 9, NIL); \
      if (BLTCHAR_index == 0xffffffff) {                                                \
        /*   error("\\MAIKO.PUNTBLTCHAR install failed");      */                       \
        return;                                                                         \
      }                                                                                 \
    }                                                                                   \
    CurrentStackPTR += (BLTCHAR_argnum - 1) * DLWORDSPER_CELL;                          \
    ccfuncall(BLTCHAR_index, BLTCHAR_argnum, 3);                                        \
    return;                                                                             \
  }
#endif /* INIT */

#define TEDIT_BLTCHAR_argnum 6
#define PUNT_TO_TEDIT_BLTCHAR                                                             \
  {                                                                                       \
    if (TEDIT_BLTCHAR_index == 0xffffffff) {                                              \
      TEDIT_BLTCHAR_index = get_package_atom("\\TEDIT.BLTCHAR", 14, "INTERLISP", 9, NIL); \
      if (TEDIT_BLTCHAR_index == 0xffffffff) {                                            \
        error("TEDIT install failed");                                                    \
        return;                                                                           \
      }                                                                                   \
    }                                                                                     \
    CurrentStackPTR += (TEDIT_BLTCHAR_argnum - 1) * DLWORDSPER_CELL;                      \
    ccfuncall(TEDIT_BLTCHAR_index, TEDIT_BLTCHAR_argnum, 3);                              \
    return;                                                                               \
  }

#define FGetNum(ptr, place)                     \
  {                                             \
    if (((ptr)&SEGMASK) == S_POSITIVE) {        \
      (place) = ((ptr)&0xffff);                 \
    } else if (((ptr)&SEGMASK) == S_NEGATIVE) { \
      (place) = (int)((ptr) | 0xffff0000);      \
    } else {                                    \
      PUNT_TO_BLTCHAR;                          \
    }                                           \
  }
#define FGetNum2(ptr, place)                    \
  {                                             \
    if (((ptr)&SEGMASK) == S_POSITIVE) {        \
      (place) = ((ptr)&0xffff);                 \
    } else if (((ptr)&SEGMASK) == S_NEGATIVE) { \
      (place) = (int)((ptr) | 0xffff0000);      \
    } else {                                    \
      return (-1);                              \
    }                                           \
  }

LispPTR *TOPWDS68k;          /* Top of window stack's DS */
LispPTR BLTCHAR_index;       /* Atom # for \PUNTBLTCHAR punt fn */
LispPTR TEDIT_BLTCHAR_index; /* if NIL ,TEDIT is not yet loaded */



/************************************************************************/
/*                                                                      */
/*                          n e w b l t c h a r                                 */
/*                         (non-PIXRECT version)                        */
/*                                                                      */
/************************************************************************/

void newbltchar(LispPTR *args) {
  register DISPLAYDATA *displaydata68k;
  int right, left, curx;
  PILOTBBT *pbt;
  int lmargin, rmargin, xoff;
  int base;
  int h, w;
#ifdef REALCURSOR
  int displayflg;
#endif
  int backwardflg = 0, sx, dx, srcbpl, dstbpl, src_comp, op;
  DLword *srcbase, *dstbase;
  int gray = 0;
#ifdef NEWBITBLT
  int num_gray = 0, curr_gray_line = 0;
#endif

  displaydata68k = (DISPLAYDATA *)Addr68k_from_LADDR(((BLTARG *)args)->displaydata);

  if ((displaydata68k->ddcharset & 0xFFFF) != ((BLTARG *)args)->charset) {
    /*if(changecharset_display(displaydata68k, ((BLTARG *)args)->charset) ==-1)*/
    PUNT_TO_BLTCHAR;
  }

  if (displaydata68k->ddslowprintingcase) { PUNT_TO_BLTCHAR; /** \SLOWBLTCHAR--return;**/ }

  FGetNum(displaydata68k->ddxposition, curx);
  FGetNum(displaydata68k->ddrightmargin, rmargin);
  FGetNum(displaydata68k->ddleftmargin, lmargin);
  FGetNum(displaydata68k->ddxoffset, xoff);

  right =
      curx +
      GETWORD((DLword *)Addr68k_from_LADDR(displaydata68k->ddcharimagewidths + ((BLTARG *)args)->char8code));

  if ((right > rmargin) && (curx > lmargin)) PUNT_TO_BLTCHAR;
  if (((BLTARG *)args)->displaystream != *TOPWDS68k) PUNT_TO_BLTCHAR;

  {
    register int newpos;
    newpos = curx +
             GETWORD((DLword *)Addr68k_from_LADDR(displaydata68k->ddwidthscache + ((BLTARG *)args)->char8code));

    if ((0 <= newpos) && (newpos < 65536))
      (displaydata68k->ddxposition) = (LispPTR)(S_POSITIVE | newpos);
    else if (-65537 < newpos)
      (displaydata68k->ddxposition) = (LispPTR)(S_NEGATIVE | (0xffff & newpos));
    else {
      PUNT_TO_BLTCHAR;
    }
  }

  curx += xoff;
  right += xoff;
  if (right > (int)(displaydata68k->ddclippingright)) right = displaydata68k->ddclippingright;

  if (curx > (int)(displaydata68k->ddclippingleft))
    left = curx;
  else
    left = displaydata68k->ddclippingleft;

  pbt = (PILOTBBT *)Addr68k_from_LADDR(displaydata68k->ddpilotbbt);
  h = pbt->pbtheight;
  w = right - left;
  if ((h <= 0) || (w <= 0)) return;

  srcbase = (DLword *)Addr68k_from_LADDR(VAG2(pbt->pbtsourcehi, pbt->pbtsourcelo));

  dstbase = (DLword *)Addr68k_from_LADDR(VAG2(pbt->pbtdesthi, pbt->pbtdestlo));

  op = pbt->pbtoperation;
  src_comp = pbt->pbtsourcetype;

  srcbpl = abs(pbt->pbtsourcebpl);
  dstbpl = abs(pbt->pbtdestbpl);
  base = GETWORD(Addr68k_from_LADDR(displaydata68k->ddoffsetscache + ((BLTARG *)args)->char8code));
  sx = base + left - curx;
  dx = left;

  LOCKSCREEN;

#ifdef REALCURSOR
  displayflg = (cursorin(pbt->pbtdesthi, (pbt->pbtdestlo + (left >> 4)), (right - left),
                         pbt->pbtheight, pbt->pbtbackward));
  if (displayflg) HideCursor;
#endif /* REALCURSOR */

#ifdef NEWBITBLT
  bitblt(srcbase, dstbase, sx, dx, w, h, srcbpl, dstbpl, backwardflg, src_comp, op, gray, num_gray,
         curr_gray_line);
#else
  new_char_bitblt_code
#endif

#ifdef DISPLAYBUFFER
#ifdef COLOR
  if (MonoOrColor == MONO_SCREEN)
#endif /* COLOR */

    if (in_display_segment(dstbase)) {
      /*      DBPRINT(("newbltchar:  x %d, y 0x%x, w %d, h %d.\n", dx, dstbase, w, h));*/
      flush_display_lineregion(dx, dstbase, w, h);
    }
#endif

#ifdef XWINDOW
  if (in_display_segment(dstbase)) flush_display_lineregion(dx, dstbase, w, h);
#endif /* XWINDOW */
#ifdef DOS
  if (in_display_segment(dstbase)) flush_display_lineregion(dx, dstbase, w, h);
#endif /* DOS */

#ifdef REALCURSOR
  if (displayflg) ShowCursor;
#endif /* REALCURSOR */

  UNLOCKSCREEN;

} /* end of newbltchar */


/******************************************************************/
#ifndef BYTESWAP
#ifdef BIGVM
typedef struct {
  LispPTR FONTDEVICE;
  LispPTR FONTFAMILY;
  LispPTR FONTSIZE;
  LispPTR FONTFACE;
  DLword SFAscent;
  DLword SFDescent;
  DLword SFHeight;
  DLword ROTATION;
  short FBBOX;
  short FBBOY;
  short FBBDX;
  short FBBDY;
  LispPTR SFLKerns;
  LispPTR SFRWidths;
  LispPTR FONTDEVICESPEC;
  LispPTR OTHERDEVICEFONTPROPS;
  LispPTR FONTSCALE;
  unsigned SFFACECODE : 8;
  unsigned nil : 8;
  DLword FONTAVGCHARWIDTH;
  LispPTR FONTIMAGEWIDTHS;
  LispPTR FONTCHARSETVECTOR;
  LispPTR FONTEXTRAFIELD2;
} FONTDESC;
#else
typedef struct {
  LispPTR FONTDEVICE;
  LispPTR SFObsolete1;
  LispPTR FONTFAMILY;
  LispPTR FONTSIZE;
  LispPTR FONTFACE;
  LispPTR SFObsolete2;
  LispPTR SFObsolete3;
  LispPTR SFObsolete4;
  DLword SFObsolete5;
  DLword SFObsolete6;
  DLword SFAscent;
  DLword SFDescent;
  DLword SFHeight;
  DLword ROTATION;
  short FBBOX;
  short FBBOY;
  short FBBDX;
  short FBBDY;
  unsigned SFFACECODE : 8;
  unsigned SFLKerns : 24;
  LispPTR SFRWidths;
  LispPTR FONTDEVICESPEC;
  LispPTR OTHERDEVICEFONTPROPS;
  LispPTR FONTSCALE;
  DLword FONTAVGCHARWIDTH;
  DLword dum;
  LispPTR FONTIMAGEWIDTHS;
  LispPTR FONTCHARSETVECTOR;
  LispPTR FONTEXTRAFIELD2;
} FONTDESC;
#endif /* BIGVM */

typedef struct {
  LispPTR WIDTHS;
  LispPTR OFFSETS;
  LispPTR IMAGEWIDTHS;
  LispPTR CHARSETBITMAP;
  LispPTR YWIDTHS;
  DLword CHARSETASCENT;
  DLword CHARSETDESCENT;
  LispPTR LEFTKERN;
} CHARSETINFO;
#else
typedef struct {
  LispPTR FONTDEVICE;
  LispPTR SFObsolete1;
  LispPTR FONTFAMILY;
  LispPTR FONTSIZE;
  LispPTR FONTFACE;
  LispPTR SFObsolete2;
  LispPTR SFObsolete3;
  LispPTR SFObsolete4;
  DLword SFObsolete6;
  DLword SFObsolete5;
  DLword SFDescent;
  DLword SFAscent;
  DLword ROTATION;
  DLword SFHeight;
  short FBBOY;
  short FBBOX;
  short FBBDY;
  short FBBDX;
  unsigned SFLKerns : 24;
  unsigned SFFACECODE : 8;
  LispPTR SFRWidths;
  LispPTR FONTDEVICESPEC;
  LispPTR OTHERDEVICEFONTPROPS;
  LispPTR FONTSCALE;
  DLword dum;
  DLword FONTAVGCHARWIDTH;
  LispPTR FONTIMAGEWIDTHS;
  LispPTR FONTCHARSETVECTOR;
  LispPTR FONTEXTRAFIELD2;
} FONTDESC;

typedef struct {
  LispPTR WIDTHS;
  LispPTR OFFSETS;
  LispPTR IMAGEWIDTHS;
  LispPTR CHARSETBITMAP;
  LispPTR YWIDTHS;
  DLword CHARSETDESCENT;
  DLword CHARSETASCENT;
  LispPTR LEFTKERN;
} CHARSETINFO;
#endif /* BYTESWAP */

#define IMIN(x, y) (((x) > (y)) ? (y) : (x))
#define IMAX(x, y) (((x) > (y)) ? (x) : (y))

/** changecharset_display,sfffixy are not tested *****I don't use TAKE **/
#if 0
static LispPTR sfffixy(DISPLAYDATA *displaydata68k, CHARSETINFO *csinfo68k, PILOTBBT *pbt68k)

{
  int y;
  int chartop, top;
  BITMAP *bm68k;
  register LispPTR base, ypos, yoff;

  FGetNum2(displaydata68k->ddyoffset, yoff);
  FGetNum2(displaydata68k->ddyposition, ypos);

  y = ypos + yoff;

  displaydata68k->ddcharsetascent = csinfo68k->CHARSETASCENT;
  chartop = y + displaydata68k->ddcharsetascent;

  bm68k = (BITMAP *)Addr68k_from_LADDR(displaydata68k->dddestination);
  base = bm68k->bmbase;
  top = IMAX(IMIN(displaydata68k->ddclippingtop, chartop), 0);
  base = base + (bm68k->bmrasterwidth * (bm68k->bmheight - top));
  pbt68k->pbtdesthi = base >> 16;
  pbt68k->pbtdestlo = base;

  bm68k = (BITMAP *)Addr68k_from_LADDR(csinfo68k->CHARSETBITMAP);
  base = bm68k->bmbase;
  displaydata68k->ddcharheightdelta = IMIN(IMAX(chartop - top, 0), 65535); /* always positive */
  base = base + bm68k->bmrasterwidth * displaydata68k->ddcharheightdelta;
  pbt68k->pbtsourcehi = base >> 16;
  pbt68k->pbtsourcelo = base;

  displaydata68k->ddcharsetdescent = csinfo68k->CHARSETDESCENT;

  pbt68k->pbtheight =
      IMAX(0, top - (IMAX(y - displaydata68k->ddcharsetdescent, displaydata68k->ddclippingbottom)));
  return (T);

} /* sfffixy */

static LispPTR changecharset_display(register DISPLAYDATA *displaydata68k, DLword charset) {
  register PILOTBBT *pbt68k;
  register FONTDESC *fontd68k;
  LispPTR csinfo;
  register CHARSETINFO *csinfo68k;
  BITMAP *bm68k;
  LispPTR *base68k;

  pbt68k = (PILOTBBT *)Addr68k_from_LADDR(displaydata68k->ddpilotbbt);
  fontd68k = (FONTDESC *)Addr68k_from_LADDR(displaydata68k->ddfont);
  base68k = (LispPTR *)Addr68k_from_LADDR(fontd68k->FONTCHARSETVECTOR);

  if ((csinfo = *(base68k + charset)) == NIL) { return (-1); /* punt case */ }
  csinfo68k = (CHARSETINFO *)Addr68k_from_LADDR(csinfo);
  /* REF CNT */

  FRPLPTR(displaydata68k->ddwidthscache, csinfo68k->WIDTHS);
  FRPLPTR(displaydata68k->ddoffsetscache, csinfo68k->OFFSETS);
  FRPLPTR(displaydata68k->ddcharimagewidths, csinfo68k->IMAGEWIDTHS);
  displaydata68k->ddcharset = charset;

  bm68k = (BITMAP *)Addr68k_from_LADDR(csinfo68k->CHARSETBITMAP);

  pbt68k->pbtsourcebpl = (bm68k->bmrasterwidth) << 4;

  if ((displaydata68k->ddcharsetascent != csinfo68k->CHARSETASCENT) ||
      (displaydata68k->ddcharsetdescent != csinfo68k->CHARSETDESCENT)) {
    printf("CCD1\n");
    return (sfffixy(displaydata68k, csinfo68k, pbt68k));
  } else {
    register LispPTR addr;
    register int num;
    FGetNum2(displaydata68k->ddcharheightdelta, num); /* if not number, return -1 */
    addr = bm68k->bmbase + (bm68k->bmrasterwidth * num);
    printf("CCD2 num=%d\n", num);
    pbt68k->pbtsourcehi = addr >> 16;
    pbt68k->pbtsourcelo = addr; /* don't care REFCNT */
    return (T);
  }
} /* changecharset_display */
#endif
/******************************************************************/

void ccfuncall(register unsigned int atom_index, register int argnum, register int bytenum)
 /* Atomindex for Function you want to invoke */
 /* Number of ARGS on TOS and STK */
 /* Number of bytes of Caller's OPCODE(including multi-byte) */
{
  register struct definition_cell *defcell68k; /* Definition Cell PTR */
  register short pv_num;                       /* scratch for pv */
  register struct fnhead *tmp_fn;
  int rest; /* use for alignments */

  /* Get Next Block offset from argnum */
  CURRENTFX->nextblock = (LADDR_from_68k(CurrentStackPTR) & 0x0ffff) - (argnum << 1) + 4 /* +3  */;

  /* Setup IVar */
  IVar = Addr68k_from_LADDR((((LispPTR)(CURRENTFX->nextblock)) | STK_OFFSET));

  /* Set PC to the Next Instruction and save into FX */
  CURRENTFX->pc = ((UNSIGNED)PC - (UNSIGNED)FuncObj) + bytenum;

  PushCStack; /* save TOS */

  /* Get DEFCELL 68k address */
  defcell68k = (struct definition_cell *)GetDEFCELL68k(atom_index);

  tmp_fn = (struct fnhead *)Addr68k_from_LADDR(defcell68k->defpointer);

  if ((UNSIGNED)(CurrentStackPTR + tmp_fn->stkmin + STK_SAFE) >= (UNSIGNED)EndSTKP) {
    LispPTR test;
    test = *((LispPTR *)CurrentStackPTR);
    DOSTACKOVERFLOW(argnum, bytenum - 1);
    S_CHECK(test == *((LispPTR *)CurrentStackPTR), "stack overflow in ccfuncall");
  }
  FuncObj = tmp_fn;

  if (FuncObj->na >= 0) {
    /* This Function is Spread Type */
    /* Arguments on Stack Adjustment  */
    rest = argnum - FuncObj->na;

    while (rest < 0) {
      PushStack(NIL_PTR);
      rest++;
    }
    CurrentStackPTR -= (rest << 1);
  } /* if end */

  /* Set up BF */
  CurrentStackPTR += 2;
  GETWORD(CurrentStackPTR) = BF_MARK;
  GETWORD(CurrentStackPTR + 1) = CURRENTFX->nextblock;
  CurrentStackPTR += 2;

  /* Set up FX */
  GETWORD(CurrentStackPTR) = FX_MARK;

  /* Now SET new FX */
  ((struct frameex1 *)CurrentStackPTR)->alink = LADDR_from_68k(PVar);
  PVar = (DLword *)CurrentStackPTR + FRAMESIZE;
#ifdef BIGVM
  ((struct frameex1 *)CurrentStackPTR)->fnheader = (defcell68k->defpointer);
#else
  ((struct frameex1 *)CurrentStackPTR)->lofnheader = (defcell68k->defpointer) & 0x0ffff;
  ((struct frameex1 *)CurrentStackPTR)->hi2fnheader = ((defcell68k->defpointer) & SEGMASK) >> 16;
#endif /* BIGVM */
  CurrentStackPTR = PVar;

  /* Set up PVar area */
  pv_num = FuncObj->pv + 1; /* Changed Apr.27 */

  while (pv_num > 0) {
    *((LispPTR *)CurrentStackPTR) = 0x0ffff0000;
    CurrentStackPTR += DLWORDSPER_CELL;
    *((LispPTR *)CurrentStackPTR) = 0x0ffff0000;
    CurrentStackPTR += DLWORDSPER_CELL;
    pv_num--;
  }

  /* Set PC points New Function's first OPCODE */
  PC = (ByteCode *)FuncObj + FuncObj->startpc;
  /* It assume that ccfuncall is called  for PUNTing from SUBRCALL */
  PC -= 3; /* Ajust PC */

} /* end ccfuncall */

/****************************************************************/
/*                                                              */
/*                        tedit_bltchar                         */
/*                                                              */
/*     C-coded version of TEdit's character-painting function   */
/*              \\TEDIT.BLTCHAR                                         */
/*                                                              */
/****************************************************************/

/***************************/
/*   Non-PIXRECT version   */
/***************************/
void tedit_bltchar(LispPTR *args)
{
#define backwardflg 0
#define displayflg 0
  register DISPLAYDATA *displaydata68k;
  int right;
  register PILOTBBT *pbt;
  int imagewidth, newx;
  /* for new_char_bitblt_code */
  int h, w;
  int sx, dx, srcbpl, dstbpl, src_comp, op;
  DLword *srcbase, *dstbase;
  int gray = 0;
#ifdef NEWBITBLT
  int num_gray = 0, curr_gray_line = 0;
#endif

  displaydata68k = (DISPLAYDATA *)Addr68k_from_LADDR(((TBLTARG *)args)->displaydata);
  if (displaydata68k->ddcharset != ((TBLTARG *)args)->charset) {
    /**if(changecharset_display(displaydata68k, ((TBLTARG *)args)->charset)== -1)**/
    { PUNT_TO_TEDIT_BLTCHAR; }
  }
  imagewidth = *((DLword *)Addr68k_from_LADDR(displaydata68k->ddcharimagewidths + ((TBLTARG *)args)->char8code));
  newx = ((TBLTARG *)args)->current_x + imagewidth;
  dx = ((TBLTARG *)args)->current_x;
  right = IMIN(newx, ((TBLTARG *)args)->clipright);

  if (dx < right) {
    pbt = (PILOTBBT *)Addr68k_from_LADDR(displaydata68k->ddpilotbbt);
    h = pbt->pbtheight;
    srcbase = (DLword *)Addr68k_from_LADDR(VAG2(pbt->pbtsourcehi, pbt->pbtsourcelo));

    dstbase = (DLword *)Addr68k_from_LADDR(VAG2(pbt->pbtdesthi, pbt->pbtdestlo));
    srcbpl = abs(pbt->pbtsourcebpl);
    dstbpl = abs(pbt->pbtdestbpl);

    op = pbt->pbtoperation;
    src_comp = pbt->pbtsourcetype;

    /*dx=left;  I'll optimize  later*/
    sx = GETBASE(Addr68k_from_LADDR(displaydata68k->ddoffsetscache), ((TBLTARG *)args)->char8code);
    w = IMIN(imagewidth, (right - dx));
#ifdef NEWBITBLT
    bitblt(srcbase, dstbase, sx, dx, w, h, srcbpl, dstbpl, backwardflg, src_comp, op, gray,
           num_gray, curr_gray_line);
#else

    new_char_bitblt_code;
#endif
  }
#undef displayflg
#undef backwardflg

} /* end tedit_bltchar */

#if defined(REALCURSOR) || defined(SUNDISPLAY)
#ifndef COLOR
/* Lisp addr hi-word, lo-word, ... */
static int old_cursorin(DLword addrhi, DLword addrlo, int x, int w, int h, int y, int backward)
{
#ifdef INIT
  init_kbd_startup;
#endif
  if (addrhi == DISPLAY_HI)
    y = addrlo / DisplayRasterWidth;
  else if (addrhi == DISPLAY_HI + 1)
    y = (addrlo + DLWORDSPER_SEGMENT) / DisplayRasterWidth;
  else
    return (NIL);

  if (backward) y -= h;

  if ((x < MOUSEXR) && (x + w > MOUSEXL) && (y < MOUSEYH) && (y + h > MOUSEYL))
    return (T);
  else
    return (NIL);
}

#else
/* For MONO and COLOR */
/* Lisp addr hi-word, lo-word, ... */
static int old_cursorin(DLword addrhi, DLword addrlo, int x, int w, int h, int y, int backward)
{
  register DLword *base68k;
  extern int MonoOrColor;
  extern int displaywidth;
#ifdef INIT
  init_kbd_startup;
#endif

  if (MonoOrColor == MONO_SCREEN) {
    if (addrhi == DISPLAY_HI)
      y = addrlo / DisplayRasterWidth;
    else if (addrhi == DISPLAY_HI + 1)
      y = (addrlo + DLWORDSPER_SEGMENT) / DisplayRasterWidth;
    else
      return (NIL);

    if (backward) y -= h;

    if ((x < MOUSEXR) && (x + w > MOUSEXL) && (y < MOUSEYH) && (y + h > MOUSEYL))
      return (T);
    else
      return (NIL);
  } /* MONO case end */
  else {
    base68k = (DLword *)Addr68k_from_LADDR(addrhi << 16 | addrlo);
    if ((ColorDisplayRegion68k <= base68k) && (base68k <= COLOR_MAX_Address)) {
      y = (base68k - ColorDisplayRegion68k) / displaywidth;
    } else
      return (NIL);

    if (backward) y -= h;
    /*  printf("old_c:x=%d,y=%d,w=%d,h=%d\n",x,y,w,h);*/
    if ((x < MOUSEXR) && ((x + (w >> 3)) > MOUSEXL) && (y < MOUSEYH) &&
        (y + h > MOUSEYL)) { /* printf("old_c T\n");*/
      return (T);
    } else
      return (NIL);
  } /* COLOR case end */
}
#endif /* COLOR */
#endif /* defined(REALCURSOR) || defined(SUNDISPLAY) */
