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: rmimage.c,v 1.8 2005/06/26 18:50:25 wes Exp $
27 * Version: $Name: OpenRM-1-6-0-2-RC2 $
28 * $Revision: 1.8 $
29 * $Log: rmimage.c,v $
30 * Revision 1.8 2005/06/26 18:50:25 wes
31 * Documentation updates.
32 *
33 * Revision 1.7 2005/05/15 15:22:11 wes
34 * Update inline docs for rmImageMirror.
35 *
36 * Revision 1.6 2005/05/06 16:36:53 wes
37 * Update docs to reflect that 1D images are supported. Only a couple
38 * of minor code tweaks were needed.
39 *
40 * Revision 1.5 2005/02/19 16:32:31 wes
41 * Distro sync and consolidation.
42 * Add code to set "bytes per component" field of an RMimage.
43 *
44 * Revision 1.4 2005/01/23 17:04:03 wes
45 * Copyright update to 2005.
46 *
47 * Revision 1.3 2004/01/16 16:45:12 wes
48 * Updated copyright line for 2004.
49 *
50 * Revision 1.2 2003/02/02 02:07:15 wes
51 * Updated copyright to 2003.
52 *
53 * Revision 1.1.1.1 2003/01/28 02:15:23 wes
54 * Manual rebuild of rm150 repository.
55 *
56 * Revision 1.10 2003/01/16 22:21:17 wes
57 * Updated all source files to reflect new organization of header files:
58 * all header files formerly located in include/rmaux, include/rmi, include/rmv
59 * are now located in include/rm.
60 *
61 * Revision 1.9 2002/12/04 14:50:33 wes
62 * Cleanup SGI compiles.
63 *
64 * Revision 1.8 2002/04/30 19:28:17 wes
65 * rmImageSetVismap() now takes NULL for the vismap parameter. This change
66 * allows applications to "clear" any vis colormap associated with an
67 * RMimage, and is also used to fix a memory leak bug associated with
68 * rmImageDelete.
69 *
70 * Revision 1.7 2001/10/15 01:38:53 wes
71 * Bugs in 4-byte alignment code for W32 rmimages fixed.
72 *
73 * Revision 1.5 2001/05/28 23:29:29 wes
74 * Fixed nbytesPerScanline computation bug in rmImageNew.
75 *
76 * Revision 1.4 2001/03/31 17:12:38 wes
77 * v1.4.0-alpha-2 checkin.
78 *
79 * Revision 1.3 2000/12/03 22:35:38 wes
80 * Mods for thread safety.
81 *
82 * Revision 1.2 2000/04/20 16:29:47 wes
83 * Documentation additions/enhancements, some code rearragement.
84 *
85 * Revision 1.1.1.1 2000/02/28 21:29:40 wes
86 * OpenRM 1.2 Checkin
87 *
88 * Revision 1.1.1.1 2000/02/28 17:18:48 wes
89 * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
90 *
91 */
92
93
94 #include <rm/rm.h>
95 #include "rmprivat.h"
96
97 /*
98 * ----------------------------------------------------
99 * @Name rmImageNew
100 @pstart
101 RMimage * rmImageNew (int ndims,
102 int width,
103 int height,
104 int depth,
105 RMenum formatEnum,
106 RMenum typeEnum,
107 RMenum copyFlag)
108 @pend
109
110 @astart
111 int ndims - integer value specifying the number of dimensions in the
112 new image. May be a value of 2 for regular images, 3 for 3D
113 volumes, or 1 for 1D (texture) images (input).
114
115 int width, height - integer values specifying the width and height of
116 the new image (input).
117
118 int depth - integer value specifying the size of the 3rd image
119 dimension for 3D images. When "ndims" is 1 or 2, this parameter is
120 ignored (input).
121
122 RMenum formatEnum - an RMenum value specifying the pixel format for
123 the new image. Use one of the following values (input):
124
125 RM_IMAGE_ALPHA - alpha-only pixels, one component per pixel.
126 RM_IMAGE_LUMINANCE - luminance only pixels, one component per pixel.
127 RM_IMAGE_LUMINANCE_ALPHA - each pixel is considered to be a luminance-alpha
128 pair, two components per pixel. Pixel data organized as LALALA...
129 RM_IMAGE_RGB - each pixel is considered to be an RGB 3-tuple, organized
130 as RGBRGB...
131 RM_IMAGE_RGBA - each pixel is considered to be an RGBA 4-tuple, organized
132 as RGBARGBA...
133 RM_IMAGE_DEPTH - identifies the pixel data as depth buffer pixels. Each
134 pixel consists of a single component.
135
136 RMenum typeEnum - an RMenum value specifying the type of each pixel
137 component. Use one of the following enumerators (input):
138 RM_UNSIGNED_BYTE, RM_FLOAT, RM_SHORT, or RM_UNSIGNED_SHORT.
139
140 RMenum copyFlag - an RMenum value specifying whether or not RM will
141 make a copy of the pixel data. Use one of RM_COPY_DATA or
142 RM_DONT_COPY_DATA (input).
143 @aend
144
145 @dstart
146
147 Creates a new RMimage object according to the caller's
148 specifications, and returns an RMimage handle to the caller upon
149 success, or NULL upon failure.
150
151 Once created, the size and pixel format/type of an RMimage object may
152 not be changed by the application. However, the pixel storage mode
153 may change over the lifetime of the RMimage object.
154
155 Win32 peculiarities: due to bugs in the Win32 OpenGL, all pixel data
156 in an RMimage object is padded to 4-byte boundaries on a per-scanline
157 basis. This will become significant when transferring pixel data to
158 the RMimage object. Use the routine rmImageGetBytesPerScanline to
159 obtain the computed number of bytes per scanline (that value is
160 computed by RM by rmImageNew and remains constant for the lifetime of
161 the RMimage object).
162
163 When copyFlag is set to RM_COPY_DATA, rmImageNew creates a pixel
164 buffer internal to the RMimage object. When set to RM_DONT_COPY_DATA,
165 no pixel buffer is created. However, the bytes-per-scanline value is
166 computed and assigned to the new RMimage object.
167
168 Important! Applications must honor the bytes-per-scanline attribute
169 of the RMimage object, otherwise the application's notion of pixel
170 data organization will not jibe with RM's notion, leading potentially
171 to garbage images on screen (at best) to possible seg faults (at
172 worst).
173
174 @dend
175 * ----------------------------------------------------
176 */
177 RMimage *
rmImageNew(int ndims,int width,int height,int depth,RMenum format_enum,RMenum type_enum,RMenum copy_flag)178 rmImageNew (int ndims,
179 int width,
180 int height,
181 int depth,
182 RMenum format_enum, /* RM_IMAGE_RGB, etc. */
183 RMenum type_enum, /* RM_UNSIGNED_BYTE or RM_FLOAT */
184 RMenum copy_flag)
185 {
186 int elements;
187 int nbytes_per_component, nbytes_per_scanline, nbytes_for_pixeldata;
188 RMimage *t;
189 int save;
190
191 t = private_rmImageNew();
192
193 save = t->compListIndx;
194 memset(t, 0, sizeof(RMimage));
195 t->compListIndx = save;
196
197 if (t == NULL)
198 {
199 rmError("rmImageNew() error: unable to allocate a new RMimage object.");
200 return(NULL);
201 }
202
203 private_rmImageSetNDims(t, ndims);
204 private_rmImageSetType(t, type_enum);
205 private_rmImageSetWidth(t, width);
206 private_rmImageSetHeight(t, height);
207
208 if ((ndims == 2) || (ndims == 1))
209 depth = 1;
210
211 private_rmImageSetDepth(t, depth);
212
213 if ((elements = private_rmImageGetNumElements(format_enum)) == RM_WHACKED)
214 {
215 rmError("rmImage3DNew() error: unsupported image format requested.");
216 return(NULL);
217 }
218
219 private_rmImageSetElements(t, elements);
220 nbytes_per_component = private_rmImageNumComponentBytes(type_enum);
221 private_rmImageSetBytesPerComponent(t, nbytes_per_component);
222 nbytes_per_scanline = elements * width * nbytes_per_component;
223
224 #ifdef RM_WIN
225 {
226 int extraBytes;
227 extraBytes = nbytes_per_scanline % 4;
228 if (extraBytes != 0)
229 {
230 extraBytes = 4 - extraBytes;
231 nbytes_per_scanline += extraBytes;
232 #if 0
233 while (extraBytes > 0)
234 {
235 nbytes_per_scanline++;
236 extraBytes--;
237 }
238 #endif
239 }
240 }
241 #endif
242
243 nbytes_for_pixeldata = nbytes_per_scanline * height * depth;
244 private_rmImageSetBytesPerScanline(t, nbytes_per_scanline);
245 t->pbsize = nbytes_for_pixeldata;
246
247 private_rmImageSetFormat(t, format_enum);
248 rmImageSetPixelZoom(t, 1.0F, 1.0F); /* default */
249
250 rmImageSetScale(t, 1.0F);
251 rmImageSetBias(t, 0.0F);
252
253 if (copy_flag == RM_COPY_DATA)
254 {
255 t->pixeldata = (unsigned char *)malloc(sizeof(unsigned char) * nbytes_for_pixeldata);
256 if (t == NULL)
257 {
258 char buf[128];
259
260 sprintf(buf,"rmImage3DNew() error: unable to allocated %d bytes of voxel data.", nbytes_for_pixeldata);
261 rmError(buf);
262 return(NULL);
263 }
264 memset(t->pixeldata, 0, sizeof(unsigned char) * nbytes_for_pixeldata);
265 private_rmImageSetCopyFlag(t, RM_COPY_DATA);
266 }
267 else
268 {
269 private_rmImageSetCopyFlag(t, RM_DONT_COPY_DATA);
270 t->pixeldata = NULL;
271 }
272 #if 0
273 /* 10/5/2000 - all RMimage display list code removed during SBIR work */
274 private_rmImageSetDisplayList(t, -1);
275 #endif
276
277 return(t);
278 }
279
280
281 /*
282 * ----------------------------------------------------
283 * @Name rmImageDup
284 @pstart
285 RMimage * rmImageDup (const RMimage *toDuplicate)
286 @pend
287
288 @astart
289 const RMimage *toDuplicate - a handle to an RMimage object (input).
290 @aend
291
292 @dstart
293
294 Use this routine to create a duplicate of an RMimage object. Returns
295 a handle to the new object upon success, or NULL upon failure.
296
297 A new RMimage object is created that is an exact duplicate of the
298 input object. When the pixel data is under the purview of
299 RM_COPY_DATA, a copy of the pixel data from the source RMimage is
300 created and placed into the new RMimage object's pixel buffer.
301 Otherwise (RM_DONT_COPY_DATA), the handle to the application pixel
302 data is copied to the new RMimage object, along with the handle to
303 the application callback used to free pixel data.
304
305 The RMvisMap object, if present in source, is duplicated and copied
306 to the new object. RMimage object's do not share data management of
307 RMvisMap objects with the application.
308
309 All size and other configuration information from the source is used
310 to create the new object. Pixel zoom, bias and scale are also copied
311 from the source to the new object.
312
313 @dend
314 * ----------------------------------------------------
315 */
316 RMimage *
rmImageDup(const RMimage * src)317 rmImageDup (const RMimage *src)
318 {
319 unsigned char *s, *d;
320 float xz, yz;
321 RMenum copy_flag;
322 RMimage *dst;
323 RMvisMap *vmap = NULL;
324
325 if (RM_ASSERT(src, "rmImageDup() error: input RMimage is NULL.") == RM_WHACKED)
326 return(NULL);
327
328 copy_flag = private_rmImageGetCopyFlag(src);
329
330 /* make a new image which has all the config information present in the old image */
331 dst = rmImageNew(private_rmImageGetNDims(src), private_rmImageGetWidth(src), private_rmImageGetHeight(src), private_rmImageGetDepth(src),
332 private_rmImageGetFormat(src), private_rmImageGetType(src), private_rmImageGetCopyFlag(src));
333
334 if (dst == NULL)
335 return(NULL);
336
337 rmImageGetPixelZoom(src, &xz, &yz);
338 rmImageSetPixelZoom(dst, xz, yz);
339
340 rmImageGetScale(src, &xz);
341 rmImageSetScale(dst, xz);
342
343 rmImageGetBias(src, &xz);
344 rmImageSetBias(dst, xz);
345
346 s = rmImageGetPixelData(src);
347 d = rmImageGetPixelData(dst);
348
349 if (private_rmImageGetCopyFlag(src) == RM_COPY_DATA)
350 memcpy((void *)d, (void *)s, sizeof(unsigned char)*src->pbsize);
351 else
352 {
353 dst->pixeldata = s;
354 dst->appfreefunc = src->appfreefunc;
355 }
356
357 if (rmImageGetVismap(src, &vmap) == RM_CHILL)
358 {
359 rmImageSetVismap(dst, vmap);
360 rmVismapDelete(vmap);
361 }
362 return(dst);
363 }
364
365
366 /*
367 * ----------------------------------------------------
368 * @Name rmImageDelete
369 @pstart
370 RMenum rmImageDelete (RMimage *toDelete)
371
372 @pend
373
374 @astart
375 RMimage *toDelete - a handle to an RMimage object.
376 @aend
377
378 @dstart
379
380 Releases resources associated with an RMimage object (the opposite of
381 rmImageNew). Returns RM_CHILL upon success, or RM_WHACKED upon
382 failure.
383
384 @dend
385 * ----------------------------------------------------
386 */
387 RMenum
rmImageDelete(RMimage * r)388 rmImageDelete (RMimage *r)
389 {
390 if (RM_ASSERT(r, "rmImageDelete() error: input RMimage is NULL.") == RM_WHACKED)
391 return(RM_WHACKED);
392
393 return(private_rmImageDelete(r));
394 #if 0
395 /* this code goes away with the new component manager */
396 if (private_rmImageGetCopyFlag(r) == RM_COPY_DATA)
397 free((void *)(r->pixeldata));
398 else
399 {
400 void (*appfunc)(void *);
401
402 appfunc = r->appfreefunc;
403 if (appfunc != NULL)
404 (*appfunc)((void *)(r->pixeldata));
405 }
406 free(r);
407 return(RM_CHILL);
408 #endif
409 }
410
411
412 /*
413 * ----------------------------------------------------
414 * @Name rmImageSetPixelData
415 @pstart
416 RMenum rmImageSetPixelData (RMimage *toModify,
417 void *pixelData,
418 RMenum copyEnum,
419 void (*appFreeFunc)(void *))
420 @pend
421
422 @astart
423 RMimage *toModify - a handle to an RMimage object (modified).
424
425 void *pixelData - a handle to the raw pixel data supplied by the
426 caller. The contents of this buffer will become the pixel data
427 for the RMimage object (input).
428
429 RMenum copyEnum - an RMenum value specifying whether or not RM should
430 make a copy of this data. Must be either RM_COPY_DATA or
431 RM_DONT_COPY_DATA.
432
433 void (*appFreeFunc)(void *) - a handle to an application callback
434 used to free the pixel data when the RMimage object is
435 deleted. When copyEnum is RM_COPY_DATA, this parameter is ignored.
436 @aend
437
438 @dstart
439
440 Assigns raw pixel data to an RMimage object. Returns RM_CHILL upon
441 success, or RM_WHACKED upon failure.
442
443 The expected size of the pixel buffer is:
444
445 (bytes_per_scanline)*height*depth * num_pixel_components
446
447 The type of each pixel component may be obtained with rmImageGetType.
448
449 The RMimage object's internal pixel buffer created with rmImageNew
450 using RM_COPY_DATA should be considered READ ONLY. It is possible for
451 applications to write directly into this pixel buffer, but this
452 practice is highly discouraged. The reason is that RM will attempt to
453 cache the RMimage object pixel buffer into OpenGL display lists
454 wherever possible, and is capable of detecting changes to the pixel
455 buffer (implying the need to refresh the display list data) only when
456 the RM interface is used to update the pixel data
457 (rmImageSetPixelData).
458
459 In order to avoid multiple copies of pixel data in memory, use
460 RM_DONT_COPY_DATA when creating the RMimage object. In that case, the
461 application manages the pixel data. A call to rmImageSetPixelData
462 will result in a pointer copy (not a block pixel copy), and will
463 correctly cause any dependent display lists to be refreshed.
464
465 When rmImageSetPixelData is called using RM_COPY_DATA, RM makes a
466 copy of the pixel buffer and stores it in the RMimage object. When
467 called with RM_DONT_COPY_DATA, RM copies only the pointer to the
468 pixel data.
469
470 When using RM_DONT_COPY_DATA, applications must provide a callback
471 that will be invoked when the RMimage object is deleted with
472 rmImageDelete. The application callback will be passed a single
473 parameter, a handle to the raw pixel data cast to a void *.
474
475 @dend
476 * ----------------------------------------------------
477 */
478 RMenum
rmImageSetPixelData(RMimage * ri,void * pixeldata,RMenum copy_enum,void (* appfreefunc)(void *))479 rmImageSetPixelData (RMimage *ri,
480 void *pixeldata,
481 RMenum copy_enum,
482 void (*appfreefunc)(void *))
483 {
484 /*
485 * validity checking:
486 * 1. input image & pixeldata must not be null
487 * 2. assert copy_enum == RM_DONT_COPY_DATA && appfreefunc != NULL
488 */
489 RMenum old_copy_flag;
490
491 if (RM_ASSERT(ri, "rmImageSetPixelData() error: NULL input RMimage.") == RM_WHACKED)
492 return(RM_WHACKED);
493
494 if ((copy_enum == RM_DONT_COPY_DATA) && (appfreefunc == NULL))
495 {
496 rmError("rmImageSetPixelData() error: when using RM_DONT_COPY_DATA, you must supply a function which RM will call to free the image buffer. RM will not call this function until you delete the RMnode that contains the image (texture, sprite primitive, etc.)");
497 return(RM_WHACKED);
498 }
499 /*
500 * we need to check for the case in which the image was created with
501 * RM_COPY_DATA, but now data is being set with RM_DONT_COPY_DATA. this
502 * may be a potential problem..
503 */
504 old_copy_flag = private_rmImageGetCopyFlag(ri);
505 if (old_copy_flag != copy_enum) /* a problem */
506 {
507 if (old_copy_flag == RM_COPY_DATA) /* & copy_flag == RM_DONT_COPY */
508 free((void *)(rmImageGetPixelData(ri))); /* free it */
509
510 else /* old is DONT_COPY, new is COPY, malloc buffer */
511 {
512 unsigned char *c;
513 void (*appfunc)(void *);
514
515 /* call the app free func, if defined, to free up the old buffer */
516 appfunc = ri->appfreefunc;
517
518 if (appfunc != NULL)
519 (*appfunc)((void *)(rmImageGetPixelData(ri)));
520
521 c = (unsigned char *)malloc(sizeof(unsigned char) * ri->pbsize);
522 ri->pixeldata = c;
523 }
524 }
525 /* else, no problem */
526 private_rmImageSetCopyFlag(ri, copy_enum);
527
528 if (copy_enum == RM_COPY_DATA)
529 {
530 memcpy((void *)(ri->pixeldata), pixeldata, ri->pbsize);
531 }
532 else
533 {
534 ri->pixeldata = (unsigned char *)pixeldata;
535 ri->appfreefunc = appfreefunc;
536 }
537 #if 0
538 /* 10/5/200 - should be replaced with context cache stuff */
539 private_rmImageSetDirtyFlag(ri, RM_TRUE); /* what's this for ? */
540 #endif
541
542 return(RM_CHILL);
543 }
544
545
546 /*
547 * ----------------------------------------------------
548 * @Name rmImageGetPixelData
549 @pstart
550 void * rmImageGetPixelData (const RMimage *toQuery)
551 @pend
552
553 @astart
554 const RMimage *toQuery
555 @aend
556
557 @dstart
558
559 Returns to the caller a handle to the raw pixel data inside an
560 RMimage object, cast to a void * upon success. Otherwise, returns
561 NULL.
562
563 The size of the returned pixel buffer is:
564
565 (bytes_per_scanline)*height*depth * num_pixel_components
566
567 The type of each pixel component may be obtained with rmImageGetType.
568
569 The RMimage object's internal pixel buffer created with rmImageNew
570 using RM_COPY_DATA should be considered READ ONLY. It is possible for
571 applications to write directly into this pixel buffer, but this
572 practice is highly discouraged. The reason is that RM will attempt to
573 cache the RMimage object pixel buffer into OpenGL display lists
574 wherever possible, and is capable of detecting changes to the pixel
575 buffer (implying the need to refresh the display list data) only when
576 the RM interface is used to update the pixel data
577 (rmImageSetPixelData).
578
579 In order to avoid multiple copies of pixel data in memory, use
580 RM_DONT_COPY_DATA when creating the RMimage object. In that case, the
581 application manages the pixel data. A call to rmImageSetPixelData
582 will result in a pointer copy (not a block pixel copy), and will
583 correctly cause any dependent display lists to be refreshed.
584
585 @dend
586 * ----------------------------------------------------
587 */
588 void *
rmImageGetPixelData(const RMimage * ri)589 rmImageGetPixelData (const RMimage *ri)
590 {
591 if (RM_ASSERT(ri, "rmImageGetPixelData() error: input RMimage is NULL") == RM_WHACKED)
592 return(NULL);
593
594 return((void *)(ri->pixeldata));
595 }
596
597
598 /*
599 * ----------------------------------------------------
600 * @Name rmImageGetBytesPerScanline
601 @pstart
602 unsigned int rmImageGetBytesPerScanline (const RMimage *toQuery)
603 @pend
604
605 @astart
606 const RMimage *toQuery - a handle to an RMimage object (input).
607 @aend
608
609 @dstart
610
611 Returns to the caller the computed number of bytes per scanline of
612 image data. Some OpenGL implementations silently require that all
613 image data is padded to 4-byte boundaries on a per-scanline basis.
614
615 This read-only value, bytes-per-scanline, is computed by rmImageNew
616 at RMimage creation time and remains constant for the lifetime of the
617 RMimage object.
618
619 Note that there is no corresponding rmImageSetBytesPerScanline
620 routine. The bytes per scanline of an RMimage object is established
621 at the time the RMimage object is created with rmImageNew and remains
622 immutable for the lifetime of the object.
623
624 See also rmImageGetImageSize.
625
626 @dend
627 * ----------------------------------------------------
628 */
629 unsigned int
rmImageGetBytesPerScanline(const RMimage * src)630 rmImageGetBytesPerScanline (const RMimage *src)
631 {
632 if (RM_ASSERT(src, "rmImageGetBytesPerScanline() error: input RMimage pointer is NULL.") == RM_WHACKED)
633 return(0);
634
635 return(private_rmImageGetBytesPerScanline(src));
636 }
637
638
639 /*
640 * ----------------------------------------------------
641 * @Name rmImageGetCopyFlag
642 @pstart
643 RMenum rmImageGetCopyFlag (const RMimage *toQuery)
644 @pend
645
646 @astart
647 const RMimage *toQuery - a handle to an RMimage object object
648 (input).
649 @aend
650
651 @dstart
652
653 Returns to the caller an RMenum value indicating the RMimage object's
654 notion of who manages the pixel data. Either RM_COPY_DATA or
655 RM_DONT_COPY_DATA will be returned, indicating that RM manages the
656 data or the application manages the data, respectively. If the input
657 RMimage is NULL, then RM_WHACKED is returned.
658
659 There is no corresponding rmImageSetCopyFlag routine. The copy flag
660 attribute is established at the time the RMimage is created with
661 rmImageNew is called and is immutable for the lifetime of the object.
662
663 @dend
664 * ----------------------------------------------------
665 */
666 RMenum
rmImageGetCopyFlag(const RMimage * ri)667 rmImageGetCopyFlag (const RMimage *ri)
668 {
669 if (RM_ASSERT(ri, "rmImageGetCopyFlag() error: the input RMimage is NULL.") == RM_WHACKED)
670 return(RM_WHACKED);
671
672 return(private_rmImageGetCopyFlag(ri));
673 }
674
675
676 /*
677 * ----------------------------------------------------
678 * @Name rmImageGetType
679 @pstart
680 RMenum rmImageGetType (const RMimage *toQuery)
681 @pend
682
683 @astart
684 const RMimage *toQuery
685 @aend
686
687 @dstart
688
689 Returns to the caller an RMenum value indicating the RMimage pixel
690 type. Upon success, the RMenum value will be one of the RM pixel
691 types, such as RM_UNSIGNED_BYTE, RM_FLOAT, RM_SHORT, or
692 RM_UNSIGNED_SHORT. Otherwise, RM_WHACKED is returned.
693
694 There is no corresponding rmImageSetType routine. The pixel type of
695 an RMimage object is established at the time the RMimage object is
696 created with rmImageNew, and remains immutable for the lifetime of
697 the object.
698
699 @dend
700 * ----------------------------------------------------
701 */
702 RMenum
rmImageGetType(const RMimage * img)703 rmImageGetType (const RMimage *img)
704 {
705 if (RM_ASSERT(img, "rmImageGetType() error: input RMimage pointer is NULL.") == RM_WHACKED)
706 return(RM_WHACKED);
707
708 return(private_rmImageGetType(img));
709 }
710
711
712 /*
713 * ----------------------------------------------------
714 * @Name rmImageGetFormat
715 @pstart
716 RMenum rmImageGetFormat (const RMimage *toQuery)
717 @pend
718
719 @astart
720 const RMimage *toQuery
721 @aend
722
723 @dstart
724
725 Returns to the caller an RMenum value indicating the pixel format of
726 the RMimage object. Upon success, the return value will be one of the
727 RM pixel format enumerators, such as RM_IMAGE_ALPHA,
728 RM_IMAGE_LUMINANCE, RM_IMAGE_LUMINANCE_ALPHA, RM_IMAGE_RGB,
729 RM_IMAGE_RGBA or RM_IMAGE_DEPTH. Upon failure, RM_WHACKED is
730 returned to the caller.
731
732 Note that there is no corresponding rmImageSetFormat routine. The
733 pixel format of an RMimage object is established at the time the
734 RMimage object is created with rmImageNew and remains immutable for
735 the lifetime of the object.
736
737 @dend
738 * ----------------------------------------------------
739 */
740 RMenum
rmImageGetFormat(const RMimage * img)741 rmImageGetFormat (const RMimage *img)
742 {
743 if (RM_ASSERT(img, "rmImageGetFormat() error: input RMimage pointer is NULL.") == RM_WHACKED)
744 return(RM_WHACKED);
745
746 return(private_rmImageGetFormat(img));
747 }
748
749
750 /*
751 * ----------------------------------------------------
752 * @Name rmImageGetImageSize
753 @pstart
754 RMenum rmImageGetImageSize (const RMimage *toQuery,
755 int *returnNDims,
756 int *returnWidth,
757 int *returnHeight,
758 int *returnDepth,
759 int *returnElements,
760 int *returnBytesPerScanline)
761
762 @pend
763
764 @astart
765 const RMimage *toQuery - a handle to an RMimage object to query
766 (input).
767
768 int *returnNDims, *returnWidth, *returnHeight, *returnDepth,
769 *returnElements, *returnBytesPerScanline - handles to integers
770 supplied by the caller. Parameters from the RMimage object will be
771 copied into these caller-supplied memory areas. Specifying NULL
772 for one or more of these values is permissible.
773 @aend
774
775 @dstart
776
777 Use rmImageGetImageSize to obtain configuration information about an
778 RMimage object.
779
780 If not NULL, upon return, "returnNDims" will contain the number of
781 dimensions in the RMimage object, either 2 or 3.
782
783 If not NULL, upon return, "returnWidth", "returnHeight" and
784 "returnDepth" will contain the width, height and depth of the RMimage
785 object. When the dimensionality of the RMimage object is 2,
786 "returnDepth" will be set to 1.
787
788 If not NULL, upon return, "returnElements" will contain the number of
789 components per pixel. For example, if the pixel format is
790 RM_IMAGE_RGB, "returnElements" will contain 3.
791
792 If not NULL, upon return, "returnBytesPerScanline" will contain the
793 value computed by RM indicating the actual number of bytes per
794 scanline in the pixel buffer. That value is computed to honor
795 scanline padding requirements of some OpenGL implementations. This
796 read-only value is computed by rmImageNew.
797
798 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
799
800 Note that there is no corresponding rmImageSetImageSize routine. The
801 size of an RMimage object is established at the time the RMimage
802 object is created with rmImageNew and remains immutable for the
803 lifetime of the object.
804
805 @dend
806 * ----------------------------------------------------
807 */
808 RMenum
rmImageGetImageSize(const RMimage * ri,int * ret_ndims,int * ret_w,int * ret_h,int * ret_d,int * ret_e,int * bytes_per_scanline)809 rmImageGetImageSize (const RMimage *ri,
810 int *ret_ndims,
811 int *ret_w,
812 int *ret_h,
813 int *ret_d,
814 int *ret_e,
815 int *bytes_per_scanline)
816 {
817 if (RM_ASSERT(ri, "rmImageGetImageSize() error: input RMimage is NULL.") == RM_WHACKED)
818 return(RM_WHACKED);
819
820 /*
821 * we assume that the caller may or may not be interested in all the
822 * parms, therefore it's not an error for some of the parms to be NULL.
823 */
824 if (ret_ndims != NULL)
825 *ret_ndims = private_rmImageGetNDims(ri);
826
827 if (ret_w != NULL)
828 *ret_w = private_rmImageGetWidth(ri);
829
830 if (ret_h != NULL)
831 *ret_h = private_rmImageGetHeight(ri);
832
833 if (ret_d != NULL)
834 *ret_d = private_rmImageGetDepth(ri);
835
836 if (ret_e != NULL)
837 *ret_e = private_rmImageGetElements(ri);
838
839 if (bytes_per_scanline != NULL)
840 *bytes_per_scanline = private_rmImageGetBytesPerScanline(ri);
841
842 return(RM_CHILL);
843 }
844
845
846 /*
847 * ----------------------------------------------------
848 * @Name rmImageSetPixelZoom
849 @pstart
850 RMenum rmImageSetPixelZoom (RMimage *toModify,
851 float xzoom,
852 float yzoom)
853 @pend
854
855 @astart
856 RMimage *toModify - a handle to an RMimage object (modified).
857
858 float xzoom, yzoom - floating point values used to specify the x- and y-axis
859 pixel replication, or zoom, factors (input).
860 @aend
861
862 @dstart
863
864 This routine is used to set the x- and y-axis pixel zoom parameters
865 of an RMimage object. Returns RM_CHILL upon success, or RM_WHACKED
866 upon failure.
867
868 In OpenGL, image-based data is usually drawn pixel-for-pixel, so that
869 one pixel in the source image maps to one pixel on the screen. That
870 mapping can be modified by changing the "pixel zoom". Setting the
871 x-axis pixel zoom to 2.0 will cause each input pixel to map to two
872 on-screen pixels. Setting the x-axis pixel zoom to 0.5 will cause
873 each two pixels of input to map to one pixel of output.
874
875 Pixel zoom operations apply to RM_SPRITE primitives, and background
876 image tiles. The pixel zoom values are not used when the RMimage
877 object is the source of pixel data in an RMtexture (used in texture
878 mapping).
879
880 @dend
881 * ----------------------------------------------------
882 */
883 RMenum
rmImageSetPixelZoom(RMimage * ri,float xzoom,float yzoom)884 rmImageSetPixelZoom (RMimage *ri,
885 float xzoom,
886 float yzoom)
887 {
888 if (RM_ASSERT(ri, "rmImageSetPixelZoom() error: input RMimage pointer is NULL.") == RM_WHACKED)
889 return(RM_WHACKED);
890
891 ri->xzoom = xzoom;
892 ri->yzoom = yzoom;
893
894 return(RM_CHILL);
895 }
896
897
898 /*
899 * ----------------------------------------------------
900 * @Name rmImageGetPixelZoom
901 @pstart
902 RMenum rmImageGetPixelZoom (const RMimage *toQuery,
903 float *returnXZoom,
904 float *returnYZoom)
905 @pend
906
907 @astart
908 RMimage *toQuery - a handle to an RMimage object that will be queried
909 by this routine (input).
910
911 float *returnXZoom, *returnYZoom - handles to floating point values
912 that will contain the x- and y-axis pixel zoom factors of the
913 RMimage object toQuery (modified).
914 @aend
915
916 @dstart
917
918 This routine is used to obtain the x- and y-axis pixel zoom
919 parameters of an RMimage object. The pixel zoom factors are copied
920 into caller-supplied memory. Returns RM_CHILL upon success, or
921 RM_WHACKED upon failure.
922
923 In OpenGL, image-based data is usually drawn pixel-for-pixel, so that
924 one pixel in the source image maps to one pixel on the screen. That
925 mapping can be modified by changing the "pixel zoom". Setting the
926 x-axis pixel zoom to 2.0 will cause each input pixel to map to two
927 on-screen pixels. Setting the x-axis pixel zoom to 0.5 will cause
928 each two pixels of input to map to one pixel of output.
929
930 Pixel zoom operations apply to RM_SPRITE primitives, and background
931 image tiles. The pixel zoom values are not used when the RMimage
932 object is the source of pixel data in an RMtexture (used in texture
933 mapping).
934
935 @dend
936 * ----------------------------------------------------
937 */
938 RMenum
rmImageGetPixelZoom(const RMimage * ri,float * xzoom,float * yzoom)939 rmImageGetPixelZoom (const RMimage *ri,
940 float *xzoom,
941 float *yzoom)
942 {
943 if (RM_ASSERT(ri, "rmImageGetPixelZoom() error: the input RMimage object is NULL.") == RM_WHACKED)
944 return(RM_WHACKED);
945
946 if (RM_ASSERT(xzoom, "rmImageGetPixelZoom() error: the input xzoom parameter pointer is NULL.") == RM_WHACKED)
947 return(RM_WHACKED);
948
949 if (RM_ASSERT(yzoom, "rmImageGetPixelZoom() error: the input yzoom parameter pointer is NULL.") == RM_WHACKED)
950 return(RM_WHACKED);
951
952 *xzoom = ri->xzoom;
953 *yzoom = ri->yzoom;
954
955 return(RM_CHILL);
956 }
957
958
959 /*
960 * ----------------------------------------------------
961 * @Name rmImageSetVismap
962 @pstart
963 RMenum rmImageSetVismap (RMimage *toModify,
964 const RMvisMap *vismap)
965 @pend
966
967 @astart
968 RMimage *toModify - a handle to an RMimage object (modified).
969
970 const RMvisMap *vismap - a handle to an RMvisMap object (input).
971 @aend
972
973 @dstart
974
975 Use this routine to set, or delete, the colormap associated with an
976 RMimage object. This routine will return RM_CHILL upon success, or
977 RM_WHACKED upon failure. A copy of the caller's RMvisMap object is
978 created inside this routine, and assigned to the RMimage object. If the
979 input RMvisMap parameter is NULL, any RMvisMap associated with the
980 RMimage object will be deleted. Application changes to the
981 application RMvisMap object made after this call will not affect the
982 RMimage object.
983
984 The colormap is used at pixel expansion time within the OpenGL pixel
985 pipeline. Inside OpenGL, application pixel components are first
986 converted to the range [0..1] using an algorithm that is a function
987 of the source pixel type (byte, short, etc.). Next, pixels are
988 converted from the source pixel format (luminance-alpha, RGB, etc.)
989 into RGBA. Next, each pixel component is multiplied by the "scale"
990 factor, then "bias" is added. Finally, each pixel component undergoes
991 a color->color lookup.
992
993 This routine is used to control that color->color lookup. Pixel
994 scale, bias and color lookup operations are applied to all imaging
995 operations, including both pixel draws and during transfer of pixel
996 data to texture memory. Therefore, this routine may be used to
997 perform false-coloring of scalar image data either for direct display
998 using an RM_SPRITE primitive or in the form of texture-mapping.
999
1000 Note that scale and bias parameters operate on pixel data that has
1001 been converted to the range [0..1] according to a type-specific
1002 algorithm. Source pixels that are in floating point are not
1003 converted, but are clamped to the range [0..1]. Clamping occurs late
1004 in the pixel pipeline, only after scale, bias and color lookup have
1005 been performed.
1006
1007 False coloring with the RMvisMap object is implemented by
1008 manipulating OpenGL pixel transfer modes with glPixelTransferi().
1009
1010 January 2000 - RMvisMap objects contain a transfer function. The
1011 transfer function is effectively ignored during the false coloring
1012 process inside the OpenGL pixel pipeline. Use the scale and bias
1013 attributes of the RMimage object to implement a transfer function.
1014 However, the RMvisMap object's transfer function is used inside the
1015 RMV visualization routines.
1016
1017 April 2002 - NULL is now permitted as a parameter for the vismap.
1018 this will permit applications to "clear" the vismap associated with
1019 an RMimage object.
1020
1021 @dend
1022 * ----------------------------------------------------
1023 */
1024 RMenum
rmImageSetVismap(RMimage * dst,const RMvisMap * vismap)1025 rmImageSetVismap (RMimage *dst,
1026 const RMvisMap *vismap)
1027 {
1028 if (RM_ASSERT(dst, "rmImageSetVismap() error: input RMimage object is NULL") == RM_WHACKED)
1029 return(RM_WHACKED);
1030
1031 if (dst->vismap)
1032 {
1033 rmVismapDelete(dst->vismap);
1034 dst->vismap = NULL;
1035 }
1036
1037 if (vismap != NULL)
1038 dst->vismap = rmVismapDup(vismap);
1039
1040 return(RM_CHILL);
1041 }
1042
1043
1044 /*
1045 * ----------------------------------------------------
1046 * @Name rmImageGetVismap
1047 @pstart
1048 RMenum rmImageGetVismap (const RMimage *toQuery,
1049 RMvisMap **vismapReturn)
1050 @pend
1051
1052 @astart
1053 const RMimage *toQuery - a handle to an RMimage object (input).
1054
1055 RMvisMap **vismapReturn - a handle to an RMvisMap pointer (modified).
1056 @aend
1057
1058 @dstart
1059
1060 Use this routine to set the obtain a copy of the colormap associated
1061 with an RMimage object. If a RMvisMap object exists inside the
1062 RMimage object, a copy of the RMvisMap object will be created and
1063 returned to the caller, and RM_CHILL will be returned. Otherwise,
1064 RM_WHACKED is returned.
1065
1066 The RMvisMap object returned to the caller is a duplicate of the one
1067 inside the RMimage object. Application changes to the returned
1068 RMvisMap will not affect the RMimage object. When applications are
1069 finished with the returned RMvisMap object, resources should be freed
1070 with rmVismapDelete().
1071
1072 The colormap is used at pixel expansion time within the OpenGL pixel
1073 pipeline. Inside OpenGL, application pixel components are first
1074 converted to the range [0..1] using an algorithm that is a function
1075 of the source pixel type (byte, short, etc.). Next, pixels are
1076 converted from the source pixel format (luminance-alpha, RGB, etc.)
1077 into RGBA. Next, each pixel component is multiplied by the "scale"
1078 factor, then "bias" is added. Finally, each pixel component undergoes
1079 a color->color lookup.
1080
1081 This routine is used to control that color->color lookup. Pixel
1082 scale, bias and color lookup operations are applied to all imaging
1083 operations, including both pixel draws and during transfer of pixel
1084 data to texture memory. Therefore, this routine may be used to
1085 perform false-coloring of scalar image data either for direct display
1086 using an RM_SPRITE primitive or in the form of texture-mapping.
1087
1088 Note that scale and bias parameters operate on pixel data that has
1089 been converted to the range [0..1] according to a type-specific
1090 algorithm. Source pixels that are in floating point are not
1091 converted, but are clamped to the range [0..1]. Clamping occurs late
1092 in the pixel pipeline, only after scale, bias and color lookup have
1093 been performed.
1094
1095 False coloring with the RMvisMap object is implemented by
1096 manipulating OpenGL pixel transfer modes with glPixelTransferi().
1097
1098 January 2000 - RMvisMap objects contain a transfer function. The
1099 transfer function is effectively ignored during the false coloring
1100 process inside the OpenGL pixel pipeline. Use the scale and bias
1101 attributes of the RMimage object to implement a transfer function.
1102 However, the RMvisMap object's transfer function is used inside the
1103 RMV visualization routines.
1104
1105 @dend
1106 * ----------------------------------------------------
1107 */
1108 RMenum
rmImageGetVismap(const RMimage * toQuery,RMvisMap ** vismapReturn)1109 rmImageGetVismap (const RMimage *toQuery,
1110 RMvisMap **vismapReturn)
1111 {
1112 RMenum rstat;
1113
1114 if ((RM_ASSERT(toQuery, "rmImageGetVismap() error: input RMimage object is NULL") == RM_WHACKED) ||
1115 (RM_ASSERT(vismapReturn, "rmImageGetVismap() error: input vismap is NULL.") == RM_WHACKED))
1116 return(RM_WHACKED);
1117
1118 if (toQuery->vismap)
1119 {
1120 *vismapReturn = rmVismapDup(toQuery->vismap);
1121 rstat = RM_CHILL;
1122 }
1123 else
1124 rstat = RM_WHACKED;
1125
1126 return(rstat);
1127 }
1128
1129
1130 /*
1131 * ----------------------------------------------------
1132 * @Name rmImageMirror
1133 @pstart
1134 RMenum rmImageMirror (RMimage *toMirror,
1135 RMenum mirrorAxisEnum)
1136 @pend
1137
1138 @astart
1139 RMimage *toMirror - a handle to an RMimage object (modified).
1140
1141 RMenum mirrorAxisEnum - an RMenum value specifying along which axis
1142 mirroring will occur (input).
1143 @aend
1144
1145 @dstart
1146
1147 This routine is used to perform reflection of pixel data in an
1148 RMimage object. Returns RM_CHILL upon success, or RM_WHACKED upon
1149 failure.
1150
1151 The parameter mirrorAxisEnum should be either RM_IMAGE_MIRROR_HEIGHT to
1152 flip the image along the height axis (exchanging the top and bottom), or
1153 RM_IMAGE_MIRROR_WIDTH to flip the image along the horizontal axis
1154 (exchanging left and right).
1155
1156 May 2005 - at this time, this routine will operate only on 2D images.
1157
1158 @dend
1159 * ----------------------------------------------------
1160 */
1161 RMenum
rmImageMirror(RMimage * toMirror,RMenum mirrorAxisEnum)1162 rmImageMirror (RMimage *toMirror,
1163 RMenum mirrorAxisEnum)
1164 {
1165 int ndim;
1166
1167 if (RM_ASSERT(toMirror,"rmImageMirror() error: the input RMimage object is NULL. ") == RM_WHACKED)
1168 return(RM_WHACKED);
1169
1170 rmImageGetImageSize(toMirror, &ndim, NULL, NULL, NULL, NULL, NULL);
1171 if (ndim != 2)
1172 {
1173 rmWarning(" rmImageMirror() warning: can handle only 2D images at this time. ");
1174 return(RM_WHACKED);
1175 }
1176
1177 if (mirrorAxisEnum == RM_IMAGE_MIRROR_HEIGHT)
1178 return(private_rmImage2DMirrorVertical(toMirror));
1179 else /* assume RM_IMAGE_MIRROR_WIDTH */
1180 return(private_rmImage2DMirrorHorizontal(toMirror));
1181 }
1182
1183
1184 /*
1185 * ----------------------------------------------------
1186 * @Name rmImageResize
1187 @pstart
1188 RMenum rmImageResize (const RMimage *src,
1189 RMimage *dst,
1190 RMenum hardwareEnum,
1191 RMpipe *hwPipe)
1192 @pend
1193
1194 @astart
1195 const RMimage *src - a handle to an RMimage object. Used as the
1196 source image in an image resize operation.
1197
1198 RMimage *dst - a handle to an RMimage object. The resized image will
1199 be placed into this object.
1200
1201 RMenum hardwareEnum - an RMenum value specifying whether or not to
1202 use the graphics hardware for performing the pixel resize
1203 operation. Must be either RM_HARDWARE or RM_SOFTWARE.
1204
1205 RMpipe *hwPipe - a handle to an RMpipe (input). This parameter must be
1206 non-NULL whenever the hardwareEnum parameter is set to RM_HARDWARE,
1207 and must refer to a fully initialized RMpipe. When RM_SOFTWARE
1208 image resizing is specified, this parameter is ignored, and may
1209 be set to NULL by the caller.
1210 @aend
1211
1212 @dstart
1213
1214 Use this routine to scale an image. The source image is scaled to
1215 match the dimensions specified by the destination image. Thus, the
1216 destination image must have been first created with rmImageNew,
1217 implying that it's size, pixel format and type attributes have been
1218 set. This routine does not create a new image. This routine is useful
1219 for resizing images to be an even power of 2 in size, as required for
1220 OpenGL texture mapping.
1221
1222 Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1223
1224 When hardwareEnum is set to RM_SOFTWARE, the routine gluScaleImage is
1225 used to perform the image resize operation, therefore it is a
1226 software operation. Note that gluScaleImage queries the underlying
1227 OpenGL for information about unpacklength.
1228
1229 Therefore, OpenGL must be fully initialized prior to making a call to
1230 rmImageResize using either RM_HARDWARE or RM_SOFTWARE.
1231
1232 When hardwareEnum is set to RM_HARDWARE, the underlying graphics
1233 hardware is used to perform the resizing operation. This is
1234 accomplished by writing pixels to the framebuffer using appropriate
1235 pixel zoom values, then reading the image back into the RMimage pixel
1236 data memory. In many cases, use of RM_HARDWARE will greatly
1237 accelerate image resizing operations, such as resizing a giga-scale
1238 volume down to something more manageable.
1239
1240 A valid, initialized RMpipe is required in the hwPipe parameter when
1241 using RM_HARDWARE image resize methods.
1242
1243 During RM_HARDWARE image resize operations, pixels are written into
1244 the back buffer, then read back. After the readback, a swapbuffers
1245 is performed to provide visual feedback. Since the backbuffer is used
1246 for write/read operations, the display window need not be on top in
1247 stacking order.
1248
1249 When using RM_HARDWARE, the size of the window used by the hwPipe
1250 RMpipe must be greater than or equal in size to the size of the
1251 destination image dimensions. If this condition does not hold, an
1252 error message is issued, and RM_WHACKED is returned.
1253
1254 Note about RM_HARDWARE and using RM_PIPE_MULTISTAGE_PARALLEL RMpipe
1255 processing modes: use of RM_HARDWARE in conjunction with
1256 RM_PIPE_MULTISTAGE_PARALLEL is guaranteed to work only if the image
1257 resize operation is performed before the first rmFrame() call. After
1258 the first rmFrame() call, an image resize operation that uses RM_HARDWARE
1259 on an RMpipe using the RM_PIPE_MULTISTAGE_PARALLEL processing mode
1260 may produce unexpected results, including an application crash.
1261
1262 As of the time of this writing (January 2000), only RM_HARDWARE is
1263 supported for 3D RMimage objects.
1264
1265 @dend
1266 * ----------------------------------------------------
1267 */
1268 RMenum
rmImageResize(const RMimage * src,RMimage * dst,RMenum hardwareEnum,RMpipe * hwPipe)1269 rmImageResize (const RMimage *src,
1270 RMimage *dst,
1271 RMenum hardwareEnum,
1272 RMpipe *hwPipe)
1273 {
1274 /*
1275 * hack. for now, we figure out if the images are 2D or 3D, and
1276 * call the appropriate resize routine.
1277 */
1278 int src_ndim, dst_ndim, destW, destH, destD;
1279 RMenum rstat;
1280 /*
1281 * validity checking:
1282 * 1. src & dst are not NULL.
1283 * 2. image formats for both are the same
1284 * 3. image ndim for both are the same
1285 */
1286
1287 if ((RM_ASSERT(src, "rmImageResize() error: input src RMimage is NULL.") == RM_WHACKED) ||
1288 (RM_ASSERT(dst, "rmImageResize() error: input dst RMimage is NULL.") == RM_WHACKED))
1289 return(RM_WHACKED);
1290
1291 /* we want better validity checking on hwPipe than this. */
1292 if ((hardwareEnum == RM_HARDWARE) && (hwPipe == NULL))
1293 {
1294 rmError("rmImageResize() error: a valid RMpipe object must be provided when using RM_HARDWARE as the image resize method.");
1295 return(RM_WHACKED);
1296 }
1297
1298 rmImageGetImageSize(src, &src_ndim, NULL, NULL, NULL, NULL, NULL);
1299 rmImageGetImageSize(dst, &dst_ndim, &destW, &destH, &destD, NULL, NULL);
1300
1301 if (src_ndim != dst_ndim)
1302 {
1303 rmError("rmImageResize() error: ndim for src and dst images are not equal.");
1304 return(RM_WHACKED);
1305 }
1306
1307 /* for RM_HARDWARE, check if size of dst image is less than or
1308 equal to the size of the display window. */
1309 if (hardwareEnum == RM_HARDWARE)
1310 {
1311 int winW, winH;
1312 rmPipeGetWindowSize(hwPipe, &winW, &winH);
1313 if ((winW < destW) || (winH < destH))
1314 {
1315 rmError(" rmImageResize() error: when using RM_HARDWARE image resize methods, the destination image dimensions must be less than or equal to the size of the display window.");
1316 return(RM_WHACKED);
1317 }
1318 }
1319
1320 #if 0
1321 if (private_rmImageGetFormat(src) != private_rmImageGetFormat(dst))
1322 {
1323 rmError("rmImageResize() error: src and dst images are not the same image format.");
1324 return(RM_WHACKED);
1325 }
1326 #endif
1327
1328 if (private_rmImageGetNDims(src) == 2)
1329 rstat = private_rmImage2DResize(src, dst, hardwareEnum, hwPipe);
1330 else
1331 if (private_rmImageGetNDims(src) == 3)
1332 rstat = private_rmImage3DResize(src, dst, hardwareEnum, hwPipe);
1333 else
1334 rstat = RM_WHACKED; /* bogus image dimensions */
1335
1336 return(rstat);
1337 }
1338
1339
1340 /*
1341 * ----------------------------------------------------
1342 * @Name rmImageSetScale
1343 @pstart
1344 RMenum rmImageSetScale (RMimage *toModify,
1345 float newScale)
1346
1347 @pend
1348
1349 @astart
1350 RMimage *toModify - a handle to an RMimage object to modify.
1351
1352 float newScale - a floating point value that represents the new pixel
1353 scale that will be applied to the RMimage object.
1354 @aend
1355
1356 @dstart
1357
1358 Use this routine to set the pixel scale parameter of an RMimage
1359 object. Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1360
1361 Pixel scale and bias are used in the OpenGL pixel pipeline to modify
1362 pixel values as they move from the application into the framebuffer.
1363 Inside OpenGL, application pixel components are first converted to
1364 the range [0..1] using an algorithm that is a function of the source
1365 pixel type (byte, short, etc.). Next, pixels are converted from the
1366 source pixel format (luminance-alpha, RGB, etc.) into RGBA. Next,
1367 each pixel component is multiplied by the "scale" factor, then "bias"
1368 is added.
1369
1370 The scale value is simply a linear multiplier that is applied to each
1371 pixel value.
1372
1373 Note that scale and bias parameters operate on pixel data that has
1374 been converted to the range [0..1] according to a type-specific
1375 algorithm. Source pixels that are in floating point are not
1376 converted, but are clamped to the range [0..1]. Clamping occurs late
1377 in the pixel pipeline, only after scale, bias and color lookup have
1378 been performed.
1379
1380 @dend
1381 * ----------------------------------------------------
1382 */
1383 RMenum
rmImageSetScale(RMimage * toModify,float newScale)1384 rmImageSetScale (RMimage *toModify,
1385 float newScale)
1386 {
1387 if (RM_ASSERT(toModify, "rmImageSetScale error: the input RMimage is NULL") == RM_WHACKED)
1388 return(RM_WHACKED);
1389
1390 toModify->scale = newScale;
1391
1392 return(RM_CHILL);
1393 }
1394
1395
1396 /*
1397 * ----------------------------------------------------
1398 * @Name rmImageGetScale
1399 @pstart
1400 RMenum rmImageGetScale (const RMimage *toQuery,
1401 float *returnScale)
1402
1403 @pend
1404
1405 @astart
1406 const RMimage *toQuery - a handle to an RMimage object to query
1407 (input).
1408
1409 float *returnScale - a handle to a float that will be set to contain
1410 the RMimage object's pixel scale attribute (modified).
1411 @aend
1412
1413 @dstart
1414
1415 Use this routine to obtain the pixel scale parameter of an RMimage
1416 object. Returns RM_CHILL upon success, and copies the RMimage
1417 object's pixel scale attribute into the caller-supplied
1418 memory. Returns RM_WHACKED upon failure.
1419
1420 Pixel scale and bias are used in the OpenGL pixel pipeline to modify
1421 pixel values as they move from the application into the framebuffer.
1422 Inside OpenGL, application pixel components are first converted to
1423 the range [0..1] using an algorithm that is a function of the source
1424 pixel type (byte, short, etc.). Next, pixels are converted from the
1425 source pixel format (luminance-alpha, RGB, etc.) into RGBA. Next,
1426 each pixel component is multiplied by the "scale" factor, then "bias"
1427 is added.
1428
1429 The scale value is simply a linear multiplier that is applied to each
1430 pixel value.
1431
1432 Note that scale and bias parameters operate on pixel data that has
1433 been converted to the range [0..1] according to a type-specific
1434 algorithm. Source pixels that are in floating point are not
1435 converted, but are clamped to the range [0..1]. Clamping occurs late
1436 in the pixel pipeline, only after scale, bias and color lookup have
1437 been performed.
1438
1439 @dend
1440 * ----------------------------------------------------
1441 */
1442 RMenum
rmImageGetScale(const RMimage * toQuery,float * returnScale)1443 rmImageGetScale (const RMimage *toQuery,
1444 float *returnScale)
1445 {
1446 if ((RM_ASSERT(toQuery, "rmImageGetScale error: the input RMimage is NULL") == RM_WHACKED) ||
1447 (RM_ASSERT(returnScale, "rmImageGetScale error: the returnScale float * is NULL") == RM_WHACKED))
1448 return(RM_WHACKED);
1449
1450 *returnScale = toQuery->scale;
1451
1452 return(RM_CHILL);
1453 }
1454
1455
1456 /*
1457 * ----------------------------------------------------
1458 * @Name rmImageSetBias
1459 @pstart
1460 RMenum rmImageSetBias (RMimage *toModify,
1461 float newBias)
1462
1463 @pend
1464
1465 @astart
1466 RMimage *toModify - a handle to an RMimage object (modified).
1467
1468 float newBias - a floating point value that represents the new pixel
1469 bias that will be applied to the RMimage object (input).
1470 @aend
1471
1472 @dstart
1473
1474 Use this routine to set the pixel bias parameter of an RMimage
1475 object. Returns RM_CHILL upon success, or RM_WHACKED upon failure.
1476
1477 Pixel scale and bias are used in the OpenGL pixel pipeline to modify
1478 pixel values as they move from the application into the framebuffer.
1479 Inside OpenGL, application pixel components are first converted to
1480 the range [0..1] using an algorithm that is a function of the source
1481 pixel type (byte, short, etc.). Next, pixels are converted from the
1482 source pixel format (luminance-alpha, RGB, etc.) into RGBA. Next,
1483 each pixel component is multiplied by the "scale" factor, then "bias"
1484 is added.
1485
1486 The bias value is simply an offset that is added to each pixel value.
1487
1488 Note that scale and bias parameters operate on pixel data that has
1489 been converted to the range [0..1] according to a type-specific
1490 algorithm. Source pixels that are in floating point are not
1491 converted, but are clamped to the range [0..1]. Clamping occurs late
1492 in the pixel pipeline, only after scale, bias and color lookup have
1493 been performed.
1494
1495 @dend
1496 * ----------------------------------------------------
1497 */
1498 RMenum
rmImageSetBias(RMimage * toModify,float newBias)1499 rmImageSetBias (RMimage *toModify,
1500 float newBias)
1501 {
1502 if (RM_ASSERT(toModify, "rmImageSetBias error: the input RMimage is NULL") == RM_WHACKED)
1503 return(RM_WHACKED);
1504
1505 toModify->bias = newBias;
1506
1507 return(RM_CHILL);
1508 }
1509
1510
1511 /*
1512 * ----------------------------------------------------
1513 * @Name rmImageGetBias
1514 @pstart
1515 RMenum rmImageGetBias (const RMimage *toQuery,
1516 float *returnBias)
1517
1518 @pend
1519
1520 @astart
1521 const RMimage *toQuery - a handle to an RMimage object to query
1522 (input).
1523
1524 float *returnBias - a handle to a float that will be set to contain
1525 the RMimage object's bias attribute (modified).
1526 @aend
1527
1528 @dstart
1529
1530 Use this routine to obtain the pixel bias parameter of an RMimage
1531 object. Returns RM_CHILL upon success, and copies the RMimage
1532 object's bias attribute into the caller-supplied memory. Returns
1533 RM_WHACKED upon failure.
1534
1535 Pixel scale and bias are used in the OpenGL pixel pipeline to modify
1536 pixel values as they move from the application into the framebuffer.
1537 Inside OpenGL, application pixel components are first converted to
1538 the range [0..1] using an algorithm that is a function of the source
1539 pixel type (byte, short, etc.). Next, pixels are converted from the
1540 source pixel format (luminance-alpha, RGB, etc.) into RGBA. Next,
1541 each pixel component is multiplied by the "scale" factor, then "bias"
1542 is added.
1543
1544 The bias value is simply an offset that is added to each pixel value.
1545
1546 Note that scale and bias parameters operate on pixel data that has
1547 been converted to the range [0..1] according to a type-specific
1548 algorithm. Source pixels that are in floating point are not
1549 converted, but are clamped to the range [0..1]. Clamping occurs late
1550 in the pixel pipeline, only after scale, bias and color lookup have
1551 been performed.
1552
1553 @dend
1554 * ----------------------------------------------------
1555 */
1556 RMenum
rmImageGetBias(const RMimage * toQuery,float * returnBias)1557 rmImageGetBias (const RMimage *toQuery,
1558 float *returnBias)
1559 {
1560 if ((RM_ASSERT(toQuery, "rmImageGetBias error: the input RMimage is NULL") == RM_WHACKED) ||
1561 (RM_ASSERT(returnBias, "rmImageGetBias error: the returnBias float * is NULL") == RM_WHACKED))
1562 return(RM_WHACKED);
1563
1564 *returnBias = toQuery->bias;
1565
1566 return(RM_CHILL);
1567 }
1568
1569
1570 /* PRIVATE */
1571 int
private_rmImageNumComponentBytes(RMenum type_enum)1572 private_rmImageNumComponentBytes (RMenum type_enum)
1573 {
1574 int rval = 0;
1575
1576 switch(type_enum)
1577 {
1578 case RM_UNSIGNED_BYTE:
1579 rval = sizeof(unsigned char);
1580 break;
1581
1582 case RM_FLOAT:
1583 rval = sizeof(float);
1584 break;
1585
1586 case RM_UNSIGNED_SHORT:
1587 case RM_SHORT:
1588 rval = sizeof(short);
1589 break;
1590
1591 default:
1592 rmError("private_rmImageNumComponentBytes() error: invalid image type enumerator.");
1593 break;
1594 }
1595
1596 return(rval);
1597 }
1598
1599
1600 /* PRIVATE */
1601 GLenum
private_rmImageGetOGLFormat(const RMimage * img)1602 private_rmImageGetOGLFormat (const RMimage *img)
1603 {
1604 int glformat;
1605
1606 switch(private_rmImageGetFormat(img))
1607 {
1608 case RM_IMAGE_ALPHA:
1609 glformat = GL_ALPHA;
1610 break;
1611
1612 case RM_IMAGE_LUMINANCE_ALPHA:
1613 glformat = GL_LUMINANCE_ALPHA;
1614 break;
1615
1616 case RM_IMAGE_LUMINANCE:
1617 glformat = GL_LUMINANCE;
1618 break;
1619
1620 #if 0
1621 /* deprecated */
1622 case RM_IMAGE_INDEXED_RGB:
1623 #endif
1624 case RM_IMAGE_RGB:
1625 glformat = GL_RGB;
1626 break;
1627
1628 #if 0
1629 /* deprecated */
1630 case RM_IMAGE_INDEXED_RGBA:
1631 #endif
1632 case RM_IMAGE_RGBA:
1633 glformat = GL_RGBA;
1634 break;
1635
1636 case RM_IMAGE_DEPTH:
1637 glformat = GL_DEPTH_COMPONENT;
1638 break;
1639
1640 default:
1641 rmError(" rmImageGetOGLFormat() error: image format not appropriately handled. ");
1642 glformat = GL_RGB; /* ???? */
1643 break;
1644 }
1645 return(glformat);
1646 }
1647
1648
1649 /* PRIVATE */
1650 GLenum
private_rmImageGetOGLType(const RMimage * img)1651 private_rmImageGetOGLType(const RMimage *img)
1652 {
1653 int glformat;
1654
1655 switch(private_rmImageGetType(img))
1656 {
1657 case RM_UNSIGNED_BYTE:
1658 glformat = GL_UNSIGNED_BYTE;
1659 break;
1660
1661 case RM_FLOAT:
1662 glformat = GL_FLOAT;
1663 break;
1664
1665 case RM_SHORT:
1666 glformat = GL_SHORT;
1667 break;
1668
1669 case RM_UNSIGNED_SHORT:
1670 glformat = GL_UNSIGNED_SHORT;
1671 break;
1672
1673 default:
1674 rmError(" rmImageGetOGLType() error: image format not appropriately handled. ");
1675 glformat = GL_UNSIGNED_BYTE; /* ???? */
1676 break;
1677 }
1678 return(glformat);
1679 }
1680
1681
1682 /* PRIVATE */
1683 int
private_rmImageGetNumElements(RMenum image_format_enum)1684 private_rmImageGetNumElements (RMenum image_format_enum)
1685 {
1686 int rstat;
1687
1688 /* given an RM image format enumerator, return the number of elements that make up the image */
1689 switch(image_format_enum)
1690 {
1691 #if 0
1692 /* deprecated */
1693 case RM_IMAGE_INDEXED_RGB:
1694 case RM_IMAGE_INDEXED_RGBA:
1695 #endif
1696 case RM_IMAGE_LUMINANCE:
1697 case RM_IMAGE_ALPHA:
1698 case RM_IMAGE_DEPTH:
1699 rstat = 1;
1700 break;
1701
1702 case RM_IMAGE_RGB:
1703 rstat = 3;
1704 break;
1705
1706 case RM_IMAGE_RGBA:
1707 rstat = 4;
1708 break;
1709
1710 case RM_IMAGE_LUMINANCE_ALPHA:
1711 rstat = 2;
1712 break;
1713
1714 default:
1715 rstat = RM_WHACKED;
1716 break;
1717 }
1718 return(rstat);
1719 }
1720
1721
1722 /* PRIVATE */
1723 RMenum
private_rmImage2DMirrorVertical(RMimage * r)1724 private_rmImage2DMirrorVertical (RMimage *r)
1725 {
1726 unsigned char *tmp, *s, *d;
1727 int w, h, i, n, elements;
1728 RMenum f;
1729
1730 if (RM_ASSERT(r, "rmImage2DMirrorVert() error: input RMimage2D is NULL.") == RM_WHACKED)
1731 return(RM_WHACKED);
1732
1733 w = private_rmImageGetWidth(r);
1734 h = private_rmImageGetHeight(r);
1735
1736 f = private_rmImageGetFormat(r);
1737 elements = private_rmImageGetElements(r);
1738
1739 n = private_rmImageGetBytesPerScanline(r);
1740
1741 tmp = (unsigned char *)malloc(sizeof(unsigned char)*n);
1742
1743 s = rmImageGetPixelData(r);
1744
1745 if (RM_ASSERT(s, "private_rmImage2DMirrorVertical() error: the pixel data pointer for the input RMimage is NULL!") == RM_WHACKED)
1746 return(RM_WHACKED);
1747
1748 d = s + (n * (h - 1));
1749
1750 for (i = 0; i< (h >> 1); i++, s += n, d -= n)
1751 {
1752 memcpy((void *)tmp, (void *)d, (sizeof(unsigned char) * n));
1753 memcpy((void *)d, (void *)s, (sizeof(unsigned char) * n));
1754 memcpy((void *)s, (void *)tmp, (sizeof(unsigned char) * n));
1755 }
1756 free((void *)tmp);
1757
1758 return(RM_CHILL);
1759 }
1760
1761 /* private */
1762 static void
private_rmMirrorHorizontalPixels(unsigned char * b,int w,int bytesPerPixel,unsigned char * b2)1763 private_rmMirrorHorizontalPixels(unsigned char *b,
1764 int w,
1765 int bytesPerPixel,
1766 unsigned char *b2)
1767 {
1768 int i;
1769 int s = 0;
1770 int d = (w-1) * bytesPerPixel;
1771
1772 for (i=0;i<w;i++)
1773 {
1774 /* copy pixel[i] in b1 to pixel[w-1-i] in b2 */
1775 memcpy((void *)(b2+d), (void *)(b+s), bytesPerPixel);
1776 s += bytesPerPixel;
1777 d -= bytesPerPixel;
1778 }
1779
1780 /* copy b2 back into b */
1781 memcpy(b, b2, sizeof(unsigned char)*w*bytesPerPixel);
1782 }
1783
1784 /* PRIVATE */
1785 RMenum
private_rmImage2DMirrorHorizontal(RMimage * r)1786 private_rmImage2DMirrorHorizontal (RMimage *r)
1787 {
1788 unsigned char *tmp, *s, *tmp2;
1789 int w, h, i, n, elements;
1790 RMenum f, t;
1791 int bytesPerPixel;
1792
1793 if (RM_ASSERT(r, "rmImage2DMirrorVert() error: input RMimage2D is NULL.") == RM_WHACKED)
1794 return(RM_WHACKED);
1795
1796 w = private_rmImageGetWidth(r);
1797 h = private_rmImageGetHeight(r);
1798
1799 f = private_rmImageGetFormat(r);
1800 elements = private_rmImageGetElements(r);
1801
1802 t = private_rmImageGetType(r);
1803
1804 n = private_rmImageGetBytesPerScanline(r);
1805
1806 tmp = (unsigned char *)malloc(sizeof(unsigned char)*n);
1807 tmp2 = (unsigned char *)malloc(sizeof(unsigned char)*n);
1808
1809 bytesPerPixel = private_rmImageNumComponentBytes(t) * elements;
1810
1811 s = rmImageGetPixelData(r);
1812
1813 if (RM_ASSERT(s, "private_rmImage2DMirrorVertical() error: the pixel data pointer for the input RMimage is NULL!") == RM_WHACKED)
1814 return(RM_WHACKED);
1815
1816 for (i = 0; i<h; i++, s += n)
1817 {
1818 /* copy row of pixels into work buffer */
1819 memcpy((void *)tmp, (void *)s, (sizeof(unsigned char) * n));
1820
1821 /* reverse order of pixels in tmp */
1822 private_rmMirrorHorizontalPixels(tmp, w, bytesPerPixel, tmp2);
1823
1824 /* copy row of pixels from work buffer back into pixel buffer */
1825 memcpy((void *)s, (void *)tmp, (sizeof(unsigned char) * n));
1826 }
1827 free((void *)tmp2);
1828 free((void *)tmp);
1829
1830 return(RM_CHILL);
1831 }
1832
1833
1834 /* PRIVATE */
1835 RMenum
private_rmImage2DResize(const RMimage * src,RMimage * dst,RMenum hardware_or_software,RMpipe * hwPipe)1836 private_rmImage2DResize (const RMimage *src,
1837 RMimage *dst,
1838 RMenum hardware_or_software,
1839 RMpipe *hwPipe)
1840 {
1841 /*
1842 * resizes the image in src placing the result in dst. we
1843 * restrict the image format of src and dst to be the same.
1844 *
1845 * we assume that the image buffer in dst has already been malloc'ed
1846 *
1847 * 7/27/01 - RM_HARDWARE operations (read, write) moved to the
1848 * back buffer to avoid problems associated with needing the OpenGL
1849 * window to be unobstructed and on top in stacking order. we will
1850 * do all read/write ops to the backbuffer, but do a swapbuffers
1851 * after read/write operations are complete to provide visual
1852 * feedback. we may want, at some point, to add a parm that enables
1853 * a swapbuffers.
1854 */
1855 int sw, sh;
1856 int dw, dh;
1857 float xzoom, yzoom;
1858 GLenum srcglformat, srcptype, dstptype, dstglformat;
1859 RMenum src_format, dst_format;
1860
1861 sw = private_rmImageGetWidth(src);
1862 sh = private_rmImageGetHeight(src);
1863
1864 dw = private_rmImageGetWidth(dst);
1865 dh = private_rmImageGetHeight(dst);
1866
1867 src_format = private_rmImageGetFormat(src);
1868 dst_format = private_rmImageGetFormat(dst);
1869
1870 if (src_format != dst_format)
1871 return(RM_WHACKED);
1872
1873 srcglformat = private_rmImageGetOGLFormat(src);
1874 dstglformat = private_rmImageGetOGLFormat(dst);
1875
1876 srcptype = private_rmImageGetOGLType(src);
1877 dstptype = private_rmImageGetOGLType(dst);
1878
1879 if (hardware_or_software == RM_HARDWARE)
1880 {
1881 private_rmInitInternalImagingPipeline(hwPipe);
1882
1883 glDrawBuffer(GL_BACK);
1884
1885 xzoom = (float)(dw + 1) / (float)(sw);
1886 yzoom = (float)(dh + 1) / (float)(sh);
1887
1888 glRasterPos2f(0.0F, 0.0F);
1889 glPixelZoom((GLfloat)xzoom, (GLfloat)yzoom);
1890 private_glDrawPixels(sw, sh, srcglformat, srcptype, (unsigned char *)private_rmImageGetPixelData(src), src);
1891
1892 glFlush();
1893 glFinish();
1894
1895 glRasterPos2f(0.0F, 0.0F);
1896 glPixelZoom((GLfloat)1.0F, (GLfloat)1.0F);
1897
1898 glReadBuffer(GL_BACK);
1899
1900 glPixelZoom((GLfloat)1.0F, (GLfloat)1.0F);
1901
1902 private_glReadPixels(0, 0, dw, dh, dstglformat, dstptype, (GLvoid *)private_rmImageGetPixelData(dst));
1903
1904 private_postRenderSwapBuffersFunc (hwPipe);
1905
1906 #if 0
1907 /* temp hack: shows the pixels we just read on-screen for a sanity check */
1908 glReadPixels(0, 0, dw, dh, dstglformat, dstptype, (GLvoid *)private_rmImageGetPixelData(dst));
1909 glRasterPos2f(0.0, 0.0);
1910 glClear(GL_COLOR_BUFFER_BIT);
1911 glDrawPixels(dw, dh, dstglformat, dstptype, (GLvoid *)private_rmImageGetPixelData(dst));
1912 glDrawBuffer(GL_BACK);
1913 #endif
1914 }
1915 else /* RM_SOFTWARE */
1916 {
1917 float *t; /* tmp */
1918 int i; /* tmp */
1919 fake_gluScaleImage(srcglformat, sw, sh, srcptype, private_rmImageGetPixelData(src), dw, dh, dstptype, private_rmImageGetPixelData(dst));
1920
1921 t = (float *)private_rmImageGetPixelData(src);
1922 t = (float *)private_rmImageGetPixelData(dst);
1923 i = 0;
1924 }
1925
1926 return(RM_CHILL);
1927
1928 /*
1929 * we need code that will accomodate framebuffers which don't
1930 * support alpha directly when the input image format has alpha.
1931 * the approach will be to strip out the alpha from the input,
1932 * treat it as luminance, do a glDrawPixels, then read it back in.
1933 */
1934 #if 0
1935 glPixelTransferf(GL_RED_SCALE, (GLfloat)0.3 * scale);
1936 glPixelTransferf(GL_RED_BIAS, (GLfloat)bias);
1937 glPixelTransferf(GL_GREEN_SCALE, (GLfloat)0.59 * scale);
1938 glPixelTransferf(GL_GREEN_BIAS, (GLfloat)bias);
1939 glPixelTransferf(GL_BLUE_SCALE, (GLfloat)0.1 * scale);
1940 glPixelTransferf(GL_BLUE_BIAS, (GLfloat)bias);
1941 #endif
1942 }
1943
1944
1945 /* PRIVATE */
1946 RMenum
private_rmImageSetGLScaleAndBias(const RMimage * src)1947 private_rmImageSetGLScaleAndBias (const RMimage *src)
1948 {
1949 GLfloat scale, bias;
1950
1951 scale = src->scale;
1952 bias = src->bias;
1953
1954 /* is the image a depth image? if so, apply scale and bias only to depth, otherwise apply to RGBA channels */
1955 if (private_rmImageGetFormat(src) == RM_IMAGE_DEPTH)
1956 {
1957 glPixelTransferf(GL_DEPTH_BIAS, bias);
1958 glPixelTransferf(GL_DEPTH_SCALE, scale);
1959 }
1960 else
1961 {
1962 glPixelTransferf(GL_RED_BIAS, bias);
1963 glPixelTransferf(GL_GREEN_BIAS, bias);
1964 glPixelTransferf(GL_BLUE_BIAS, bias);
1965 glPixelTransferf(GL_ALPHA_BIAS, bias);
1966
1967 glPixelTransferf(GL_RED_SCALE, scale);
1968 glPixelTransferf(GL_GREEN_SCALE, scale);
1969 glPixelTransferf(GL_BLUE_SCALE, scale);
1970 glPixelTransferf(GL_ALPHA_SCALE, scale);
1971 }
1972
1973 return(RM_CHILL);
1974 }
1975
1976
1977 /* PRIVATE */
1978 RMenum
private_rmSetLuminancePixelScale(void)1979 private_rmSetLuminancePixelScale(void)
1980 {
1981 float bias = 0.0;
1982 float rscale = 0.3, gscale = 0.6, bscale = 0.1, ascale = 0.0;
1983
1984 glPixelTransferf(GL_RED_BIAS, bias);
1985 glPixelTransferf(GL_GREEN_BIAS, bias);
1986 glPixelTransferf(GL_BLUE_BIAS, bias);
1987 glPixelTransferf(GL_ALPHA_BIAS, bias);
1988
1989 glPixelTransferf(GL_RED_SCALE, rscale);
1990 glPixelTransferf(GL_GREEN_SCALE, gscale);
1991 glPixelTransferf(GL_BLUE_SCALE, bscale);
1992 glPixelTransferf(GL_ALPHA_SCALE, ascale);
1993
1994 return(RM_CHILL);
1995 }
1996
1997
1998 /* PRIVATE */
1999 RMenum
private_rmUnsetLuminancePixelScale(void)2000 private_rmUnsetLuminancePixelScale(void)
2001 {
2002 float bias = 0.0;
2003 float rscale = 1.0, gscale = 1.0, bscale = 1.0, ascale = 1.0;
2004
2005 glPixelTransferf(GL_RED_BIAS, bias);
2006 glPixelTransferf(GL_GREEN_BIAS, bias);
2007 glPixelTransferf(GL_BLUE_BIAS, bias);
2008 glPixelTransferf(GL_ALPHA_BIAS, bias);
2009
2010 glPixelTransferf(GL_RED_SCALE, rscale);
2011 glPixelTransferf(GL_GREEN_SCALE, gscale);
2012 glPixelTransferf(GL_BLUE_SCALE, bscale);
2013 glPixelTransferf(GL_ALPHA_SCALE, ascale);
2014
2015 return(RM_CHILL);
2016 }
2017
2018
2019 /* PRIVATE */
2020 RMenum
private_rmImageUnsetGLScaleAndBias(const RMimage * src)2021 private_rmImageUnsetGLScaleAndBias(const RMimage *src)
2022 {
2023 if (private_rmImageGetFormat(src) == RM_IMAGE_DEPTH)
2024 {
2025 glPixelTransferf(GL_DEPTH_BIAS, 0.0F);
2026 glPixelTransferf(GL_DEPTH_SCALE, 1.0F);
2027 }
2028 else
2029 {
2030 glPixelTransferf(GL_RED_SCALE, 1.F);
2031 glPixelTransferf(GL_GREEN_SCALE, 1.F);
2032 glPixelTransferf(GL_BLUE_SCALE, 1.F);
2033 glPixelTransferf(GL_ALPHA_SCALE, 1.F);
2034
2035 glPixelTransferf(GL_RED_BIAS, 0.F);
2036 glPixelTransferf(GL_GREEN_BIAS, 0.F);
2037 glPixelTransferf(GL_BLUE_BIAS, 0.F);
2038 glPixelTransferf(GL_ALPHA_BIAS, 0.F);
2039 }
2040
2041 return(RM_CHILL);
2042 }
2043
2044
2045 /* PRIVATE */
2046 RMenum
private_glReadPixels(int x,int y,int width,int height,GLenum format,GLenum type,GLvoid * pixels)2047 private_glReadPixels (int x,
2048 int y,
2049 int width,
2050 int height,
2051 GLenum format,
2052 GLenum type,
2053 GLvoid *pixels)
2054 {
2055 if (format == GL_LUMINANCE)
2056 private_rmSetLuminancePixelScale();
2057
2058 glReadPixels(x, y, width, height, format, type, pixels);
2059
2060 if (format == GL_LUMINANCE)
2061 private_rmUnsetLuminancePixelScale();
2062
2063 return(RM_CHILL);
2064 }
2065
2066
2067 /* PRIVATE */
2068 RMenum
private_glDrawPixels(GLsizei width,GLsizei height,GLenum format,GLenum type,const GLvoid * pixeldata,const RMimage * src)2069 private_glDrawPixels (GLsizei width,
2070 GLsizei height,
2071 GLenum format,
2072 GLenum type,
2073 const GLvoid *pixeldata,
2074 const RMimage *src)
2075 {
2076 int doScaleBias = 0;
2077 int doColormap = 0;
2078
2079 if (src != NULL)
2080 {
2081 /* set scale & bias */
2082 if ((src->bias != 0.F) || (src->scale != 1.0F))
2083 {
2084 doScaleBias = 1;
2085 private_rmImageSetGLScaleAndBias(src);
2086 }
2087
2088 /* set pixel transfer */
2089 if (src->vismap != NULL)
2090 {
2091 doColormap = 1;
2092 private_rmSetPixelTransferMode(src->vismap);
2093 }
2094 }
2095 #if 0
2096 {
2097 GLboolean b;
2098 GLfloat f[4];
2099
2100 glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &b);
2101 fprintf(stderr," current raster position is %s valid \n", (b == GL_TRUE) ? "definitely" : "not");
2102
2103 glGetFloatv(GL_CURRENT_RASTER_POSITION, f);
2104
2105 if (b == GL_TRUE)
2106 fprintf(stderr, " rasterpos: %g %g %g \n", f[0], f[1], f[2]);
2107 }
2108 #endif
2109 /* draw pixels */
2110 glDrawPixels(width, height, format, type, pixeldata);
2111
2112 /* unset pixel transfer */
2113 if (doScaleBias == 1)
2114 private_rmImageUnsetGLScaleAndBias(src);
2115
2116 /* unset scale & bias */
2117 if (doColormap == 1)
2118 private_rmUnsetPixelTransferMode();
2119
2120 return(RM_CHILL);
2121 }
2122 /* EOF */
2123