/****************************************************************/
/* The function "extract_one()" of this module if from the	*/
/* file flextr.c of the FBM Library 0.9.			*/
/*								*/
/* Some changes are made, to work with one bit per pixel	*/
/* instead of 1 byte.						*/
/*								*/
/* The warning "out of bounds" is deleted, because I didn't	*/
/* understand it.						*/
/*								*/
/* 27-07-90  Georg Hessmann (hes)				*/
/* 14-11-90  Michael Illgner, speed improvement			*/
/****************************************************************/

/*****************************************************************
 * flextr.c: FBM Library 0.9 (Beta test) 07-Mar-89  Michael Mauldin
 *
 * Copyright (C) 1989 by Michael Mauldin.  Permission is granted to
 * use this file in whole or in part provided that you do not sell it
 * for profit and that this copyright notice is retained unchanged.
 *
 * flextr.c: Extract a rectangle and/or resize it.
 *
 * CONTENTS
 *	extract_fbm (input, output, xo, yo, w, h, ow, oh, title, credits)
 *
 * EDITLOG
 *	LastEditDate = Tue Mar  7 19:56:56 1989 - Michael Mauldin
 *	LastFileName = /usr2/mlm/src/misc/fbm/flextr.c
 *
 * HISTORY
 * 07-Mar-89  Michael Mauldin (mlm) at Carnegie Mellon University
 *	Beta release (version 0.9) mlm@cs.cmu.edu
 *
 * 12-Nov-88  Michael Mauldin (mlm) at Carnegie-Mellon University
 *	Created.
 *****************************************************************/


#include <stdio.h>
#include <libraries/dos.h>
#include <proto/dos.h>

#include "specialhost.h"


static unsigned char bit_mask[8] = { 1, 2, 4, 8, 16, 32, 64, 128 };

int extract_one(unsigned char *inbm, unsigned char *outbm,
		number cols,  number rows,	/* size input plane in pixel	*/
		number inlen, number outlen,	/* line length in bytes		*/
		number xo,    number yo,	/* offset in input plane	*/
		number w,     number h,		/* size input plane in pixel	*/
		number ow,    number oh)	/* size output plane in pixel	*/
{
  int xf, yf, xi, i;
  unsigned char *bm1, *bm2, *obm;
  int j, yi;
  long dc;
  int byte, bit;
  int ibyte, ibit;
  int ibyte1, ibit1;

  const long wh2 = (ow*oh)/2;
  const int  xm  = w % ow;
  const int  xd  = w / ow;

  struct DateStamp Date1, Date2;
  long diff;

  DateStamp(&Date1);

  /* Check for scale of 1-1, special case for speed */
  if (w == ow && h == oh && xo >= 0 && yo >= 0 && xo+w <= cols && yo+h <= rows) {
    for (j=0; j<h; j++) {
      bm1 = &inbm[(j+yo) * inlen];
      obm = &outbm[j * outlen];

      for (i=0; i<inlen; i++) {
        obm[i] = bm1[i+xo];
      }
    }
  }
  else {
    for (j=0; j<oh; j++) {

      if ((j & 255) == 255) {
        pline("   work on line %d (from %d lines)", j, oh);
      }

      yi = ((j*h) / oh) + yo;
      yf = ((j*h) % oh);
      
      obm = &outbm[j * outlen];
      bm1 = &inbm[yi * inlen];
      bm2 = bm1 + inlen;

      xf = 0; xi = xo;
      bit = 7; byte = 0;

      for (i=0; i<ow; i++) {

	ibit  = 7 - (xi & 0x00000007);
	ibyte = xi >> 3;
	
	ibyte1 = ibyte;
	ibit1 = ibit - 1;
	if (ibit1 < 0) {
	  ibit1 = 7;
	  ibyte1++;
	}

        if (xi < 0 || yi < 0 || xi > cols-2 || yi > rows-2) {
          /* If right on edge, just use edge value */
          if ((xi == cols-1 && yi >= 0 && yi <= rows-1) ||
              (yi == rows-1 && xi >= 0 && xi <= cols-1)) {
                obm[byte] |= (bm1[ibyte] & bit_mask[ibit] ) ? bit_mask[bit] : 0;
          }
          else {
            obm[byte] |= (unsigned char)bit_mask[bit];
          }
        }
        else {
	  dc = (((bm1[ibyte]  & bit_mask[ibit]) == 0)  ? 0 : (ow-xf)*(oh-yf)) +
	       (((bm2[ibyte]  & bit_mask[ibit]) == 0)  ? 0 : (ow-xf)*(yf)   ) +
	       (((bm1[ibyte1] & bit_mask[ibit1]) == 0) ? 0 : (xf)*(oh-yf)   ) +
	       (((bm2[ibyte1] & bit_mask[ibit1]) == 0) ? 0 : (xf)*(yf)      );
	  if (dc > wh2) {
	    obm[byte] |= bit_mask[bit];
	  }
        }
	xf += xm; xi += xd;
	if (xf >= ow) {
	  xf -= ow;
	  xi++;
	}

	bit--;
	if (bit == -1) {
	  bit = 7;
	  byte++;
	}
      }
    }
  }
  DateStamp(&Date2);
  diff = (Date2.ds_Days - Date1.ds_Days) * (24 * 60);
  diff = (diff + (Date2.ds_Minute - Date1.ds_Minute)) * 60 * TICKS_PER_SECOND;
  diff += Date2.ds_Tick - Date1.ds_Tick;
  pline("   Time: %7.2lf Seconds", (double)diff / (double)TICKS_PER_SECOND);
  
  return 1;
}
