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