#ifndef lint
static char SccsId[] = "%W%  %G%";
#endif

/* Module:	mgfydraw.c (Magnify Draw)
 * Purpose:	Quickly draw the zoomed piece of image in the zoom box
 * Subroutine:	draw_magnifier()			returns: void
 * Copyright:	1988, 1991, 1995 Smithsonian Astrophysical Observatory
 *		You may do anything you like with this file except remove
 *		this copyright.  The Smithsonian Astrophysical Observatory
 *		makes no representations about the suitability of this
 *		software for any purpose.  It is provided "as is" without
 *		express or implied warranty.
 * Modified:	{0} Michael VanHilst	initial version	      3 December 1988
 *		{1} MVH improved limit checking, added comments	   1 Jan 1991
 *		{2} MVH same fix as 1, for bitmap display	  21 Jun 1991
 *		{3} Doug Mink  cast valbuf to short for comp	   4 May 1995
 *		{n} <who> -- <does what> -- <when>
 */

#include <X11/Xlib.h>		/* X window stuff */
#include <X11/Xutil.h>		/* X window manager stuff */
#include "hfiles/color.h"	/* define GCspec */
#include "hfiles/magnify.h"	/* magnifier quick access structure */

struct magRec magset;


#ifdef ANSIC
/*  Exported declarations must be centralized before ANSI C can be used  */

void		draw_magnifier(	double bufx, double bufy );

#else

void draw_magnifier();
GC set_gc(), set_gc_with_background();
void blank_scope(), mark_Zmagnifier(), mark_XYmagnifier();

#endif


/* Subroutine:	draw_magnifier
 * Purpose:	Draw image in zoombox, quickly (use magset parameters)
 */
#ifdef ANSIC
void draw_magnifier( double bufx, double bufy )
#else
void draw_magnifier ( bufx, bufy )
     double bufx, bufy;
#endif
{
  int magXwdth, magYhght;	/* Dimensions of destination area drawn */
  int magX1, magY1;		/* Upper left coords of destination drawn */
  int bufX1, bufY1;		/* Upper left coords of source area */
  int Xrep1, Yrep1;		/* Repetitions of first pixel (on UL edge) */
  int margin;
  int imgjump;			/* Memory offset from end to start of next */
  /* Variables used in display loop */
  int rep;
  unsigned char *lookup;
  unsigned char *magline;
  int yline;
  int yrepend;

  /* Check for special handling */
  margin = 0;
  /* Check for being completely beyoind buffer and set initial dimensions */
  if( bufx < magset.buf.X1lim ) {
    blank_scope();
    return;
  }
  if( bufx <= magset.buf.X2bdr )
    magXwdth = magset.win.width;
  else {
    if( bufx > magset.buf.X2lim ) {
      blank_scope();
      return;
    }
    /* Note rounding for a negative number */
    magXwdth = magset.win.width +
      (int)(((magset.buf.X2bdr - bufx) * (float)magset.zoom_rep) - 0.5);
    margin = 1;
  }
  if( bufy < magset.buf.Y1lim ) {
    blank_scope();
    return;
  }
  if( bufy <= magset.buf.Y2bdr )
    magYhght = magset.win.height;
  else {
    if( bufy > magset.buf.Y2lim ) {
      blank_scope();
      return;
    }
    /* Note rounding for a negative number */
    magYhght = magset.win.height +
      (int)(((magset.buf.Y2bdr - bufy) * (float)magset.zoom_rep) - 0.5);
    margin = 1;
  }
  /* Convert to buffer coordinates, and calculate partial offsets */
  bufx -= magset.buf.Xcen;
  if( bufx >= 0.0 ) {
    int xrepoff;

    /* Left edge of magnifier within buffer */
    magX1 = 0;
    bufX1 = (int)bufx;
    /* Number of replications of first pixel is less fractional overlap */
    xrepoff = (int)((bufx - (float)bufX1) * magset.zoom_rep);
    if( xrepoff < magset.zoom_rep ) {
      Xrep1 = magset.zoom_rep - xrepoff;
      imgjump = magset.buf.width -
	(1 + ((magXwdth + xrepoff - 1) / magset.zoom_rep));
    } else {
      /* If rounds to next edge, skip first pixel */
      bufX1 += 1;
      Xrep1 = magset.zoom_rep;
      imgjump = magset.buf.width - (1 + ((magXwdth - 1) / magset.zoom_rep));
    }
  } else {
    /* Left edge of magnifier beyond buffer */
    magX1 = -(int)(0.5 + (bufx * magset.zoom_rep));
    magXwdth -= magX1;
    bufX1 = 0;
    Xrep1 = magset.zoom_rep;
    imgjump = magset.buf.width - (1 + ((magXwdth - 1) / magset.zoom_rep));
    margin = 1;
  }
  bufy -= magset.buf.Ycen;
  if( bufy >= 0.0 ) {
    /* Top edge of magnifier within buffer */
    magY1 = 0;
    bufY1 = (int)bufy;
    /* Number of replications of first pixel is less fractional overlap */
    Yrep1 = magset.zoom_rep -
      (int)((bufy - (float)bufY1) * (float)magset.zoom_rep);
    /* If rounds to next edge, skip first pixel */
    if( Yrep1 <= 0 ) {
      bufY1 += 1;
      Yrep1 = magset.zoom_rep;
    }
  } else {
    /* Top edge of magnifier beyond buffer */
    magY1 = -(int)(0.5 + (bufy * (float)magset.zoom_rep));
    magYhght -= magY1;
    bufY1 = 0;
    Yrep1 = magset.zoom_rep;
    margin = 1;
  }
  if( !magset.halftone ) {
    /* Variables used only in color loop */
    int magjump;
    register unsigned char *magbuf;
    if( margin == 1 ) {
      /* Image doesn't cover entire field, blank field, compute offset start */
      bzero(magset.data, magset.data_size);
      magbuf = (unsigned char *)magset.data + magX1 +
	(magset.win.width * magY1);
    } else {
      /* Simple start at top left corner of magnibox buffer */
      magbuf = (unsigned char *)magset.data;
    }
    {
      register unsigned char *xrowend;
      register unsigned char *xrepend;
      register short *imgbuf;

      /* Compute start in data buffer, get scaling lookup table */
      imgbuf = magset.buf.shortbuf + bufX1 + (bufY1 * magset.buf.width);
      lookup = magset.lookup;
      magjump = magset.win.width - magXwdth;
      rep = magset.zoom_rep;
      yline = 0;
      yrepend = Yrep1;
      while( yline < magYhght ) {
	magline = magbuf;
	/* Create row of magnibuf from image buffer data */
	xrowend = magbuf + magXwdth;
	xrepend = magbuf + Xrep1;
	while( magbuf < xrowend ) {
	  unsigned char val;

	  val = lookup[*imgbuf++];
	  /* Make sure repetition does not run beyond end */
	  if( xrepend > xrowend )
	    xrepend = xrowend;
	  while( magbuf < xrepend )
	    *magbuf++ = val;
	  xrepend += rep;
	}
	magbuf += magjump;
	imgbuf += imgjump;
	/* Make sure repetition does not run beyond end */
	if( yrepend > magYhght )
	  yrepend = magYhght;
	/* Copy original row for rep'd lines (magnification in Y direction) */
	while( ++yline < yrepend ) {
	  register unsigned char *copy;

	  copy = magline;
	  while( copy < xrowend )
	    *magbuf++ = *copy++;
	  magbuf += magjump;
	}
	yrepend += rep;
      }
    }
    {
      GC gc;
      /* Install the sighting mark */
      mark_Zmagnifier();
      gc = set_gc(magset.gcset_disp);
      XPutImage(magset.win.display, magset.win.ID, gc, magset.image,
		0, 0, magset.win.x, magset.win.y,
		magset.win.width, magset.win.height);
    }
  } else {
    /* Variables used only in bitmap loop */
    unsigned char *bitmap_row;
    short *matrix_row;
    int first_bit;
    unsigned char *valbuf;
    unsigned char linebuf[1024];

    /* Blank field */
    bzero((char *)magset.data, magset.bitmap_size);
    if( margin == 1 ) {
      /* Image doesn't cover entire field - compute offset start  */
      bitmap_row = (unsigned char *)
	magset.data + (magX1 / 8) + (magset.bytes_per_line * magY1);
      first_bit = magX1 & 7;
    } else {
      /* Simple start at top left corner of magnibox buffer */
      bitmap_row = (unsigned char *)magset.data;
      first_bit = 0;
    }
    {
      register unsigned char *bitmap_byte_or_xrepend;
      register unsigned char *xrowend;
      register short *imgbuf;

      /* Compute start in data buffer, get scaling lookup table */
      imgbuf = magset.buf.shortbuf + bufX1 + (bufY1 * magset.buf.width);
      lookup = magset.lookup;
      rep = magset.zoom_rep;
      matrix_row = magset.matrix;
      yline = 0;
      xrowend = linebuf + magXwdth;
      yrepend = Yrep1;
      while( yline < magYhght ) {
	/* Load scaled image data into temporary value buffer */
	valbuf = linebuf;
	bitmap_byte_or_xrepend = valbuf + Xrep1;
	while( valbuf < xrowend ) {
	  unsigned char val;

	  val = lookup[*imgbuf++];
	  if( bitmap_byte_or_xrepend > xrowend )
	    bitmap_byte_or_xrepend = xrowend;
	  while( valbuf < bitmap_byte_or_xrepend )
	    *valbuf++ = val;
	  bitmap_byte_or_xrepend += rep;
	}
	imgbuf += imgjump;
	/* Copy data line row for rep'd lines, using dither mask */
	bitmap_byte_or_xrepend = bitmap_row;
	if( magset.inverse ) {
	  if( yrepend > magYhght )
	    yrepend = magYhght;
	  while( yline < yrepend ) {
	    register short *matrix;
	    register int bitmap_bit;

	    /* Count lines when actually written */
	    yline++;
	    /* Set markers for start of a line */
	    bitmap_bit = first_bit;
	    valbuf = linebuf;
	    /* Point mask at start of dither mtrx row (each row is 16 wide) */
	    matrix = matrix_row;
	    while( valbuf < xrowend ) {
	      /* Set bit by comparing val to matrix entry */
	      if( (short)*valbuf++ <= matrix[bitmap_bit] ) 
		*bitmap_byte_or_xrepend |= 1 << bitmap_bit;
	      /* Check for next bitmap word */
	      if( ++bitmap_bit >= 8 ) {
		bitmap_bit = 0;
		++bitmap_byte_or_xrepend;
		if( matrix == matrix_row )
		  matrix += 8;
		else
		  matrix = matrix_row;
	      }
	    }
	    if( (matrix_row += 16) >= magset.matrix_end )
	      matrix_row = magset.matrix;
	    bitmap_byte_or_xrepend = (bitmap_row += magset.bytes_per_line);
	  }
	  yrepend += rep;
	} else {
	  if( yrepend > magYhght )
	    yrepend = magYhght;
	  while( yline < yrepend ) {
	    register short *matrix;
	    register int bitmap_bit;

	    /* Count lines when actually written */
	    yline++;
	    /* Set markers for start of a line */
	    bitmap_bit = first_bit;
	    valbuf = linebuf;
	    /* Point mask at start of dither mtrx row (each row is 16 wide) */
	    matrix = matrix_row;
	    while( valbuf < xrowend ) {
	      /* Set bit by comparing val to matrix entry */
	      if( (short)*valbuf++ > matrix[bitmap_bit] ) 
		*bitmap_byte_or_xrepend |= 1 << bitmap_bit;
	      /* Check for next bitmap word */
	      if( ++bitmap_bit >= 8 ) {
		bitmap_bit = 0;
		++bitmap_byte_or_xrepend;
		if( matrix == matrix_row )
		  matrix += 8;
		else
		  matrix = matrix_row;
	      }
	    }
	    if( (matrix_row += 16) >= magset.matrix_end )
	      matrix_row = magset.matrix;
	    bitmap_byte_or_xrepend = (bitmap_row += magset.bytes_per_line);
	  }
	  yrepend += rep;
	}
      }
    }
    {
      GC gc;
      /* Install the sighting mark */
      mark_XYmagnifier();
      gc = set_gc_with_background(magset.gcset_disp,
				  magset.gcset_disp->background);
      XPutImage(magset.win.display, magset.win.ID, gc, magset.image,
		0, 0, magset.win.x, magset.win.y,
		magset.win.width, magset.win.height);
    }
  }
}


syntax highlighted by Code2HTML, v. 0.9.1