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