/* * Copyright (C) 1997-2005, R3vis Corporation. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 * USA, or visit http://www.gnu.org/copyleft/lgpl.html. * * Original Contributor: * Wes Bethel, R3vis Corporation, Marin County, California * Additional Contributor(s): * * The OpenRM project is located at http://openrm.sourceforge.net/. */ /* * $Id: rmbitmap.c,v 1.5 2005/02/19 16:22:50 wes Exp $ * Version: $Name: OpenRM-1-6-0-RC5 $ * $Revision: 1.5 $ * $Log: rmbitmap.c,v $ * Revision 1.5 2005/02/19 16:22:50 wes * Distro sync and consolidation. * * Revision 1.4 2005/01/23 17:00:22 wes * Copyright updated to 2005. * * Revision 1.3 2004/01/16 16:43:24 wes * Updated copyright line for 2004. * * Revision 1.2 2003/02/02 02:07:15 wes * Updated copyright to 2003. * * Revision 1.1.1.1 2003/01/28 02:15:23 wes * Manual rebuild of rm150 repository. * * Revision 1.5 2003/01/16 22:21:17 wes * Updated all source files to reflect new organization of header files: * all header files formerly located in include/rmaux, include/rmi, include/rmv * are now located in include/rm. * * Revision 1.4 2002/04/30 19:28:55 wes * Updated copyright dates. * * Revision 1.3 2001/03/31 17:12:38 wes * v1.4.0-alpha-2 checkin. * * Revision 1.2 2000/04/20 16:29:47 wes * Documentation additions/enhancements, some code rearragement. * * Revision 1.1.1.1 2000/02/28 21:29:40 wes * OpenRM 1.2 Checkin * * Revision 1.1.1.1 2000/02/28 17:18:47 wes * Initial entry - pre-RM120 release, source base for OpenRM 1.2. * */ #include #include "rmprivat.h" /* * ---------------------------------------------------- * @Name rmBitmapNew @pstart RMbitmap * rmBitmapNew (int width, int height) @pend @astart int width, height - integer values that specify the width and height of the bitmap (input). @aend @dstart Creates a new RMbitmap object. The size of the bitmap will be (width,height), and remains fixed for the lifetime of the object. The bitmap data is initialized by this routine to all zeros. Returns a handle to the new object upon success, or NULL upon failure. @dend * ---------------------------------------------------- */ RMbitmap * rmBitmapNew (int width, int height) { int bitmap_width_in_bytes; RMbitmap *b; /* given width in pixels, compute width in bytes (windows wants an even multiple of four bytes */ bitmap_width_in_bytes = (width / 8); /* if not an exact even multiple of 8 bits, incr byte count */ if ((width & 0x7) != 0) bitmap_width_in_bytes++; #ifdef RM_WIN /* * MS OpenGL is buggy - it assumes that all pixel data is aligned * to 4-byte boundaries, regardless of the values specified by * glPixelStorei(). this code takes care of that for you by rounding * the internal number of bytes per scanline up to the nearest * 4-byte boundary. */ { while ((bitmap_width_in_bytes & 0x3) != 0) bitmap_width_in_bytes++; } #endif b = (RMbitmap *)malloc(sizeof(RMbitmap)); memset(b, 0, sizeof(RMbitmap)); private_rmBitmapSetWidth(b, width); private_rmBitmapSetHeight(b, height); private_rmBitmapSetBytesPerScanline(b, bitmap_width_in_bytes); private_rmBitmapSetPBSize(b, bitmap_width_in_bytes * height); b->pixeldata = (unsigned char *)malloc(sizeof(unsigned char) * private_rmBitmapGetPBSize(b)); if (RM_ASSERT(private_rmBitmapGetPixelData(b), "rmBitmapNew() error: unable to allocate memory for the bitmap data.") == RM_WHACKED) { free((void *)b); return(NULL); } memset(b->pixeldata, 0, private_rmBitmapGetPBSize(b)); return(b); } /* * ---------------------------------------------------- * @Name rmBitmapCopy @pstart RMenum rmBitmapCopy (RMbitmap *dst, const RMbitmap *src) @pend @astart RMbitmap *dst - the destination RMbitmap object (output). const RMbitmap *src - the source RMbitmap object (input). @aend @dstart Copies the bitmap data from one RMbitmap object to another. Both RMbitmaps must be fully configured (created with rmBitmapNew), and must be the same size. Size information may be obtained with rmBitmapGetSize, but is set at the time the RMbitmap is created with rmBitmapNew. Returns RM_CHILL to the caller upon success, or RM_WHACKED upon failure. @dend * ---------------------------------------------------- */ RMenum rmBitmapCopy (RMbitmap *dst, const RMbitmap *src) { /* the only check is for whether or not the sizes are the same */ if (RM_ASSERT(src, "rmBitmapCopy() source bitmap is NULL") == RM_WHACKED) return(RM_WHACKED); if (RM_ASSERT(dst, "rmBitmapCopy() dest bitmap is NULL") == RM_WHACKED) return(RM_WHACKED); if ((private_rmBitmapGetWidth(src) != private_rmBitmapGetWidth(dst)) || (private_rmBitmapGetHeight(src) != private_rmBitmapGetHeight(dst))) { rmError("rmBitmapCopy() error: the sizes of the source and dest. bitmaps are not the same: no copy will occur. "); return(RM_WHACKED); } else { memcpy((void *)(private_rmBitmapGetPixelData(dst)), (void *)(private_rmBitmapGetPixelData(src)), private_rmBitmapGetPBSize(src)); } return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmBitmapDup @pstart RMbitmap *rmBitmapDup (const RMbitmap *src) @pend @astart const RMbitmap *src - a handle to a source RMbitmap object. @aend @dstart Creates a new RMbitmap object that is an exact replica of an existing one. Upon return from this routine, the new RMbitmap object is an exact duplicate, except that both source and destination RMbitmap objects have their own buffers. A change to one will not affect the other. Returns a handle to a new RMbitmap object upon success, or NULL upon failure. @dend * ---------------------------------------------------- */ RMbitmap * rmBitmapDup (const RMbitmap *src) { int w, h, bytes_per_scanline; RMbitmap *dst; if (RM_ASSERT(src, "rmBitmapDup() null source bitmap pointer") == RM_WHACKED) return(NULL); rmBitmapGetSize(src, &w, &h, &bytes_per_scanline); dst = rmBitmapNew(w, h); if (dst == NULL) return(NULL); rmBitmapCopy(dst, src); return(dst); } /* * ---------------------------------------------------- * @Name rmBitmapDelete @pstart void rmBitmapDelete (RMbitmap *toDelete) @pend @astart RMbitmap *toDelete - a handle to the RMbitmap object to be deleted. @aend @dstart Releases resources associated with an RMbitmap object. This routine is the opposite of rmBitmapNew(). @dend * ---------------------------------------------------- */ void rmBitmapDelete (RMbitmap *b) { RM_ASSERT(b, "rmBitmapDelete() null input bitmap \n"); if (b->pixeldata != NULL) free((void *)b->pixeldata); free((void *)b); } /* * ---------------------------------------------------- * @Name rmBitmapSetPixelData @pstart RMenum rmBitmapSetPixelData (RMbitmap *toModify, const void *pixeldata) @pend @astart RMbitmap *toModify - a handle to the RMbitmap object who's bitmap data will be modified by this call (input). const void *pixeldata - a handle to the raw bitmap data. @aend @dstart Copies bitmap data from the caller's memory into the RMbitmap's internal buffer. Unlike other RM objects, RMbitmap objects do not allows for shared data management of pixel data. By convention, bitmap data must be scanline padded to the nearest 4-byte boundary. This is an artifact of the Win32 OpenGL implementation. Returns RM_CHILL to the caller if the operation was successful, otherwise RM_WHACKED is returned. @dend * ---------------------------------------------------- */ RMenum rmBitmapSetPixelData (RMbitmap *b, const void *pixeldata) { if ((RM_ASSERT(b, "rmBitmapSetPixelData() error: the input bitmap is NULL.") == RM_WHACKED) || (RM_ASSERT(pixeldata, "rmBitmapSetPixelData() error: the input bitmap data is NULL.") == RM_WHACKED)) return(RM_WHACKED); memcpy((void *)(private_rmBitmapGetPixelData(b)), pixeldata, private_rmBitmapGetPBSize(b)); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmBitmapGetPixelData @pstart void * rmBitmapGetPixelData (const RMbitmap *toQuery) @pend @astart const RMbitmap *toQuery - a handle to an RMbitmap object (input). @aend @dstart Returns to the caller a handle to the raw bitmap data from the bitmap object upon success, otherwise NULL is returned. The data can be interpreted as raw byte data, where the high order bit of the first byte corresponds to the upper-left most bit in the image. Use rmBitmapSetPixelData() to set this data (in toto), or rmBitmapSetBit to turn on a single bit. Use rmBitmapGetSize() to query the dimensions of the bitmap. @dend * ---------------------------------------------------- */ void * rmBitmapGetPixelData (const RMbitmap *toQuery) { if (RM_ASSERT(toQuery, "rmBitmapGetPixelData() error: the input bitmap is NULL.") == RM_WHACKED) return(NULL); return(private_rmBitmapGetPixelData(toQuery)); } /* * ---------------------------------------------------- * @Name rmBitmapGetSize @pstart RMenum rmBitmapGetSize (const RMbitmap *toQuery, int *width_return, int *height_return, int *bytes_width_return) @pend @astart const RMbitmap *toQuery - a handle to the RMbitmap object to query. int *width_return, *height_return - pointers to caller-supplied int's that will be set to contain the width and height dimensions of the the bitmap. int *bytes_width_return - pointer to caller-supplied int. This will be set to reflect the real number of bytes per scanline in the RMbitmap objects pixel buffer. This value is computed by RM to honor local pixel storage restrictions. @aend @dstart Returns to the caller the width and height of the bitmap of an RMbitmap object. Since the number of bytes per scanline of the bitmap buffer may not necessarily be equal to width/8, the "real" number of bytes per scanline is returned to the caller by this routine. Returns RM_CHILL upon success, or RM_WHACKED upon failure. @dend * ---------------------------------------------------- */ RMenum rmBitmapGetSize (const RMbitmap *b, int *width_return, int *height_return, int *bytes_width_return) { if (RM_ASSERT(b, "rmBitmapGetSize() null input RMbitmap pointer. \n") == RM_WHACKED) return(RM_WHACKED); if (width_return != NULL) *width_return = private_rmBitmapGetWidth(b); if (height_return != NULL) *height_return = private_rmBitmapGetHeight(b); if (bytes_width_return != NULL) *bytes_width_return = private_rmBitmapGetBytesPerScanline(b); return(RM_CHILL); } /* * ---------------------------------------------------- * @Name rmBitmapSetBit @pstart RMenum rmBitmapSetBit (RMbitmap *toModify, int columnIndex, int rowIndex) @pend @astart RMbitmap *toModify - a handle to the RMbitmap object to modify. int columnIndex, rowIndex - integer values specifying the coordinate of the bit to set in terms of index location. @aend @dstart This routine is used to set, or turn on, a single bit in an RMbitmap object. There is no corresponding routine to turn a bit off. To turn a bit off, you have to write the entire bitmap buffer with rmBitmapSetPixelData. Returns RM_CHILL upon success, or RM_WHACKED upon failure. @dend * ---------------------------------------------------- */ RMenum rmBitmapSetBit (RMbitmap *b, int col, int row) { int w, h, bytes, indx; unsigned char *p; unsigned int mask; /* check for within bounds */ if (RM_ASSERT(b, "rmBitmapSetBit() null input RMbitmap pointer.") == RM_WHACKED) return(RM_WHACKED); if (RM_ASSERT(private_rmBitmapGetPixelData(b), "rmBitmapSetBit() - some type of internal error has occured - there is no bitmap image data allocated for this RMbitmap object.") == RM_WHACKED) return(RM_WHACKED); rmBitmapGetSize(b, &w, &h, &bytes); if ((col < 0) || (col > (w - 1)) || (row < 0) || (row > (h - 1))) { char buf[128]; sprintf(buf, "rmBitmapSetBit() error - input row or column parameters out of range. valid range is (%d,%d), you gave me (%d,%d) \n", w, h, col, row); rmError(buf); return(RM_WHACKED); } indx = row * private_rmBitmapGetBytesPerScanline(b) + (col / 8); p = b->pixeldata + indx; mask = (1 << (7 - (col % 8))); *p |= mask; #if 0 #define RM_BITMAP_SET_BIT(a, j, i) (a[j][i / 8] |= (1 << (7-(i % 8)))); RM_BITMAP_SET_BIT(b->bitmap_mask, row, col); #endif return(RM_CHILL); } /* EOF */