1 /*
2  * Copyright (C) 1997-2005, R3vis Corporation.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17  * USA, or visit http://www.gnu.org/copyleft/lgpl.html.
18  *
19  * Original Contributor:
20  *   Wes Bethel, R3vis Corporation, Marin County, California
21  * Additional Contributor(s):
22  *
23  * The OpenRM project is located at http://openrm.sourceforge.net/.
24  */
25 /*
26  * $Id: rmbitmap.c,v 1.5 2005/02/19 16:22:50 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.5 $
29  * $Log: rmbitmap.c,v $
30  * Revision 1.5  2005/02/19 16:22:50  wes
31  * Distro sync and consolidation.
32  *
33  * Revision 1.4  2005/01/23 17:00:22  wes
34  * Copyright updated to 2005.
35  *
36  * Revision 1.3  2004/01/16 16:43:24  wes
37  * Updated copyright line for 2004.
38  *
39  * Revision 1.2  2003/02/02 02:07:15  wes
40  * Updated copyright to 2003.
41  *
42  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
43  * Manual rebuild of rm150 repository.
44  *
45  * Revision 1.5  2003/01/16 22:21:17  wes
46  * Updated all source files to reflect new organization of header files:
47  * all header files formerly located in include/rmaux, include/rmi, include/rmv
48  * are now located in include/rm.
49  *
50  * Revision 1.4  2002/04/30 19:28:55  wes
51  * Updated copyright dates.
52  *
53  * Revision 1.3  2001/03/31 17:12:38  wes
54  * v1.4.0-alpha-2 checkin.
55  *
56  * Revision 1.2  2000/04/20 16:29:47  wes
57  * Documentation additions/enhancements, some code rearragement.
58  *
59  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
60  * OpenRM 1.2 Checkin
61  *
62  * Revision 1.1.1.1  2000/02/28 17:18:47  wes
63  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
64  *
65  */
66 
67 #include <rm/rm.h>
68 #include "rmprivat.h"
69 
70 /*
71  * ----------------------------------------------------
72  * @Name rmBitmapNew
73  @pstart
74  RMbitmap * rmBitmapNew (int width,
75 	                 int height)
76  @pend
77 
78  @astart
79  int width, height - integer values that specify the width and height
80     of the bitmap (input).
81  @aend
82 
83  @dstart
84 
85  Creates a new RMbitmap object. The size of the bitmap will be
86  (width,height), and remains fixed for the lifetime of the object. The
87  bitmap data is initialized by this routine to all zeros.
88 
89  Returns a handle to the new object upon success, or NULL upon
90  failure.
91 
92  @dend
93  * ----------------------------------------------------
94  */
95 RMbitmap *
rmBitmapNew(int width,int height)96 rmBitmapNew (int width,
97 	     int height)
98 {
99     int       bitmap_width_in_bytes;
100     RMbitmap *b;
101 
102     /* given width in pixels, compute width in bytes (windows wants an even multiple of four bytes */
103     bitmap_width_in_bytes = (width / 8);
104 
105     /* if not an exact even multiple of 8 bits, incr byte count */
106     if ((width & 0x7) != 0)
107 	bitmap_width_in_bytes++;
108 
109 #ifdef RM_WIN
110     /*
111      * MS OpenGL is buggy - it assumes that all pixel data is aligned
112      * to 4-byte boundaries, regardless of the values specified by
113      * glPixelStorei(). this code takes care of that for you by rounding
114      * the internal number of bytes per scanline up to the nearest
115      * 4-byte boundary.
116      */
117     {
118         while ((bitmap_width_in_bytes & 0x3) != 0)
119 	    bitmap_width_in_bytes++;
120     }
121 #endif
122 
123     b = (RMbitmap *)malloc(sizeof(RMbitmap));
124     memset(b, 0, sizeof(RMbitmap));
125 
126     private_rmBitmapSetWidth(b, width);
127     private_rmBitmapSetHeight(b, height);
128     private_rmBitmapSetBytesPerScanline(b, bitmap_width_in_bytes);
129     private_rmBitmapSetPBSize(b, bitmap_width_in_bytes * height);
130 
131     b->pixeldata = (unsigned char *)malloc(sizeof(unsigned char) * private_rmBitmapGetPBSize(b));
132     if (RM_ASSERT(private_rmBitmapGetPixelData(b), "rmBitmapNew() error: unable to allocate memory for the bitmap data.") == RM_WHACKED)
133     {
134 	free((void *)b);
135 	return(NULL);
136     }
137     memset(b->pixeldata, 0, private_rmBitmapGetPBSize(b));
138 
139     return(b);
140 }
141 
142 
143 /*
144  * ----------------------------------------------------
145  * @Name rmBitmapCopy
146  @pstart
147  RMenum rmBitmapCopy (RMbitmap *dst,
148 	              const RMbitmap *src)
149  @pend
150 
151  @astart
152  RMbitmap *dst - the destination RMbitmap object (output).
153 
154  const RMbitmap *src - the source RMbitmap object (input).
155  @aend
156 
157  @dstart
158 
159  Copies the bitmap data from one RMbitmap object to another. Both
160  RMbitmaps must be fully configured (created with rmBitmapNew), and
161  must be the same size. Size information may be obtained with
162  rmBitmapGetSize, but is set at the time the RMbitmap is created with
163  rmBitmapNew.
164 
165  Returns RM_CHILL to the caller upon success, or RM_WHACKED upon
166  failure.
167 
168  @dend
169  * ----------------------------------------------------
170  */
171 RMenum
rmBitmapCopy(RMbitmap * dst,const RMbitmap * src)172 rmBitmapCopy (RMbitmap *dst,
173 	      const RMbitmap *src)
174 {
175     /* the only check is for whether or not the sizes are the same */
176     if (RM_ASSERT(src, "rmBitmapCopy() source bitmap is NULL") == RM_WHACKED)
177 	return(RM_WHACKED);
178     if (RM_ASSERT(dst, "rmBitmapCopy() dest bitmap is NULL") == RM_WHACKED)
179 	return(RM_WHACKED);
180 
181     if ((private_rmBitmapGetWidth(src) != private_rmBitmapGetWidth(dst)) || (private_rmBitmapGetHeight(src) != private_rmBitmapGetHeight(dst)))
182     {
183         rmError("rmBitmapCopy() error: the sizes of the source and dest. bitmaps are not the same: no copy will occur. ");
184 	return(RM_WHACKED);
185     }
186     else
187     {
188 	memcpy((void *)(private_rmBitmapGetPixelData(dst)), (void *)(private_rmBitmapGetPixelData(src)), private_rmBitmapGetPBSize(src));
189     }
190     return(RM_CHILL);
191 }
192 
193 
194 /*
195  * ----------------------------------------------------
196  * @Name rmBitmapDup
197  @pstart
198  RMbitmap *rmBitmapDup (const RMbitmap *src)
199  @pend
200 
201  @astart
202  const RMbitmap *src - a handle to a source RMbitmap object.
203  @aend
204 
205  @dstart
206 
207  Creates a new RMbitmap object that is an exact replica of an existing
208  one. Upon return from this routine, the new RMbitmap object is an
209  exact duplicate, except that both source and destination RMbitmap
210  objects have their own buffers. A change to one will not affect the
211  other.
212 
213  Returns a handle to a new RMbitmap object upon success, or NULL upon
214  failure.
215 
216  @dend
217  * ----------------------------------------------------
218  */
219 RMbitmap *
rmBitmapDup(const RMbitmap * src)220 rmBitmapDup (const RMbitmap *src)
221 {
222     int       w, h, bytes_per_scanline;
223     RMbitmap *dst;
224 
225     if (RM_ASSERT(src, "rmBitmapDup() null source bitmap pointer") == RM_WHACKED)
226 	return(NULL);
227 
228     rmBitmapGetSize(src, &w, &h, &bytes_per_scanline);
229 
230     dst = rmBitmapNew(w, h);
231     if (dst == NULL)
232 	return(NULL);
233 
234     rmBitmapCopy(dst, src);
235 
236     return(dst);
237 }
238 
239 
240 /*
241  * ----------------------------------------------------
242  * @Name rmBitmapDelete
243  @pstart
244  void rmBitmapDelete (RMbitmap *toDelete)
245  @pend
246 
247  @astart
248  RMbitmap *toDelete - a handle to the RMbitmap object to be deleted.
249  @aend
250 
251  @dstart
252 
253  Releases resources associated with an RMbitmap object. This routine
254  is the opposite of rmBitmapNew().
255 
256  @dend
257  * ----------------------------------------------------
258  */
259 void
rmBitmapDelete(RMbitmap * b)260 rmBitmapDelete (RMbitmap *b)
261 {
262     RM_ASSERT(b, "rmBitmapDelete() null input bitmap \n");
263 
264     if (b->pixeldata != NULL)
265 	free((void *)b->pixeldata);
266     free((void *)b);
267 }
268 
269 
270 /*
271  * ----------------------------------------------------
272  * @Name rmBitmapSetPixelData
273  @pstart
274  RMenum rmBitmapSetPixelData (RMbitmap *toModify,
275 		              const void *pixeldata)
276 
277  @pend
278 
279  @astart
280  RMbitmap *toModify - a handle to the RMbitmap object who's bitmap
281      data will be modified by this call (input).
282 
283  const void *pixeldata - a handle to the raw bitmap data.
284  @aend
285 
286  @dstart
287 
288  Copies bitmap data from the caller's memory into the RMbitmap's
289  internal buffer. Unlike other RM objects, RMbitmap objects do not
290  allows for shared data management of pixel data.
291 
292  By convention, bitmap data must be scanline padded to the nearest
293  4-byte boundary. This is an artifact of the Win32 OpenGL
294  implementation.
295 
296  Returns RM_CHILL to the caller if the operation was successful,
297  otherwise RM_WHACKED is returned.
298 
299  @dend
300  * ----------------------------------------------------
301  */
302 RMenum
rmBitmapSetPixelData(RMbitmap * b,const void * pixeldata)303 rmBitmapSetPixelData (RMbitmap *b,
304 		      const void *pixeldata)
305 {
306 
307     if ((RM_ASSERT(b, "rmBitmapSetPixelData() error: the input bitmap is NULL.") == RM_WHACKED) ||
308 	(RM_ASSERT(pixeldata, "rmBitmapSetPixelData() error: the input bitmap data is NULL.") == RM_WHACKED))
309 	return(RM_WHACKED);
310 
311     memcpy((void *)(private_rmBitmapGetPixelData(b)), pixeldata, private_rmBitmapGetPBSize(b));
312 
313     return(RM_CHILL);
314 }
315 
316 
317 /*
318  * ----------------------------------------------------
319  * @Name rmBitmapGetPixelData
320  @pstart
321  void * rmBitmapGetPixelData (const RMbitmap *toQuery)
322  @pend
323 
324  @astart
325  const RMbitmap *toQuery - a handle to an RMbitmap object (input).
326  @aend
327 
328  @dstart
329 
330  Returns to the caller a handle to the raw bitmap data from the bitmap
331  object upon success, otherwise NULL is returned. The data can be
332  interpreted as raw byte data, where the high order bit of the first
333  byte corresponds to the upper-left most bit in the image.
334 
335  Use rmBitmapSetPixelData() to set this data (in toto), or
336  rmBitmapSetBit to turn on a single bit. Use rmBitmapGetSize() to
337  query the dimensions of the bitmap.
338 
339  @dend
340  * ----------------------------------------------------
341  */
342 void *
rmBitmapGetPixelData(const RMbitmap * toQuery)343 rmBitmapGetPixelData (const RMbitmap *toQuery)
344 {
345     if (RM_ASSERT(toQuery, "rmBitmapGetPixelData() error: the input bitmap is NULL.") == RM_WHACKED)
346 	return(NULL);
347 
348     return(private_rmBitmapGetPixelData(toQuery));
349 }
350 
351 
352 /*
353  * ----------------------------------------------------
354  * @Name rmBitmapGetSize
355  @pstart
356  RMenum rmBitmapGetSize (const RMbitmap *toQuery,
357 		         int *width_return,
358 			 int *height_return,
359 			 int *bytes_width_return)
360 
361  @pend
362 
363  @astart
364  const RMbitmap *toQuery - a handle to the RMbitmap object to query.
365 
366  int *width_return, *height_return - pointers to caller-supplied int's
367     that will be set to contain the width and height dimensions of the
368     the bitmap.
369 
370  int *bytes_width_return - pointer to caller-supplied int. This will
371     be set to reflect the real number of bytes per scanline in the
372     RMbitmap objects pixel buffer. This value is computed by RM to
373     honor local pixel storage restrictions.
374  @aend
375 
376  @dstart
377 
378  Returns to the caller the width and height of the bitmap of an
379  RMbitmap object. Since the number of bytes per scanline of the bitmap
380  buffer may not necessarily be equal to width/8, the "real" number of
381  bytes per scanline is returned to the caller by this routine.
382 
383  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
384 
385  @dend
386  * ----------------------------------------------------
387  */
388 RMenum
rmBitmapGetSize(const RMbitmap * b,int * width_return,int * height_return,int * bytes_width_return)389 rmBitmapGetSize (const RMbitmap *b,
390 		 int *width_return,
391 		 int *height_return,
392 		 int *bytes_width_return)
393 {
394     if (RM_ASSERT(b, "rmBitmapGetSize() null input RMbitmap pointer. \n") == RM_WHACKED)
395 	return(RM_WHACKED);
396 
397     if (width_return != NULL)
398 	*width_return = private_rmBitmapGetWidth(b);
399 
400     if (height_return != NULL)
401 	*height_return = private_rmBitmapGetHeight(b);
402 
403     if (bytes_width_return != NULL)
404 	*bytes_width_return = private_rmBitmapGetBytesPerScanline(b);
405 
406     return(RM_CHILL);
407 }
408 
409 
410 /*
411  * ----------------------------------------------------
412  * @Name rmBitmapSetBit
413  @pstart
414  RMenum rmBitmapSetBit (RMbitmap *toModify,
415 	                int columnIndex,
416 		        int rowIndex)
417  @pend
418 
419  @astart
420  RMbitmap *toModify - a handle to the RMbitmap object to modify.
421 
422  int columnIndex, rowIndex - integer values specifying the coordinate
423      of the bit to set in terms of index location.
424  @aend
425 
426  @dstart
427 
428  This routine is used to set, or turn on, a single bit in an RMbitmap
429  object. There is no corresponding routine to turn a bit off. To turn
430  a bit off, you have to write the entire bitmap buffer with
431  rmBitmapSetPixelData.
432 
433  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
434 
435  @dend
436  * ----------------------------------------------------
437  */
438 RMenum
rmBitmapSetBit(RMbitmap * b,int col,int row)439 rmBitmapSetBit (RMbitmap *b,
440 	        int col,
441 	        int row)
442 {
443     int            w, h, bytes, indx;
444     unsigned char *p;
445     unsigned int   mask;
446 
447     /* check for within bounds */
448     if (RM_ASSERT(b, "rmBitmapSetBit() null input RMbitmap pointer.") == RM_WHACKED)
449 	return(RM_WHACKED);
450     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)
451 	return(RM_WHACKED);
452 
453     rmBitmapGetSize(b, &w, &h, &bytes);
454     if ((col < 0) || (col > (w - 1)) || (row < 0) || (row > (h - 1)))
455     {
456 	char buf[128];
457 
458 	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);
459 	rmError(buf);
460 	return(RM_WHACKED);
461     }
462 
463     indx = row * private_rmBitmapGetBytesPerScanline(b) +
464 	(col / 8);
465     p = b->pixeldata + indx;
466     mask = (1 << (7 - (col % 8)));
467     *p |= mask;
468 
469 #if 0
470 #define RM_BITMAP_SET_BIT(a, j, i)	(a[j][i / 8] |=  (1 << (7-(i % 8))));
471     RM_BITMAP_SET_BIT(b->bitmap_mask, row, col);
472 #endif
473 
474     return(RM_CHILL);
475 }
476 /* EOF */
477