[comp.graphics] Rotating bitmat 90 degrees

rsbx@cbmvax.commodore.com (Raymond S. Brand) (04/17/91)

Due to the number of requests, I'm posting this instead of emailing.

The request was for a way to rotate a bitmap 90 degrees without having to do
a readpixel/writepixel for each pixel in the area to rotate. What follows is
a shar file with the source (Amiga but you can understand it anyway :-) to 2
rotate functions and 2 test programs.

						rsbx

------------------------------------------------------------------------
  Raymond S. Brand			rsbx@cbmvax.commodore.com
  Commodore-Amiga Engineering		...!uunet!cbmvax!rsbx
  1200 Wilson Drive			(215)-431-9100
  West Chester PA 19380			"Looking"
------------------------------------------------------------------------


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	readme
#	rastport.c
#	rotate1.c
#	rotatebitmap.c
#	rotatebitmap.h
#	test.c
#	test.lnk
#	test1.c
#	test1.lnk
# This archive created: Wed Apr 17 11:57:26 1991
# By:	Raymond S. Brand (Commodore-Amiga Inc, West Chester, PA)
export PATH; PATH=/bin:$PATH
if test -f 'readme'
then
	echo shar: will not over-write existing file "'readme'"
else
sed 's/^X//' << \HI_MOM > 'readme'
XWARNING: I use a Hedley display (big). You may need to change some sizes in
X	the test/demonstration programs if you don't.
X
XThe algorithm for the rotate square is from the Smalltalk-80 book referenced
Xbelow; the rotate rectangle algorithm is a modification of the square 
Xalgorithm.
X
XThe code is not recursive and makes O(log2(M)) calls to the blitter
Xfunctions where M is MAX(X_size, Y_size) of the area to rotate.
X
XIf you do something interesting with this, please let me know what you did.
X
X						rsbx
X
XReferences:
X	Goldberg and Robson, Smalltalk-80: The Language and Implementation,
X		Addison Wesley 1983, pp 408-411.
X
X------------------------------------------------------------------------
X  Raymond S. Brand			rsbx@cbmvax.commodore.com
X  Commodore-Amiga Engineering		...!uunet!cbmvax!rsbx
X  1200 Wilson Drive			(215)-431-9100
X  West Chester PA 19380			"Looking"
X------------------------------------------------------------------------
HI_MOM
fi # end of overwriting check
if test -f 'rastport.c'
then
	echo shar: will not over-write existing file "'rastport.c'"
else
sed 's/^X//' << \HI_MOM > 'rastport.c'
X/*
X**	$Id$
X**
X**	Create and free RastPorts.
X**
X**	(C) Copyright 1991 Raymond S. Brand
X**		All Rights Reserved
X*/
X
X
X#include <exec/types.h>
X#include <graphics/rastport.h>
X#include <proto/graphics.h>
X#include <proto/exec.h>
X
Xstruct RastPort *NewRastPort(int x, int y, int depth)
X	{
X	struct RastPort *rp;
X	struct BitMap *bm;
X	int i;
X
X	if (!(rp = AllocMem(sizeof(struct RastPort), 0)))
X		{
X		goto Exit1;
X		}
X
X	if (!(bm = AllocMem(sizeof(struct BitMap), 0)))
X		{
X		goto Exit2;
X		}
X
X	for (i = 0; i < depth; i++)
X		{
X		bm->Planes[i] = NULL;
X		}
X
X	for (i = 0; i < depth; i++)
X		{
X		if (!(bm->Planes[i] = AllocRaster(x, y)))
X			{
X			goto Exit3;
X			}
X		}
X
X	InitBitMap(bm, depth, x, y);
X	InitRastPort(rp);
X	rp->BitMap = bm;
X
X	return rp;
X
X
X
XExit3:
X	for (i = 0; i < depth; i++)
X		{
X		if (bm->Planes[i])
X			{
X			FreeRaster(bm->Planes[i], x, y);
X			}
X		}
X	FreeMem(bm, sizeof(struct BitMap));
XExit2:
X	FreeMem(rp, sizeof(struct RastPort));
XExit1:
X	return 0;
X	}
X
X
Xvoid FreeRastPort(struct RastPort *rp, int x, int y, int depth)
X	{
X	int i;
X
X	if (!rp)
X		{
X		return;
X		}
X
X	if (rp->BitMap)
X		{
X		for (i = 0; i < depth; i++)
X			{
X			if (rp->BitMap->Planes[i])
X				{
X				FreeRaster(rp->BitMap->Planes[i], x, y);
X				}
X			}
X		FreeMem(rp->BitMap, sizeof(struct BitMap));
X		}
X
X	FreeMem(rp, sizeof(struct RastPort));
X	}
HI_MOM
fi # end of overwriting check
if test -f 'rotate1.c'
then
	echo shar: will not over-write existing file "'rotate1.c'"
else
sed 's/^X//' << \HI_MOM > 'rotate1.c'
X/*
X**	$Id$
X**
X**	Rotate a retacngular area 90 deg. to another retangular area.
X**
X**	(C) Copyright 1991 Raymond S. Brand
X**		All Rights Reserved
X*/
X
X
X#include <exec/types.h>
X#include <graphics/rastport.h>
X#include <proto/graphics.h>
X#include "rotatebitmap.h"
X#include <math.h>
X
X
Xextern struct RastPort *NewRastPort(int x, int y, int depth);
Xextern void FreeRastPort(struct RastPort *rp, int x, int y, int depth);
X
X
Xint Rotate(struct RastPort *src, int OsrcX, int Osrcy, struct RastPort *dst, int OdstX, int OdstY, int sizeX, int sizeY,
X	struct RastPort *mask, struct RastPort *temp)
X	{
X	int s;
X	int q;
X	int a;
X	int b;
X	int z;
X	int n;
X/*
X *	struct RastPort *mask;
X *	struct RastPort *temp;
X *	int depth;
X */
X
X	s = min(sizeX, sizeY);
X
X	q = 1;
X
X	while (q < s)
X		{
X		q <<= 1;
X		}
X
X	s = q >> 1;
X	q = s >> 1;
X/*
X *	depth = dst->BitMap->Depth;
X *
X *	if (!(temp = NewRastPort(sizeX, sizeY, depth)))
X *		{
X *		return ERROR_NEWRASTPORT_FAILED;
X *		}
X *
X *	if (!(mask = NewRastPort(sizeX, sizeY, depth)))
X *		{
X *		FreeRastPort(temp, sizeX, sizeY, depth);
X *		return ERROR_NEWRASTPORT_FAILED;
X *		}
X */
X	ClipBlit(mask, 0, 0, mask, 0, 0,   sizeX,   sizeY, OP_D_EQ_ZERO    );
X
X	a = b = 0;
X
X	if (sizeX > sizeY)
X		{
X		a = sizeX - (sizeX%s);
X		}
X	else
X		{
X		b = sizeY - (sizeY%s);
X		}
X
X	while (q)
X		{
X		if ((b+s) <= sizeY)
X			{
X			for (z=0; z<a; z+=s)
X				{
X
X				ClipBlit( src, b, sizeX-z-s,  dst, z, b, s, s, OP_D_EQ_S    );
X
X				ClipBlit(mask, z, b, mask, z, b, q, q, OP_D_EQ_ONE  );
X				}
X			b += s;
X			}
X
X		if ((a+s) <= sizeX)
X			{
X			for (z=0; z<b; z+=s)
X				{
X
X				ClipBlit( src, z, sizeX-a-s,  dst, a, z, s, s, OP_D_EQ_S    );
X
X				ClipBlit(mask, a, z, mask, a, z, q, q, OP_D_EQ_ONE  );
X				}
X			a += s;
X			}
X
X		/*
X		 * exchange right & left halves
X		 */
X		ClipBlit(mask, 0, 0, temp, 0, 0,   a,   b, OP_D_EQ_S       );
X		ClipBlit(mask, 0, 0, temp, 0, q,   a, b-q, OP_D_EQ_S_OR_D  );
X		ClipBlit( dst, 0, 0, temp, 0, 0,   a,   b, OP_D_EQ_S_AND_D );
X		ClipBlit(temp, 0, 0,  dst, 0, 0,   a,   b, OP_D_EQ_S_XOR_D );
X		ClipBlit( dst, q, 0, temp, 0, 0, a-q,   b, OP_D_EQ_S_XOR_D );
X		ClipBlit( dst, q, 0,  dst, 0, 0, a-q,   b, OP_D_EQ_S_OR_D  );
X		ClipBlit(temp, 0, 0,  dst, q, 0, a-q,   b, OP_D_EQ_S_XOR_D );
X
X		/*
X		 * exchange diagonals
X		 */
X		ClipBlit( dst, 0, 0, temp, 0, 0,   a,   b, OP_D_EQ_S       );
X		ClipBlit( dst, q, q, temp, 0, 0, a-q, b-q, OP_D_EQ_S_XOR_D );
X		ClipBlit(mask, 0, 0, temp, 0, 0,   a,   b, OP_D_EQ_S_AND_D );
X		ClipBlit(temp, 0, 0,  dst, 0, 0,   a,   b, OP_D_EQ_S_XOR_D );
X		ClipBlit(temp, 0, 0,  dst, q, q, a-q, b-q, OP_D_EQ_S_XOR_D );
X
X
X		n = q>>1;
X		ClipBlit(mask, n, n, mask, 0, 0, a-n, b-n, OP_D_EQ_S_AND_D );
X		ClipBlit(mask, 0, 0, mask, 0, q,   a, b-q, OP_D_EQ_S_OR_D  );
X		ClipBlit(mask, 0, 0, mask, q, 0, a-q,   b, OP_D_EQ_S_OR_D  );
X
X		s = q;
X		q >>= 1;
X		}
X
X/*
X *	LINEROTATE
X */
X	if (b < sizeY)
X		{
X		for (z=0; z<a; z++)
X			{
X			SetAPen(dst, ReadPixel(src, b, sizeX-z-1));
X			WritePixel(dst, z, b);
X			}
X		b++;
X		}
X
X	if (a < sizeX)
X		{
X		for (z=0; z<b; z++)
X			{
X			SetAPen(dst, ReadPixel(src, z, sizeX-a-1));
X			WritePixel(dst, a, z);
X			}
X		}
X
X/*
X *	FreeRastPort(temp, sizeX, sizeY, depth);
X *	FreeRastPort(mask, sizeX, sizeY, depth);
X */
X	return 0;
X	}
HI_MOM
fi # end of overwriting check
if test -f 'rotatebitmap.c'
then
	echo shar: will not over-write existing file "'rotatebitmap.c'"
else
sed 's/^X//' << \HI_MOM > 'rotatebitmap.c'
X/*
X**	$Id$
X**
X**	Rotate a square, size 2^n rastport 90 deg.
X**
X**	(C) Copyright 1991 Raymond S. Brand
X**		All Rights Reserved
X*/
X
X
X#include <exec/types.h>
X#include <graphics/rastport.h>
X#include <proto/graphics.h>
X#include "rotatebitmap.h"
X
X
Xextern struct RastPort *NewRastPort(int x, int y, int depth);
Xextern void FreeRastPort(struct RastPort *rp, int x, int y, int depth);
X
X
Xint Rotate(struct RastPort *self, int s)
X	{
X	int q;		/* control variable */
X	int n;		/* temp */
X	int depth;
X	struct RastPort *temp;
X	struct RastPort *mask;
X
X	/*
X	 * need to do RastPort size error checking here
X	 */
X
X	if (s < 2)
X		{
X		return 0;
X		}
X
X	q = 1;
X
X	while(q < s)
X		{
X		q <<= 1;
X		}
X
X	if (q != s)
X		{
X		return ERROR_SIZE_NOT_POWER_OF_TWO;
X		}
X
X	depth = self->BitMap->Depth;
X
X	if (!(temp = NewRastPort(s, s, depth)))
X		{
X		return ERROR_NEWRASTPORT_FAILED;
X		}
X
X	if (!(mask = NewRastPort(s, s, depth)))
X		{
X		FreeRastPort(temp, s, s, depth);
X		return ERROR_NEWRASTPORT_FAILED;
X		}
X
X	ClipBlit(mask, 0, 0, mask, 0, 0,   s,   s, OP_D_EQ_ZERO    );
X	ClipBlit(mask, 0, 0, mask, 0, 0, s/2, s/2, OP_D_EQ_ONE     );
X
X	while( q >>= 1 )
X		{
X		/*
X		 * exchange right & left halves
X		 */
X		ClipBlit(mask, 0, 0, temp, 0, 0,   s,   s, OP_D_EQ_S       );
X		ClipBlit(mask, 0, 0, temp, 0, q,   s, s-q, OP_D_EQ_S_OR_D  );
X		ClipBlit(self, 0, 0, temp, 0, 0,   s,   s, OP_D_EQ_S_AND_D );
X		ClipBlit(temp, 0, 0, self, 0, 0,   s,   s, OP_D_EQ_S_XOR_D );
X		ClipBlit(self, q, 0, temp, 0, 0, s-q,   s, OP_D_EQ_S_XOR_D );
X		ClipBlit(self, q, 0, self, 0, 0, s-q,   s, OP_D_EQ_S_OR_D  );
X		ClipBlit(temp, 0, 0, self, q, 0, s-q,   s, OP_D_EQ_S_XOR_D );
X		/*
X		 * exchange diagonals
X		 */
X		ClipBlit(self, 0, 0, temp, 0, 0,   s,   s, OP_D_EQ_S       );
X		ClipBlit(self, q, q, temp, 0, 0, s-q, s-q, OP_D_EQ_S_XOR_D );
X		ClipBlit(mask, 0, 0, temp, 0, 0,   s,   s, OP_D_EQ_S_AND_D );
X		ClipBlit(temp, 0, 0, self, 0, 0,   s,   s, OP_D_EQ_S_XOR_D );
X		ClipBlit(temp, 0, 0, self, q, q, s-q, s-q, OP_D_EQ_S_XOR_D );
X		/*
X		 * refine mask
X		 */
X		n = q>>1;
X		ClipBlit(mask, n, n, mask, 0, 0, s-n, s-n, OP_D_EQ_S_AND_D );
X		ClipBlit(mask, 0, 0, mask, 0, q,   s, s-q, OP_D_EQ_S_OR_D  );
X		ClipBlit(mask, 0, 0, mask, q, 0, s-q,   s, OP_D_EQ_S_OR_D  );
X		}
X
X	FreeRastPort(temp, s, s, depth);
X	FreeRastPort(mask, s, s, depth);
X	return 0;
X	}
HI_MOM
fi # end of overwriting check
if test -f 'rotatebitmap.h'
then
	echo shar: will not over-write existing file "'rotatebitmap.h'"
else
sed 's/^X//' << \HI_MOM > 'rotatebitmap.h'
X/*
X**	$Id$
X**
X**	Constants for RoateBitMap.c
X**
X**	(C) Copyright 1991 Raymond S. Brand
X**		All Rights Reserved
X*/
X
X
X#define OK				0
X#define ERROR_SIZE_NOT_POWER_OF_TWO	1
X#define ERROR_NEWRASTPORT_FAILED	2
X#define OP_D_EQ_ZERO			0x00
X#define OP_D_EQ_ONE			0xf0
X#define OP_D_EQ_S			0xc0
X#define OP_D_EQ_S_OR_D			0xe0
X#define OP_D_EQ_S_AND_D			0x80
X#define OP_D_EQ_S_XOR_D			0x60
HI_MOM
fi # end of overwriting check
if test -f 'test.c'
then
	echo shar: will not over-write existing file "'test.c'"
else
sed 's/^X//' << \HI_MOM > 'test.c'
X/*
X**	$Id$
X**
X**	Test/demonstration program for RotateBiitMap.
X**
X**	(C) Copyright 1991 Raymond S. Brand
X**		All Rights Reserved
X*/
X
X
X#include <exec/types.h>
X#include <graphics/gfxbase.h>
X#include <proto/exec.h>
X#include <proto/graphics.h>
X
X#include <intuition/intuition.h>
X#include <proto/intuition.h>
X
X
X#define SIZE 512
X
X
Xint Rotate(struct RastPort *self, int s);
X
X
Xextern struct Library *SysBase;
Xstruct IntuitionBase *IntuitionBase = NULL;
Xstruct Window *win = NULL;
Xstruct GfxBase *GfxBase = NULL;
X
X
Xstruct NewWindow nw =
X	{
X	0, 0,			/* LeftEdge, TopEdge */
X	SIZE, SIZE,		/* Width, Height */
X	-1, -1,			/* DetailPen, BlockPen */
X	SMART_REFRESH|NOCAREREFRESH,	/* IDCMPFlags */
X	WINDOWDRAG,		/* Flags */
X	NULL,			/* FirstGadget */
X	NULL,			/* CheckMark */
X	"Rotate BitMap Test Window",	/* Title */
X	NULL, NULL,		/* Screen, BitMap */
X	SIZE, SIZE,		/* MinWidth, MinHeight */
X	SIZE, SIZE,		/* MaxWidth, MaxHeight */
X	WBENCHSCREEN		/* Type */
X	};
X
X
X
Xvoid main(int argc, char **argv)
X	{
X	if (!( IntuitionBase = (struct IntuitionBase *)
X		OpenLibrary("intuition.library", 0) ))
X		{
X		printf("Couldn't open Intuition.\n");
X		goto Error;
X		}
X
X	if (!( GfxBase = (struct GfxBase *)
X		OpenLibrary("graphics.library", 0) ))
X		{
X		printf("Couldn't open Graphics.\n");
X		goto Error;
X		}
X
X	if (!( win = OpenWindow(&nw)))
X		{
X		printf("Couldn't open window.\n");
X		goto Error;
X		}
X
X	Delay(200);
X
X	Rotate(win->RPort, SIZE);
X
X	Rotate(win->RPort, SIZE);
X
X	Rotate(win->RPort, SIZE);
X
X	Rotate(win->RPort, SIZE);
X
X	Delay(200);
X
X
XError:
X	if (win)
X		CloseWindow(win);
X
X	if (GfxBase)
X		CloseLibrary(GfxBase);
X
X	if (IntuitionBase)
X		CloseLibrary(IntuitionBase);
X
X	exit(0);
X}
HI_MOM
fi # end of overwriting check
if test -f 'test.lnk'
then
	echo shar: will not over-write existing file "'test.lnk'"
else
sed 's/^X//' << \HI_MOM > 'test.lnk'
XFROM LIB:c.o+"test.o"+"rotatebitmap.o"+"rastport.o"
XTO "test"
XLIB LIB:lc.lib LIB:amiga.lib
X
HI_MOM
fi # end of overwriting check
if test -f 'test1.c'
then
	echo shar: will not over-write existing file "'test1.c'"
else
sed 's/^X//' << \HI_MOM > 'test1.c'
X/*
X**	$Id$
X**
X**	Test/demonstration program for Rotate1.c
X**
X**	(C) Copyright 1991 Raymond S. Brand
X**		All Rights Reserved
X*/
X
X
X#include <exec/types.h>
X#include <graphics/gfxbase.h>
X#include <proto/exec.h>
X#include <proto/graphics.h>
X
X#include <intuition/intuition.h>
X#include <proto/intuition.h>
X
X
X#define XSIZE 255
X#define YSIZE 127
X#define SPACING 300
X
X
Xint Rotate(struct RastPort *src, int OsrcX, int Osrcy, struct RastPort *dst, int OdstX, int OdstY, int sizeX, int sizeY,
X	struct RastPort *mask, struct RastPort *temp);
X
X
Xextern struct Library *SysBase;
Xstruct IntuitionBase *IntuitionBase = NULL;
Xstruct Window *win1 = NULL;
Xstruct Window *win2 = NULL;
Xstruct Window *win3 = NULL;
Xstruct Window *win4 = NULL;
Xstruct GfxBase *GfxBase = NULL;
X
X
Xstruct NewWindow nw1 =
X	{
X	0, 0,			/* LeftEdge, TopEdge */
X	YSIZE, XSIZE,		/* Width, Height */
X	-1, -1,			/* DetailPen, BlockPen */
X	SMART_REFRESH|NOCAREREFRESH,	/* IDCMPFlags */
X	WINDOWDRAG,		/* Flags */
X	NULL,			/* FirstGadget */
X	NULL,			/* CheckMark */
X	"Rotate BitMap src Window",	/* Title */
X	NULL, NULL,		/* Screen, BitMap */
X	YSIZE, XSIZE,		/* MinWidth, MinHeight */
X	YSIZE, XSIZE,		/* MaxWidth, MaxHeight */
X	WBENCHSCREEN		/* Type */
X	};
X
Xstruct NewWindow nw2 =
X	{
X	SPACING, 0,		/* LeftEdge, TopEdge */
X	XSIZE, YSIZE,		/* Width, Height */
X	-1, -1,			/* DetailPen, BlockPen */
X	SMART_REFRESH|NOCAREREFRESH,	/* IDCMPFlags */
X	WINDOWDRAG,		/* Flags */
X	NULL,			/* FirstGadget */
X	NULL,			/* CheckMark */
X	"Rotate BitMap dst Window",	/* Title */
X	NULL, NULL,		/* Screen, BitMap */
X	XSIZE, YSIZE,		/* MinWidth, MinHeight */
X	XSIZE, YSIZE,		/* MaxWidth, MaxHeight */
X	WBENCHSCREEN		/* Type */
X	};
X
Xstruct NewWindow nw3 =
X	{
X	0, SPACING,		/* LeftEdge, TopEdge */
X	XSIZE, YSIZE,		/* Width, Height */
X	-1, -1,			/* DetailPen, BlockPen */
X	SMART_REFRESH|NOCAREREFRESH,	/* IDCMPFlags */
X	WINDOWDRAG,		/* Flags */
X	NULL,			/* FirstGadget */
X	NULL,			/* CheckMark */
X	"Rotate BitMap mask Window",	/* Title */
X	NULL, NULL,		/* Screen, BitMap */
X	XSIZE, YSIZE,		/* MinWidth, MinHeight */
X	XSIZE, YSIZE,		/* MaxWidth, MaxHeight */
X	WBENCHSCREEN		/* Type */
X	};
X
Xstruct NewWindow nw4 =
X	{
X	SPACING, SPACING,	/* LeftEdge, TopEdge */
X	XSIZE, YSIZE,		/* Width, Height */
X	-1, -1,			/* DetailPen, BlockPen */
X	SMART_REFRESH|NOCAREREFRESH,	/* IDCMPFlags */
X	WINDOWDRAG,		/* Flags */
X	NULL,			/* FirstGadget */
X	NULL,			/* CheckMark */
X	"Rotate BitMap temp Window",	/* Title */
X	NULL, NULL,		/* Screen, BitMap */
X	XSIZE, YSIZE,		/* MinWidth, MinHeight */
X	XSIZE, YSIZE,		/* MaxWidth, MaxHeight */
X	WBENCHSCREEN		/* Type */
X	};
X
X
X
Xvoid main(int argc, char **argv)
X	{
X	if (!( IntuitionBase = (struct IntuitionBase *)
X		OpenLibrary("intuition.library", 0) ))
X		{
X		printf("Couldn't open Intuition.\n");
X		goto Error;
X		}
X
X	if (!( GfxBase = (struct GfxBase *)
X		OpenLibrary("graphics.library", 0) ))
X		{
X		printf("Couldn't open Graphics.\n");
X		goto Error;
X		}
X
X	if (!( win1 = OpenWindow(&nw1)))
X		{
X		printf("Couldn't open window.\n");
X		goto Error;
X		}
X
X	if (!( win2 = OpenWindow(&nw2)))
X		{
X		printf("Couldn't open window.\n");
X		goto Error;
X		}
X
X	if (!( win3 = OpenWindow(&nw3)))
X		{
X		printf("Couldn't open window.\n");
X		goto Error;
X		}
X
X	if (!( win4 = OpenWindow(&nw4)))
X		{
X		printf("Couldn't open window.\n");
X		goto Error;
X		}
X
X	Delay(200);
X
X	Rotate(win1->RPort, 0, 0, win2->RPort, 0, 0, XSIZE, YSIZE, win3->RPort, win4->RPort);
X
X	Delay(200);
X
X
XError:
X	if (win1)
X		CloseWindow(win1);
X
X	if (win2)
X		CloseWindow(win2);
X
X	if (win3)
X		CloseWindow(win3);
X
X	if (win4)
X		CloseWindow(win4);
X
X	if (GfxBase)
X		CloseLibrary(GfxBase);
X
X	if (IntuitionBase)
X		CloseLibrary(IntuitionBase);
X
X	exit(0);
X}
HI_MOM
fi # end of overwriting check
if test -f 'test1.lnk'
then
	echo shar: will not over-write existing file "'test1.lnk'"
else
sed 's/^X//' << \HI_MOM > 'test1.lnk'
XFROM LIB:c.o+"test1.o"+"rotate1.o"
XTO "test1"
XLIB LIB:lc.lib LIB:amiga.lib
XADDSYM
X
HI_MOM
fi # end of overwriting check
#	End of shell archive
exit 0

------------------------------------------------------------------------
  Raymond S. Brand			rsbx@cbmvax.commodore.com
  Commodore-Amiga Engineering		...!uunet!cbmvax!rsbx
  1200 Wilson Drive			(215)-431-9100
  West Chester PA 19380			"Looking"
------------------------------------------------------------------------

jef@well.sf.ca.us (Jef Poskanzer) (04/21/91)

In the referenced message, rsbx@cbmvax.commodore.com (Raymond S. Brand) wrote:
}The request was for a way to rotate a bitmap 90 degrees without having to do
}a readpixel/writepixel for each pixel in the area to rotate. What follows is
}a shar file with the source (Amiga but you can understand it anyway :-) to 2
}rotate functions and 2 test programs.

Appended is a version for Suns using raw pixrect calls.  It's embedded
in a screen-rot program of the same genre as meltdown and termite, but
the rotation routine may be useful by itself.
---
Jef

  Jef Poskanzer  jef@well.sf.ca.us  {apple, ucbvax, hplabs}!well!jef
  If you eat a live frog in the morning, nothing worse will happen to
                either of you for the rest of the day.

/*
** sunrot - rot a Sun screen by rotating random squares
**
** Compile with: cc -O sunrot.c -lpixrect -s -o sunrot
**
** The rotation algorithm is similar to the one in "Smalltalk-80: The
** Language and Implementation", page 408.  In particular, the mask
** refinement step is the same.  However, the rest is different, simpler,
** doesn't flash white bars on the screen, and runs slightly faster (same
** number of blits but smaller area), at the cost of three off-screen
** temp areas instead of two.  I consider this modified version fairly
** obvious, in case anyone is getting any stupid ideas about patenting
** it.  The original version was non-obvious, but memory has gotten a
** lot cheaper since 1983.
**
** Copyright (C) 1991 by Jef Poskanzer.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include <sys/types.h>
#include <sys/timeb.h>
#include <sys/file.h>
#include <pixrect/pixrect_hs.h>
#define PIX_AND ( PIX_SRC & PIX_DST )
#define PIX_OR ( PIX_SRC | PIX_DST )

Pixrect* my_pr_open();
void pr_rotatepow2square();

void
main( argc, argv )
    int argc;
    char* argv[];
    {
    int argn, delay;
    struct timeb tb;
    Pixrect* disp_pr;
    int wid, hgt, maxpow2;
    int x, y, pow2, cw;
    char* fb;
    char* usage = "usage:  %s [-fb <framebuffer>] [-delay <msec>]\n";

    argn = 1;
    fb = "/dev/fb";
    delay = 0;
    if ( argn < argc && argv[argn][0] == '-' )
	{
	if ( strcmp( argv[argn], "-fb" ) == 0 ||
	     strcmp( argv[argn], "-f" ) == 0 )
	    {
	    ++argn;
	    fb = argv[argn];
	    }
	else if ( strcmp( argv[argn], "-delay" ) == 0 ||
		  strcmp( argv[argn], "-dela" ) == 0 ||
		  strcmp( argv[argn], "-del" ) == 0 ||
		  strcmp( argv[argn], "-de" ) == 0 ||
		  strcmp( argv[argn], "-d" ) == 0 )
	    {
	    ++argn;
	    delay = atoi( argv[argn] );
	    }
	else
	    {
	    fprintf( stderr, usage, argv[0] );
	    exit( 1 );
	    }
	++argn;
	}
    
    if ( argn != argc )
	{
	fprintf( stderr, usage, argv[0] );
	exit( 1 );
	}

    if ( ( disp_pr = my_pr_open( fb ) ) == (Pixrect*) 0 )
	{
	fprintf( stderr, "%s: error opening display\n", argv[0] );
	exit( 1 );
	}

    wid = disp_pr->pr_size.x;
    hgt = disp_pr->pr_size.y;
    for ( maxpow2 = 1;
	 ( 2 << maxpow2 ) <= wid && ( 2 << maxpow2 ) <= hgt;
	 ++maxpow2 )
	;

    ftime( &tb );
    srandom( (int) ( tb.time ^ tb.millitm ^ getpid( ) ) );

    for ( ; ; )
	{
	pow2 = random() % ( maxpow2 + 1 );
	x = random() % ( wid - ( 1 << pow2 ) );
	y = random() % ( hgt - ( 1 << pow2 ) );
	cw = random() % 2;
	pr_rotatepow2square( disp_pr, x, y, pow2, cw );
	if ( delay != 0 )
	    usleep( delay * 1000 );
	}
    }

Pixrect*
my_pr_open( fb )
    char* fb;
    {
    int fd;

    /* Test with open first, to avoid stupid error messages from pr_open(). */
    if ( ( fd = open( fb, O_RDWR ) ) == -1 )
	return (Pixrect*) 0;
    close( fd );
    return pr_open( fb );
    }

static Pixrect* temp1 = (Pixrect*) 0;
static Pixrect* temp2 = (Pixrect*) 0;
static Pixrect* mask = (Pixrect*) 0;

void
pr_rotatepow2square( pr, x, y, pow2, cw )
    Pixrect* pr;
    int x, y, pow2, cw;
    {
    int s, h, q, ts, th, tq;

    if ( pow2 < 2 )
	return;
    s = 1 << pow2;
    h = s / 2;
    q = h / 2;

    /* Make sure that temps and mask are big enough and the right depth. */
    if ( temp1 != (Pixrect*) 0 )
	if ( temp1->pr_size.x < s || temp1->pr_size.y < s ||
	     temp1->pr_depth != pr->pr_depth )
	    {
	    pr_destroy( temp1 );
	    temp1 = (Pixrect*) 0;
	    pr_destroy( temp2 );
	    temp2 = (Pixrect*) 0;
	    pr_destroy( mask );
	    mask = (Pixrect*) 0;
	    }
    if ( temp1 == (Pixrect*) 0 )
	{
	temp1 = mem_create( s, s, pr->pr_depth );
	temp2 = mem_create( s, s, pr->pr_depth );
	mask = mem_create( s, s, 1 );
	}

    /* Initialize mask to the upper left quadrant. */
    pr_rop( mask, 0, 0, s, s, PIX_CLR, (Pixrect*) 0, 0, 0 );
    pr_rop( mask, 0, 0, h, h, PIX_SET, (Pixrect*) 0, 0, 0 );

    for ( ts = s, th = ts / 2, tq = th / 2;
	  pow2 > 0;
	  --pow2, ts = th, th = tq, tq /= 2 )
	{
	if ( cw )
	    pr_rop( temp1,  0,  0, s-th, s-th, PIX_SRC,    pr,    x, y+th );
	else
	    pr_rop( temp1,  0,  0, s-th, s-th, PIX_SRC,    pr, x+th,    y );
	pr_rop( temp1,  0,  0,    s,    s, PIX_AND,  mask,    0,    0 );

	if ( cw )
	    pr_rop( temp2, th,  0, s-th, s-th, PIX_SRC,    pr,    x,    y );
	else
	    pr_rop( temp2, th,  0, s-th, s-th, PIX_SRC,    pr, x+th, y+th );
	pr_rop( temp2, th,  0, s-th, s-th, PIX_AND,  mask,    0,    0 );
	pr_rop( temp1, th,  0, s-th, s-th,  PIX_OR, temp2,   th,    0 );

	if ( cw )
	    pr_rop( temp2, th, th, s-th, s-th, PIX_SRC,    pr, x+th,    y );
	else
	    pr_rop( temp2, th, th, s-th, s-th, PIX_SRC,    pr,    x, y+th );
	pr_rop( temp2, th, th, s-th, s-th, PIX_AND,  mask,    0,    0 );
	pr_rop( temp1, th, th, s-th, s-th,  PIX_OR, temp2,   th,   th );

	if ( cw )
	    pr_rop( temp2,  0, th, s-th, s-th, PIX_SRC,    pr, x+th, y+th );
	else
	    pr_rop( temp2,  0, th, s-th, s-th, PIX_SRC,    pr,    x,    y );
	pr_rop( temp2,  0, th, s-th, s-th, PIX_AND,  mask,    0,    0 );
	pr_rop( temp1,  0, th, s-th, s-th,  PIX_OR, temp2,    0,   th );

	/* And copy back to the screen. */
	pr_rop(    pr,  x,  y,    s,    s, PIX_SRC, temp1,    0,    0 );

	/* Refine mask. */
	pr_rop( mask,  0,  0, s-tq, s-tq, PIX_AND, mask, tq, tq );
	pr_rop( mask,  0, th,    s, s-th,  PIX_OR, mask,  0,  0 );
	pr_rop( mask, th,  0, s-th,    s,  PIX_OR, mask,  0,  0 );
	}
    }