home *** CD-ROM | disk | FTP | other *** search
- /* File BitMap.c Copyright (C) 1996 by John R. Montbriand. All Rights Reserved. */
-
- /* File BitMap.c
-
- Copyright (C) 1996 by John Montbriand. All Rights Reserved.
-
- Distribute freely in areas where the laws of copyright apply.
-
- Use at your own risk.
-
- Do not distribute modified copies.
-
- These various BitMap libraries are for free!
-
- See the accompanying file BitMap.txt for details.
-
- */
-
- #include "BitMap.h"
- #include <Memory.h>
- #include <ToolUtils.h>
- #include <OSUtils.h>
- #include <FixMath.h>
- #include <Math.h>
-
- #pragma segment BitMaps
-
-
- BitMap* NewBitMap(short width, short height) {
- short rowBytes;
- long bytes;
- BitMap *bits;
- rowBytes = ((width + 15) >> 4) << 1;
- bytes = sizeof(BitMap) + ((long) rowBytes) * ((long) height);
- if ((bits = (BitMap*) NewPtrClear(bytes)) == NULL) return NULL;
- bits->baseAddr = ((char*) bits) + sizeof(BitMap);
- bits->rowBytes = rowBytes;
- bits->bounds.left = bits->bounds.top = 0;
- bits->bounds.right = width;
- bits->bounds.bottom = height;
- return bits;
- }
-
- void KillBitMap(BitMap* bits) {
- DisposePtr((Ptr) bits);
- }
-
-
- /* SafeHeightNewBitMap is an internal routine for creating bitmaps
- appropriately sized for the left and right rotation routines. */
- static BitMap* SafeHeightNewBitMap(short width, short height) {
- short safeheight;
- BitMap* bits;
- safeheight = (((height + 15) >> 4) << 1) * 8;
- if ((bits = NewBitMap(width, safeheight)) != NULL) bits->bounds.bottom = height;
- return bits;
- }
-
- /* ShiftLeftWords is an internal routine called to shift bits to the
- left after horizontal flip operations and right rotations. Sometimes
- this is required as bitmaps are rotated using the memory
- storage conventions rather than the coordinate mapping conventions. */
- static void ShiftLeftWords(void* p, long words, short nshifts) {
- long i, j;
- unsigned short* wp;
- for (j=0;j<nshifts;j++) for (wp = (unsigned short*) p, i=0; i<words; i++) {
- wp[i] <<= 1;
- if (i+1 < words && (wp[i+1] & 0x8000) != 0) wp[i] |= 1;
- }
- }
-
- BitMap* RotateRight(BitMap* bits) {
- short sWidth, sHeight;
- BitMap *result, *src, *dst;
- unsigned char *sp, bit, *dp, *dbyt, sbyt, mask;
- register long x, y, i;
- sWidth = bits->bounds.right - bits->bounds.left;
- sHeight = bits->bounds.bottom - bits->bounds.top;
- if ((result = SafeHeightNewBitMap(sHeight, sWidth)) != NULL) {
- src = bits;
- dst = result;
- sp = (unsigned char*) src->baseAddr;
- bit = 0x01;
- dp = ((unsigned char*) dst->baseAddr) + dst->rowBytes - 1;
- for (y = 0; y < src->bounds.bottom; y++) { // for every row...
- for (dbyt = dp, x=0; x < src->rowBytes; x++) // scan the row...
- for(sbyt = *sp++, mask = 0x80, i=0;i<8;i++, mask >>= 1, dbyt += dst->rowBytes)
- if (sbyt & mask) *dbyt |= bit;
- if (bit == 0x80) { bit = 0x01; dp--; } else bit <<= 1;
- }
- x = dst->rowBytes*8 - dst->bounds.right;
- dp = (unsigned char*) dst->baseAddr;
- for (i = 0; i < dst->bounds.bottom; i++, dp += dst->rowBytes)
- ShiftLeftWords(dp, dst->rowBytes/2, x);
- }
- return result;
- }
-
- BitMap* RotateLeft(BitMap* bits) {
- short sWidth, sHeight;
- BitMap *result, *src, *dst;
- register long x, y, i;
- unsigned char *sp, bit, *dp, *dbyt, sbyt, mask;
- sWidth = bits->bounds.right - bits->bounds.left;
- sHeight = bits->bounds.bottom - bits->bounds.top;
- if ((result = SafeHeightNewBitMap(sHeight, sWidth)) != NULL) {
- src = bits;
- dst = result;
- sp = (unsigned char*) src->baseAddr;
- bit = 0x80;
- dp = ((unsigned char*) dst->baseAddr) + (dst->rowBytes * (dst->bounds.bottom-1));
- for (y = 0; y < src->bounds.bottom; y++) { // for every row...
- for (dbyt = dp, x=0; x < src->rowBytes; x++) // scan the row...
- for(sbyt = *sp++, mask = 0x80, i=0;i<8;i++, mask >>= 1, dbyt -= dst->rowBytes)
- if (sbyt & mask) *dbyt |= bit;
- if (bit == 0x01) { bit = 0x80; dp++; } else bit >>= 1;
- }
- }
- return result;
- }
-
- BitMap* FlipVertical(BitMap* bits) {
- BitMap *result, *src, *dst;
- register long v;
- unsigned char *sp, *dp;
- if ((result = DuplicateBitMap(bits)) != NULL) {
- src = bits;
- dst = result;
- sp = (unsigned char*) src->baseAddr;
- dp = ((unsigned char*) dst->baseAddr) + (dst->bounds.bottom-1)*(long)dst->rowBytes;
- for (v = 0; v < src->bounds.bottom; v++) {
- BlockMoveData(sp, dp, dst->rowBytes);
- sp += src->rowBytes;
- dp -= dst->rowBytes;
- }
- return result;
- }
- return NULL;
- }
-
- BitMap* FlipHorizontal(BitMap* bits) {
- BitMap *result, *src, *dst;
- register long h, v, i;
- unsigned char *sp, *dp, *s, *d, mask, bit, sByte;
- result = bits;
- if ((result = DuplicateBitMap(bits)) != NULL) {
- src = bits;
- dst = result;
- sp = (unsigned char*) src->baseAddr;
- dp = (unsigned char*) dst->baseAddr;
- for (v = 0; v < src->bounds.bottom; v++) {
- for (s = sp + src->rowBytes, d = dp, h = 0; h < src->rowBytes; h++, d++)
- for (mask=0x01, bit=0x80, sByte = *--s, *d=0,i=0; i<8; i++, mask<<=1, bit>>=1)
- if (sByte & mask) *d |= bit;
- sp += src->rowBytes;
- ShiftLeftWords(dp, dst->rowBytes / 2, dst->rowBytes*8 - dst->bounds.right);
- dp += dst->rowBytes;
- }
- return result;
- }
- return NULL;
- }
-
-
- /* There are two implementations of the RotateBitMap routine: one for
- the 68000, and another for the PowerPC. Fixed point math is faster
- than floating point on the 68000, however floating point is faster
- than fixed point on the PowerPC. The method we use maps pixels that
- are set in the source bitmap to their appropriate position in the
- destination performing the necessary calculations only if the pixel is
- equal to 1. I have heard that better image quality can be found by
- mapping from the destination to the source, but I was more interested
- in speed when I made this. */
-
- #if defined(powerc) || defined(__powerc)
-
- short myround(float x) {
- float low, high;
- low = floor(x);
- high = ceil(x);
- if (fabs(low - x) < fabs(high - x))
- return (short) low;
- else return (short) high;
- }
-
- BitMap* RotateBitMap(BitMap* bits, short cx, short cy, float angle) {
- BitMap *result, *src, *dst;
- register long h, v, i;
- unsigned char *sp, *dp, *s, *d, bit;
- float x, y, rad, crad, srad, zx, zy, ccx, ccy;
- short xx, yy;
- Point pt;
- if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
- src = bits;
- rad = -(0.017453 * angle);
- crad = cos(rad);
- srad = sin(rad);
- ccx = (float) cx;
- ccy = (float) cy;
- sp = (unsigned char*) src->baseAddr;
- for (v = 0; v < src->bounds.bottom; v++, sp += src->rowBytes)
- for (s = sp, h = 0; h < src->rowBytes; h++, s++)
- for (bit=0x80, i=0; i<8; i++, bit>>=1)
- if (((*s) & bit) != 0) {
- zx = ((float) (h*8+i)) - ccx;
- zy =((float) v) - ccy;
- xx = myround(zx*crad + zy*srad + ccx);
- if (xx >= src->bounds.left && xx < src->bounds.right) {
- yy = myround(zy*crad - zx*srad + ccy);
- if (yy >= src->bounds.top && yy < src->bounds.bottom)
- BitMapSet(result, xx, yy);
- }
- }
- return result;
- }
- return NULL;
- }
-
- #else
-
- BitMap* RotateBitMap(BitMap* bits, short cx, short cy, float angle) {
- BitMap *result, *src, *dst;
- register long h, v, i;
- unsigned char *sp, *dp, *s, *d, bit;
- Fixed x, y, rad, crad, srad, zx, zy, ccx, ccy;
- short xx, yy;
- Point pt;
- if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
- src = bits;
- rad = FixMul(0x00000478, -X2Fix(angle));
- crad = FracCos(rad);
- srad = FracSin(rad);
- ccx = FixRatio(cx, 1);
- ccy = FixRatio(cy, 1);
- sp = (unsigned char*) src->baseAddr;
- for (v = 0; v < src->bounds.bottom; v++, sp += src->rowBytes)
- for (s = sp, h = 0; h < src->rowBytes; h++, s++)
- for (bit=0x80, i=0; i<8; i++, bit>>=1)
- if (((*s) & bit) != 0) {
- zx = FixRatio((h*8+i), 1) - ccx;
- zy =FixRatio (v, 1) - ccy;
- xx = FixRound(FracMul(zx, crad) + FracMul(zy, srad) + ccx);
- if (xx >= src->bounds.left && xx < src->bounds.right) {
- yy = FixRound(FracMul(zy, crad) - FracMul(zx, srad) + ccy);
- if (yy >= src->bounds.top && yy < src->bounds.bottom)
- BitMapSet(result, xx, yy);
- }
- }
- return result;
- }
- return NULL;
- }
-
- #endif
-
- BitMap* iRotateBitMap(BitMap* bits, short cx, short cy, short angle) {
- return RotateBitMap(bits, cx, cy, (float) angle);
- }
-
-
- BitMap* DuplicateBitMap(BitMap* bits) {
- BitMap *result;
- long bytes;
- result = bits;
- result = NewBitMap(bits->bounds.right, bits->bounds.bottom);
- if (result != NULL) {
- BlockMoveData(bits, result,
- sizeof(BitMap) + ((long) result->rowBytes) * ((long) result->bounds.bottom));
- result->baseAddr = ((char*) result) + sizeof(BitMap);
- return result;
- } else return NULL;
- }
-
- BitMap* PaintBucketBitMap(BitMap* bits, short h, short v) {
- BitMap *result, *src, *dst;
- if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
- src = bits;
- dst = result;
- SeedFill(src->baseAddr, dst->baseAddr, src->rowBytes, dst->rowBytes,
- dst->bounds.bottom, dst->rowBytes/2, h, v);
- }
- return result;
- }
-
- BitMap* LassoBitMap(BitMap* bits) {
- BitMap *result, *src, *dst;
- if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
- src = bits;
- dst = result;
- CalcMask(src->baseAddr, dst->baseAddr, src->rowBytes, dst->rowBytes,
- dst->bounds.bottom, dst->rowBytes/2);
- }
- return result;
- }
-
- BitMap* TraceBitMap(BitMap* bits) {
- BitMap *the_edges;
- if ((the_edges = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
- BitMapPort* bmp;
- WithBitMap(the_edges, bmp) {
- PlotBitMap(bits, -1, -1, srcOr);
- PlotBitMap(bits, 1, -1, srcOr);
- PlotBitMap(bits, -1, 1, srcOr);
- PlotBitMap(bits, 1, 1, srcOr);
- PlotBitMap(bits, 0, 0, srcBic);
- }
- }
- return the_edges;
- }
-
- /* EqualBitMaps takes into account that the rowbytes in the differing images may be
- different and that bits off to the right of the image may contain garbage. */
- Boolean EqualBitMaps(BitMap* a, BitMap* b) {
- unsigned char *aptr, *bptr, *arover, *brover;
- long x, y, bytecount, extrabits, mask;
-
- /* something not there? */
- if (a == NULL || b == NULL) return false;
-
- /* different boundary rectangles? */
- if (!EqualRect(&a->bounds, &b->bounds)) return false;
-
- /* different image content? */
- aptr = (unsigned char*) a->baseAddr;
- bptr = (unsigned char*) b->baseAddr;
- bytecount = a->bounds.right/8;
- extrabits = a->bounds.right % 8;
- mask = -(1<< (8 - extrabits));
- for (y=0; y< a->bounds.bottom; y++) {
- arover = aptr;
- brover = bptr;
- for (x=0; x<bytecount; x++)
- if (*arover++ != *brover++)
- return false;
- if (extrabits != 0) {
- if (((*arover)&mask) != ((*brover)&mask))
- return false;
- }
- aptr += a->rowBytes;
- bptr += b->rowBytes;
- }
- return true;
- }
-
- /* note, we set up the portrect, the port's size, the clip region, and the
- visible region all so they refer to the drawable area inside of the
- bitmap pointer. */
- BitMapPort* NewBMP(BitMap* bits) {
- BitMapPort* bmp;
- Rect r;
- if ((bmp = (BitMapPort*) NewPtr(sizeof(BitMapPort))) != NULL) {
- r = bits->bounds;
- GetPort(&bmp->gpsave);
- OpenPort(&bmp->gp);
- SetPortBits(bmp->bits = bits);
- PortSize(r.right, r.bottom);
- RectRgn(bmp->gp.visRgn, &r);
- RectRgn(bmp->gp.clipRgn, &r);
- }
- return bmp;
- }
-
- void DisposeBMP(BitMapPort* bmp) {
- if (bmp != NULL) {
- SetPort(bmp->gpsave);
- ClosePort(&bmp->gp);
- DisposePtr((Ptr) bmp);
- }
- }
-
- BitMap* PICTToBitMap(PicHandle pic) {
- BitMap *bits;
- BitMapPort* bmp;
- Rect r;
- r = (*pic)->picFrame;
- OffsetRect(&r, -r.left, -r.top);
- if ((bits = NewBitMap(r.right, r.bottom)) != NULL) {
- WithBitMap(bits, bmp)
- DrawPicture(pic, &r);
- }
- return bits;
- }
-
-
- void PlotBitMap(BitMap* bits, short h, short v, short mode) {
- GrafPtr port;
- Rect src, dst;
- dst = src = bits->bounds;
- OffsetRect(&dst, h, v);
- GetPort(&port);
- CopyBits(bits, &port->portBits, &src, &dst, mode, NULL);
- }
-
- PicHandle BitMapToPICT(BitMap* bits) {
- PicHandle pic;
- GrafPtr saved;
- GrafPort port;
- Rect r;
- r = bits->bounds;
- GetPort(&saved);
- OpenPort(&port);
- ClipRect(&r);
- pic = OpenPicture(&r);
- PlotBitMap(bits, 0, 0, srcCopy);
- ClosePicture();
- SetPort(saved);
- ClosePort(&port);
- return pic;
- }
-
- BitMap* BitMapAND(BitMap* a, BitMap* b) {
- BitMap *aa, *bb, *result = NULL;
- register unsigned char *ap, *bp, *rp;
- long i, n;
- aa = a;
- bb = b;
- if (EqualRect(&aa->bounds, &bb->bounds))
- if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
- rp = (unsigned char *) (result)->baseAddr;
- ap = (unsigned char *) aa->baseAddr;
- bp = (unsigned char *) bb->baseAddr;
- n = (aa->rowBytes * aa->bounds.bottom);
- for (i=0; i<n; i++) *rp++ = ((*ap++) & (*bp++));
- }
- return result;
- }
-
- BitMap* BitMapOR(BitMap* a, BitMap* b) {
- BitMap *aa, *bb, *result = NULL;
- register unsigned char *ap, *bp, *rp;
- long i, n;
- aa = a;
- bb = b;
- if (EqualRect(&aa->bounds, &bb->bounds))
- if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
- rp = (unsigned char *) (result)->baseAddr;
- ap = (unsigned char *) aa->baseAddr;
- bp = (unsigned char *) bb->baseAddr;
- n = (aa->rowBytes * aa->bounds.bottom);
- for (i=0; i<n; i++) *rp++ = ((*ap++) | (*bp++));
- }
- return result;
- }
-
- BitMap* BitMapXOR(BitMap* a, BitMap* b) {
- BitMap *aa, *bb, *result = NULL;
- register unsigned char *ap, *bp, *rp;
- long i, n;
- aa = a;
- bb = b;
- if (EqualRect(&aa->bounds, &bb->bounds))
- if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
- rp = (unsigned char *) (result)->baseAddr;
- ap = (unsigned char *) aa->baseAddr;
- bp = (unsigned char *) bb->baseAddr;
- n = (aa->rowBytes * aa->bounds.bottom);
- for (i=0; i<n; i++) *rp++ = ((*ap++) ^ (*bp++));
- }
- return result;
- }
-
- BitMap* BitMapNOT(BitMap* a) {
- BitMap *aa, *bb, *result = NULL;
- register unsigned char *ap, *bp, *rp;
- long i, n;
- aa = a;
- if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
- rp = (unsigned char *) (result)->baseAddr;
- ap = (unsigned char *) aa->baseAddr;
- n = (aa->rowBytes * aa->bounds.bottom);
- for (i=0; i<n; i++) *rp++ = ~(*ap++);
- }
- return result;
- }
-
- Boolean BitMapTest(BitMap* bits, short h, short v) {
- unsigned char* cp;
- cp = (unsigned char*) (bits);
- return BitTst(cp + (sizeof(BitMap) + (bits->rowBytes * v)), h);
- }
-
- void BitMapSet(BitMap* bits, short h, short v) {
- unsigned char* cp;
- cp = (unsigned char*) (bits);
- BitSet(cp + (sizeof(BitMap) + (bits->rowBytes * v)), h);
- }
-
- void BitMapClear(BitMap* bits, short h, short v) {
- unsigned char* cp;
- cp = (unsigned char*) (bits);
- BitClr(cp + (sizeof(BitMap) + (bits->rowBytes * v)), h);
- }
-
- Boolean BitMapToggle(BitMap* bits, short h, short v) {
- unsigned char* cp;
- cp = (unsigned char*) (bits);
- cp += (sizeof(BitMap) + (bits->rowBytes * v));
- if (BitTst(cp, h)) {
- BitClr(cp, h);
- return false;
- } else {
- BitSet(cp, h);
- return true;
- }
- }
-
- BitMap* StringToBitMap(short font, short size, short face, StringPtr s) {
- GrafPort port;
- GrafPtr saved;
- FontInfo info;
- BitMap *result = NULL;
- GetPort(&saved);
- OpenPort(&port);
- TextFont(font);
- TextSize(size);
- TextFace(face);
- GetFontInfo(&info);
- if ((result = NewBitMap(StringWidth(s), info.ascent + info.descent)) != NULL) {
- SetPortBits(result);
- PortSize(result->bounds.right, result->bounds.bottom);
- RectRgn(port.visRgn, &result->bounds);
- RectRgn(port.clipRgn, &result->bounds);
- MoveTo(0, info.ascent);
- DrawString(s);
- }
- SetPort(saved);
- ClosePort(&port);
- return result;
- }
-
- /* end File BitMap.c */
-
-