/* rotate.c
 *
 * rotate an image
 *
 * Contributed by Tom Tatlow (tatlow@dash.enet.dec.com)
 */

#include "copyright.h"
#include "image.h"

/* rotate_bitmap()
 * converts an old bitmap bit position into a new one
 */
void rotate_bitmap(num, pos, width, height, new_num, new_pos)
int      num;				/* Source byte number       */
int      pos;				/* Source bit position      */
int    width;				/* Width of source bitmap   */
int   height;				/* Height of source bitmap  */
int *new_num;				/* Destination byte number  */
int *new_pos;				/* Destination bit position */
{
  int   slen;				/* Length of source line      */
  int   dlen;				/* Length of destination line */
  int sx, sy;
  int dx, dy;

  slen = (width / 8) + (width % 8 ? 1 : 0);
  dlen = (height / 8) + (height % 8 ? 1 : 0);
  sy = num / slen;
  sx = ((num - (sy * slen)) * 8) + pos;
  dx = (height - sy) - 1;
  dy = sx;
  *new_num = (dx / 8) + (dy * dlen);
  *new_pos = dx % 8;
}

/* rotate()
 * rotates an image
 */
Image *rotate(simage, degrees, verbose)
Image *simage;				/* Image to rotate             */
int    degrees;				/* Number of degrees to rotate */
{ 
  char buf[BUFSIZ];			/* New title                   */
  Image    *image1;			/* Source image                */
  Image    *image2=NULL;		/* Destination image           */
  byte         *sp;			/* Pointer to source data      */
  byte         *dp;			/* Pointer to destination data */
  int     slinelen;			/* Length of source line       */
  int     dlinelen;			/* Length of destination line  */
  int       bit[8];			/* Array of hex values         */
  int         x, y;
  int         i, b;
  int   newi, newb;
  byte      **yptr;

  bit[0] = 128;
  bit[1] =  64;
  bit[2] =  32;
  bit[3] =  16;
  bit[4] =   8;
  bit[5] =   4;
  bit[6] =   2;
  bit[7] =   1;

  goodImage(simage, "rotate");

  if (verbose)
    { fprintf(stderr, "  Rotating image by %d degrees...", degrees);
      fflush(stderr);
    }
  if (simage->title)
    sprintf(buf, "%s (rotated by %d degrees)", simage->title, degrees);

  image1 = simage;
  do {
    degrees -= 90;
    switch (image1->type) {
    case IBITMAP:
      image2= newBitImage(image1->height, image1->width);
      for (x= 0; x < image1->rgb.used; x++) {
	*(image2->rgb.red + x)= *(image1->rgb.red + x);
	*(image2->rgb.green + x)= *(image1->rgb.green + x);
	*(image2->rgb.blue + x)= *(image1->rgb.blue + x);
      }
      slinelen= (image1->width / 8) + (image1->width % 8 ? 1 : 0);
      sp = image1->data;
      dp = image2->data;
      for (i = 0; i < (slinelen * image1->height); i++)
	for (b = 0; b < 8; b++)
	  if (sp[i] & bit[b])
	    { rotate_bitmap(i, b, image1->width, image1->height, &newi, &newb);
	      dp[newi] |= bit[newb];
	    }
      break;
      
    case IRGB:
      image2= newRGBImage(image1->height, image1->width, image1->depth);
      for (x= 0; x < image1->rgb.used; x++) {
	*(image2->rgb.red + x)= *(image1->rgb.red + x);
	*(image2->rgb.green + x)= *(image1->rgb.green + x);
	*(image2->rgb.blue + x)= *(image1->rgb.blue + x);
      }
      image2->rgb.used= image1->rgb.used;
      /* FALLTHRU */

    case ITRUE:
      if (TRUEP(image1))
	image2= newTrueImage(image1->height, image1->width);

      /* build array of y axis ptrs into destination image
       */

      yptr= (byte **)lmalloc(image1->width * sizeof(char *));
      dlinelen= image1->height * image1->pixlen;
      for (y= 0; y < image1->width; y++)
	yptr[y]= image2->data + (y * dlinelen);

      /* rotate
       */

      sp= image1->data;
      for (y = 0; y < image1->height; y++)
	for (x = 0; x < image1->width; x++) {
	  valToMem(memToVal(sp, image1->pixlen),
		   yptr[x] + ((image1->height - y - 1) * image1->pixlen),
		   image1->pixlen);
	  sp += image1->pixlen;
	}
      lfree(yptr);
      break;
    default:
      fprintf(stderr, "rotate: Unsupported image type\n");
      cleanup(-1);
    }
    if (image1 != simage)
      freeImage(image1);
    image1 = image2;
  } while (degrees);
  image1->title= dupString(buf);
  if (verbose)
    fprintf(stderr, "done\n");
  return(image1);
}

