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: rmtxture.c,v 1.13 2005/06/06 02:04:29 wes Exp $
27  * Version: $Name: OpenRM-1-6-0-2-RC2 $
28  * $Revision: 1.13 $
29  * $Log: rmtxture.c,v $
30  * Revision 1.13  2005/06/06 02:04:29  wes
31  * Lots of small additions to clean up compiler warnings.
32  *
33  * Revision 1.12  2005/05/07 15:40:42  wes
34  * Remove error message indicating 1D texture downloads not tested.
35  *
36  * Revision 1.11  2005/05/06 16:33:49  wes
37  * Update texture state/env manipulation for 1D textures. Update
38  * documentation to reflect that 1D textures are supported.
39  *
40  * Revision 1.10  2005/02/27 19:34:04  wes
41  * Added support for application supplied texture object IDs and display lists.
42  *
43  * Revision 1.9  2005/02/19 16:43:48  wes
44  * Distro sync and consolidation.
45  * Remove dead and test code.
46  *
47  * Revision 1.8  2005/01/23 17:08:25  wes
48  * Copyright updated to 2005.
49  * Updates to support access and use of extensions; multitexturing on all
50  * platforms, use of 3d texture extension to realize implementation of
51  * volume rendering and related functions on Windows platforms.
52  *
53  * Revision 1.7  2004/01/16 16:49:13  wes
54  * Updated copyright line for 2004.
55  *
56  * Revision 1.6  2003/11/22 00:53:41  wes
57  * Changes to support RMtextures being shared when assigned as scene parameters
58  * to properly implement instancing.
59  *
60  * Revision 1.5  2003/06/14 03:17:20  wes
61  * Minor documentation tweaks.
62  *
63  * Revision 1.4  2003/03/16 21:56:16  wes
64  * Documentation updates.
65  *
66  * Revision 1.3  2003/02/14 00:19:25  wes
67  * No significant changes.
68  *
69  * Revision 1.2  2003/02/02 02:07:16  wes
70  * Updated copyright to 2003.
71  *
72  * Revision 1.1.1.1  2003/01/28 02:15:23  wes
73  * Manual rebuild of rm150 repository.
74  *
75  * Revision 1.16  2003/01/27 05:04:42  wes
76  * Changes to RMpipe API and initialization sequence to unify GLX, WGL and CR
77  * platforms w/o too much disruption to existing apps.
78  *
79  * Revision 1.15  2003/01/20 05:39:49  wes
80  * Rewrote texture state handling code.
81  *
82  * Revision 1.14  2003/01/16 22:21:17  wes
83  * Updated all source files to reflect new organization of header files:
84  * all header files formerly located in include/rmaux, include/rmi, include/rmv
85  * are now located in include/rm.
86  *
87  * Revision 1.13  2003/01/12 23:50:06  wes
88  * Minor adjustments to texturing environment controls to fix problems with
89  * the texture environment not being set correctly.
90  *
91  * Revision 1.12  2002/11/14 15:34:51  wes
92  * Minor editing for beautification.
93  *
94  * Revision 1.11  2002/09/17 14:18:30  wes
95  * Conditional code added to rmTextureSetImages() that will do a more
96  * conservative job of deleting old mipmaps when new images are
97  * assigned to an RMtexture.
98  *
99  * Revision 1.10  2002/04/30 19:36:03  wes
100  * Added support for non-byte texture data for 3D textures. All RM
101  * image formats are now supported for 3D textures.
102  *
103  * Revision 1.9  2001/06/03 20:50:48  wes
104  * Removed dead code.
105  *
106  * Revision 1.8  2001/03/31 17:12:39  wes
107  * v1.4.0-alpha-2 checkin.
108  *
109  * Revision 1.7  2000/12/05 03:04:53  wes
110  * Cosmetic changes.
111  *
112  * Revision 1.6  2000/12/04 00:42:35  wes
113  * Minor tweaks to eliminate compile warnings.
114  *
115  * Revision 1.5  2000/12/03 22:35:27  wes
116  * Mods for thread safety.
117  *
118  * Revision 1.4  2000/08/22 16:19:36  wes
119  * Moved code that turns off texturing to "the right place" after
120  * textures have been downloaded.
121  *
122  * Revision 1.3  2000/05/17 14:19:19  wes
123  * Removed #ifdef MESA from around the glIsTexture call - this crash
124  * bug was fixed in the nVidia driver released on 1 May 2000.
125  *
126  * Revision 1.2  2000/04/20 16:29:47  wes
127  * Documentation additions/enhancements, some code rearragement.
128  *
129  * Revision 1.1.1.1  2000/02/28 21:29:40  wes
130  * OpenRM 1.2 Checkin
131  *
132  * Revision 1.1.1.1  2000/02/28 17:18:48  wes
133  * Initial entry - pre-RM120 release, source base for OpenRM 1.2.
134  *
135  */
136 
137 
138 #include <rm/rm.h>
139 #include "rmprivat.h"
140 
141 /*
142  * ----------------------------------------------------
143  * @Name rmTextureNew
144  @pstart
145  RMtexture * rmTextureNew (int ntdims)
146  @pend
147 
148  @astart
149  int ntdims - an integer value specifying whether the new texture
150     object will be a 1D, 2D or 3D texture. The value for this parameter
151     must be one of 1, 2 or 3.
152     (input).
153  @aend
154 
155  @dstart
156 
157  Creates a new RMtexture object, returning a handle to the caller upon
158  success, or NULL upon failure.
159 
160  Texture mapping in RM is accomplished by assigning an RMtexture
161  object to an RMnode as a scene parameter (see rmNodeSetSceneTexture).
162  Primitives that have texture coordinates (assigned with one of
163  rmPrimitiveSetTexcoord1D, rmPrimitiveSetTexcoord2D, or
164  rmPrimitiveSetTexcoord3D) that are located within any descendent
165  nodes, including the node containing the RMtexture object, that has
166  an RMprimitive with texture coordinates, will be rendered with
167  texture mapping active. The presence of the RMtexture object causes
168  texture mapping to become active, and texture coordinates cause
169  texture mapping to occur once active.
170 
171  The RMtexture object is a container for both texture images
172  (rmTextureSetImages) and texturing environment, so it encompasses
173  both the OpenGL texture object as well as the OpenGL texturing
174  environment. The texturing environment consists of wrap mode
175  (rmTextureSetWrapMode), any texture filtering that occurs when
176  textures get small or large (rmTextureSetFilterMode), selection of
177  one of several environmental modes that control how the texture color
178  is blended with the pixel fragment color (rmTextureSetEnv),
179  manipulation over how the texture is physically represented in the
180  OpenGL pipeline (rmTextureSetGLTexelFormat).
181 
182  Upon creation, rmTextureNew sets the following defaults all texture objects:
183 
184  1. Texturing environment (blending) set to GL_MODULATE
185  (rmTextureSetEnv).
186 
187  2. Wrap mode is set to GL_CLAMP (rmTextureSetWrapMode).
188 
189  4. Texel storage format is GL_RGBA. Can be overridden by a subsequent
190  call to rmTextureGLSetTexelFormat().
191 
192  For the texture filtering mode, 3D textures are assigned GL_NEAREST for
193  maximum speed, while 1D and 2D textures are assigned the value of
194  GL_LINEAR for best quality.
195 
196  Before assigning an RMtexture object to an RMnode as a scene
197  parameter with rmNodeSetSceneTexture, the application must populate
198  the RMtexture object with RMimage object(s) that contain the texture
199  data.
200 
201  @dend
202  * ----------------------------------------------------
203  */
204 RMtexture *
rmTextureNew(int ntdims)205 rmTextureNew (int ntdims)
206 {
207     int i;
208     int save;
209 
210     RMtexture *t = private_rmTextureNew();
211     save = t->compListIndx;
212     memset(t,0,sizeof(RMtexture));
213     t->compListIndx = save;
214 
215     /*
216      * initialize the struct (formerly done with bzero).
217      */
218     for (i=0;i<RM_MAX_MIPMAPS;i++)
219 	t->images[i] = NULL;
220 
221     t->nmipmaps = 0;
222 
223     t->blendColor = NULL;
224 
225     /* OpenGL texel format is initially left unspecified. the default
226      * behavior will be to ask for GL_RGBA as the OpenGL texel format.
227      * the default can be overridden by the application by calling
228      * rmTextureGLSetTexelFormat().
229      */
230     rmTextureSetGLTexelFormat(t, GL_RGBA);
231 
232     /*
233      * 11/21/03 - initialize the cache ID and data keys to a known value
234      */
235     t->cacheKeyID = RM_CACHEKEY_UNINITIALIZED_VALUE;
236     t->cacheKeyData = RM_CACHEKEY_UNINITIALIZED_VALUE;
237 
238     /*
239      * 11/21/03 - initialize the reference count to 0.
240      */
241     private_rmTextureSetRefCount(t, 0);
242 
243     /* now fill in caller-supplied info. */
244 
245     t->dims = ntdims;
246 
247     /* set the default filtering modes */
248     switch (ntdims)
249        {
250        case 3: /* 3D textures: use GL_NEAREST for speed */
251 	  rmTextureSetFilterMode(t, GL_NEAREST, GL_NEAREST);
252 	  break;
253 
254        default:
255 	  /*
256 	   * for all non 3D textures, use GL_LINEAR and pals for best images.
257 	   * apps that use mipmaps will probably want to use
258 	   * GL_LINEAR_MIPMAP_LINEAR for better images.
259 	   */
260 	  rmTextureSetFilterMode(t, GL_LINEAR, GL_LINEAR);
261 	  break;
262        }
263 
264     /* set the default wrap mode */
265     rmTextureSetWrapMode(t, GL_CLAMP);
266 
267     /* set the default texture environment mode - it determines how texels
268      are combined with existing fragments*/
269     rmTextureSetEnv(t, GL_MODULATE, NULL);
270 
271     return(t);
272 }
273 
274 
275 /*
276  * ----------------------------------------------------
277  * @Name rmTextureDelete
278  @pstart
279  RMenum rmTextureDelete (RMtexture *toDelete,
280 		         RMenum deleteImagesBool)
281  @pend
282 
283  @astart
284  RMtexture *toDelete - a handle to an RMtexture object to delete.
285 
286  RMenum deleteImagesBool - an RMenum value, either RM_TRUE or
287     RM_FALSE, that indicates whether or not to delete the underlying
288     RMimage data.
289  @aend
290 
291  @dstart
292 
293  Use this routine to free an RMtexture object when no longer
294  needed. At this time (Jan 2000), it is the applications
295  responsibility to dictate whether or not the underlying RMimage
296  texture data will be deleted. This control may become obsolete with
297  the addition of reference counting at the RMimage level, but this
298  feature is not implemented at this time.
299 
300  When the application specifies RM_TRUE for "deleteImagesBool", the
301  underlying RMimage data will be deleted (using rmImageDelete). If the
302  underlying RMimage's share management of the pixel data with the
303  application (specified using RM_DONT_COPY_DATA with
304  rmImageSetPixelData), the application-supplied callback will be
305  invoked at this time to release the image pixel data.
306 
307  This routine also deletes the underlying OpenGL texture object.
308 
309  @dend
310  * ----------------------------------------------------
311  */
312 RMenum
rmTextureDelete(RMtexture * t,RMenum delete_images_bool)313 rmTextureDelete (RMtexture *t,
314 		 RMenum delete_images_bool)
315 {
316     if (RM_ASSERT(t, "rmTextureDelete() error: the input texture object is NULL. \n") == RM_WHACKED)
317 	return(RM_WHACKED);
318 
319     /* 11/21/03 - don't permit texture deletion if the RMtexture is used
320      as a shared texture scene parameter at some RMnode. */
321     if (t->refCount > 0)
322     {
323 #if 0
324 	rmWarning("rmTextureDelete() warning: cannot delete the texture because its reference count is > 0. That means that it is being used as a scene parameter by some RMnode.");
325 #endif
326 	return RM_WHACKED;
327     }
328 
329     /* free the texture images? */
330     if (delete_images_bool == RM_TRUE)
331     {
332 	int      i;
333 	RMimage *ri;
334 
335 	for (i = 0; i < private_rmTextureGetNMipMaps(t); i++)
336 	{
337 	    ri = t->images[i];
338 	    rmImageDelete(ri);
339 	}
340     }
341 
342 #if 0
343     /* we need an RMpipe to properly delete an OpenGL texture.
344      at this point (10/2000) we have no way to explicitly remove
345      OpenGL textures once they have been created, except via
346      rmFinish(). */
347 
348     /* release opengl resources - this is deprecated code */
349     if (glIsTexture(t->tname) == GL_TRUE)
350 	glDeleteTextures(1, (GLuint *)&(t->tname));
351 #endif
352 
353     /* finally, delete the texture itself */
354     private_rmTextureDelete(t);
355 
356     return(RM_CHILL);
357 }
358 
359 
360 /*
361  * ----------------------------------------------------
362  * @Name rmTextureSetImages
363  @pstart
364  RMenum rmTextureSetImages (RMtexture *toModify,
365 		            RMimage **imageArray,
366 			    int nimages,
367 			    int borderWidth)
368  @pend
369 
370 
371  @astart
372  RMtexture *toModify - a handle to the RMtexture object to which image
373     texture data will be assigned (modified).
374 
375  RMimage **imageArray - a handle to an array of RMimage objects that
376     will be assigned to the RMtexture object as texture data. This
377     list will not be modified by this routine.
378 
379  int nimages - an integer value indicating both the length or size of
380     the imageArray parameter.
381 
382  int borderWidth - an integer value specifying the texture border
383     width. May be either 1 or 0.
384  @aend
385 
386  @dstart
387 
388  Use this routine to assign texture image data to an RMtexture object.
389  Returns RM_CHILL upon success, or RM_WHACKED upon failure.
390 
391  In OpenGL, all images that are used as textures MUST BE and even
392  power of 2 in size, although image width and height need not be
393  equal. Thus, one may have image data which is 512 pixels wide by 64
394  pixels high.  Use rmImageResize or gluScaleImage to resize an image
395  if needed to honor the power-of-two size restriction.
396 
397  One or more images may be assigned to a single texture object. The
398  practice of assigning multiple images to a single texture object is
399  called "Mip-mapping." The basic idea behind mip-mapping is that when
400  a single texel (pixel from the texture data) covers very few screen
401  pixels, one can use a low-resolution version of the texture data
402  since the high-frequency texture components are lost by the
403  rasterization process. When a single texel covers many screen pixels,
404  a high-resolution version of the texture data is used in order to
405  preserve, as much as possible, the high-frequency component of the
406  texture data.
407 
408  While mip-map construction is both a science and an art, for the most
409  part, applications may simply use scaled down versions of a
410  high-resolution texture for each mipmap level.
411 
412  When mipmapping is used (nImages > 1), the "proper" number of mipmaps
413  to create and use is 1+log2(largest dimension size of source
414  texture). So, if the original texture is 256x64, a total of 8 images
415  are needed to make a complete mipmap. The eight images will be sized:
416  256x64 (the original image), 128x32, 64x16, 32x8, 16x4, 8x2, 4x1,
417  2x1, 1x1 for a total of 9 images (log2(256)+1). In other words, you
418  must specify all images that are sized from the original image down
419  to a 1x1 representation.
420 
421  Inside this routine, each image of the RMimage array is COPIED into
422  the texture object using the routine rmImageDup. A fine point to be
423  aware of is the fact that rmImageDup does not necessarily duplicate
424  the underlying pixel data, so duplication of the imageArray does not
425  necessarily result in a significant use of memory. Whether or not the
426  image pixel data is copied is a function of whether or not the pixel
427  data is assigned to the RMimage using RM_COPY_DATA or
428  RM_DONT_COPY_DATA.
429 
430  The border width parameter (either 0 or 1) indicates whether or not
431  the "edge" pixels of the texture image data are to be treated as
432  border pixels. Above, we mentioned that OpenGL textures must be an
433  even power of two in size. More precisely, for a two-dimensional
434  texture, the size of the input image data is (2^n + 2b, 2^m + 2b)
435  where n,m are positive integers, and "b" is the borderWidth
436  parameter. The treatment of border pixels is more fully described in
437  the OpenGL Red Book.
438 
439  Note that the borderWidth parameter applies to ALL images in a set of
440  Mipmaps, not just the first image.
441 
442  @dend
443  * ----------------------------------------------------
444  */
445 RMenum
rmTextureSetImages(RMtexture * t,RMimage ** imagearray,int nimages,int borderWidth)446 rmTextureSetImages (RMtexture *t,
447 		    RMimage **imagearray,
448 		    int nimages,
449 		    int borderWidth)
450 {
451     int i;
452 
453     if (RM_ASSERT(t, "rmTextureSetImages() error: the input texture is NULL.") == RM_WHACKED)
454 	return(RM_WHACKED);
455 
456     /* first, free up any existing RMimage objects */
457     for (i = 0; i < private_rmTextureGetNMipMaps(t); i++)
458     {
459 	RMimage *img;
460 	img = t->images[i];
461 	if (img != NULL)
462 	    rmImageDelete(img);
463 	t->images[i] = NULL;
464     }
465 
466     private_rmTextureSetNMipMaps(t, nimages);
467 
468     t->borderWidth = borderWidth;
469 
470     for (i = 0; i < private_rmTextureGetNMipMaps(t); i++)
471     {
472 	RMimage *img;
473 	img = rmImageDup(imagearray[i]);
474 	t->images[i] = img;
475     }
476 
477     private_rmTextureSetDataCacheKey(t);
478 
479     return(RM_CHILL);
480 }
481 
482 
483 /*
484  * ----------------------------------------------------
485  * @Name rmTextureGetImages
486  @pstart
487  RMenum rmTextureGetImages (RMtexture *toQuery,
488 		            RMimage **imageArray,
489 			    int *nimages,
490 			    int *borderWidth)
491  @pend
492 
493  @astart
494  RMtexture *toQuery - a handle to the RMtexture object to which image
495     texture data will be assigned (input).
496 
497  RMimage **imageArray - a handle to an array of RMimage objects that
498     will be assigned to the RMtexture object as texture data. This
499     list will not be modified by this routine.
500 
501  int *nimages, *borderWidth - handles to an integers (results).
502  @aend
503 
504  @dstart
505 
506  This routine is currently only a stub.
507 
508  @dend
509  Use this routine to read back the textures assigned to an RMtexture
510  object.
511 
512  Upon successful completion, RM_CHILL is returned and the number of
513  mipmaps, border width, and copies of the actual texture images are
514  returned to the caller.  Otherwise, RM_WHACKED is returned.
515 
516  * ----------------------------------------------------
517  */
518 RMenum
rmTextureGetImages(const RMtexture * t,RMimage *** imagearray,int * nimages,int * borderWidth)519 rmTextureGetImages (const RMtexture *t,
520 		    RMimage ***imagearray,
521 		    int *nimages,
522 		    int *borderWidth)
523 {
524     /* stub - implement! */
525     rmWarning("rmTextureGetImages is not yet implemented. \n");
526 
527     /* foil compiler warning */
528     t = NULL;
529     imagearray = NULL;
530     nimages = borderWidth = NULL;
531 
532     return(RM_CHILL);
533 }
534 
535 
536 /*
537  * ----------------------------------------------------
538  * @Name rmTextureSetFilterMode
539  @pstart
540  RMenum rmTextureSetFilterMode (RMtexture *toModify,
541 		                GLenum minMode,
542 			        GLenum magMode)
543  @pend
544 
545  @astart
546  RMtexture *toModify - handle to an RMtexture object (modified).
547 
548  GLenum minMode - a GLenum value specifying a texture minification
549     filter. May be one of GL_NEAREST, GL_LINEAR,
550     GL_NEAREST_MIPMAP_NEAREST, GL_NEAREST_MIPMAP_LINEAR,
551     GL_LINEAR_MIPMAP_NEAREST, GL_LINEAR_MIPMAP_LINEAR.
552 
553  GLenum magMode - a GLenum value specifying a texture magnification
554     filter.  May be one of GL_NEAREST or GL_LINEAR.
555  @aend
556 
557  @dstart
558 
559  Use this routine to set the texture filtering mode at of an RMtexture
560  object. Returns RM_CHILL upon success, or RM_WHACKED upon
561  failure. Note that the filter does not take effect until the texture
562  object has been placed into the scene graph using either
563  rmNodeSetSceneTexture or rmNodeUpdateSceneTexture.
564 
565  When texels project to screen pixels, they rarely cover an integral
566  number of pixels. The texture filtering mode is used to control how
567  texels are interpolated to screen pixels. When a screen pixel covers
568  a very small portion of the texture, the texture is said to be
569  magnified. Conversely, when the screen pixel covers multiple texels,
570  the texture is said to be minified.
571 
572  By default, the RMtexture object uses the minification and
573  magnification filters of GL_NEAREST, GL_NEAREST, respectively. These
574  filters favor performance over quality. The minification filter
575  modes, GL_NEAREST, GL_LINEAR, ... , GL_LINEAR_MIPMAP_LINEAR represent
576  increasing levels of interpolation quality, but at increasing
577  performance cost. Only two magnification filters, GL_NEAREST and
578  GL_LINEAR, are available inside OpenGL. Please see the OpenGL red
579  book for more information about texture filtering.
580 
581  @dend
582  * ----------------------------------------------------
583  */
584 RMenum
rmTextureSetFilterMode(RMtexture * t,GLenum min_mode,GLenum mag_mode)585 rmTextureSetFilterMode (RMtexture *t,
586 		        GLenum min_mode,
587 		        GLenum mag_mode)
588 {
589     if (RM_ASSERT(t, "rmTextureSetFilterMode() error: input texture is NULL. ") == RM_WHACKED)
590 	return(RM_WHACKED);
591 
592     t->min_filter_mode = min_mode;
593     t->mag_filter_mode = mag_mode;
594 
595     return(RM_CHILL);
596 }
597 
598 
599 /*
600  * ----------------------------------------------------
601  * @Name rmTextureGetFilterMode
602  @pstart
603  RMenum rmTextureGetFilterMode (const RMtexture *toQuery,
604 		                GLenum *minModeReturn,
605 			        GLenum *magModeReturn)
606  @pend
607 
608  @astart
609  const RMtexture *toQuery - a handle to an RMtexture object to query
610     (input).
611 
612  GLenum *minModeReturn, *magModeReturn - handles to GLenum's
613     (modified, return).
614  @aend
615 
616  @dstart
617 
618  Use this routine to get the texture filtering modes from an RMtexture
619  object.  Upon success, RM_CHILL is returned and the filtering modes
620  are copied from the RMtexture object into caller-supplied
621  memory. Otherwise, RM_WHACKED is returned.
622 
623  @dend
624  * ----------------------------------------------------
625  */
626 RMenum
rmTextureGetFilterMode(const RMtexture * t,GLenum * min_mode,GLenum * mag_mode)627 rmTextureGetFilterMode (const RMtexture *t,
628 		        GLenum *min_mode,
629 		        GLenum *mag_mode)
630 {
631     if (RM_ASSERT(t, "rmTextureGetFilterMode() error: input texture is NULL. ") == RM_WHACKED)
632 	return(RM_WHACKED);
633 
634     if (min_mode != NULL)
635 	*min_mode = t->min_filter_mode;
636 
637     if (mag_mode != NULL)
638 	*mag_mode = t->mag_filter_mode;
639 
640     return(RM_CHILL);
641 }
642 
643 
644 /*
645  * ----------------------------------------------------
646  * @Name rmTextureSetWrapMode
647  @pstart
648  RMenum rmTextureSetWrapMode (RMtexture *toModify,
649 		              GLenum wrapMode)
650  @pend
651 
652  @astart
653  RMtexture *toModify - a handle to an RMtexture object to modify
654     (modified).
655 
656  GLenum wrapMode - a GLenum specifying a texture wrap mode
657     (input). May be one of GL_CLAMP or GL_REPEAT (OpenGL 1.2 adds the
658     new texture wrap mode of GL_CLAMP_TO_EDGE).
659  @aend
660 
661  @dstart
662 
663  Use this routine to set the "wrap mode" of an RMtexture
664  object. Returns RM_CHILL upon success, or RM_WHACKED upon failure.
665 
666  By definition, texture coordinates range from 0.0 to 1.0, and define
667  a parametric index into a texture. The texture wrap mode comes into
668  play when texture coordinates go outside the range 0..1.
669 
670  When GL_CLAMP is used, texture coordinates greater than 1.0 are
671  clamped to 1.0, and those less than 0.0 are clamped to 0.0. Texture
672  coordinates within the range 0..1 remain unmodified.
673 
674  When GL_REPEAT is used, texture coordinates outside the range 0..1
675  are treated as if they were inside the range 0..1. The exact method
676  used to implement this interpretation is platform-dependent, but a
677  safe assumption is that most implementations ingore all but the
678  fractional part of the texture coordinate.
679 
680  Note that when GL_REPEAT is used, the texture border color is always
681  ignored (rmTextureSetEnv). Similarly, when the GL_NEAREST filtering
682  mode is used, the border color is also always ignored.
683 
684  Please refer to the OpenGL red book for more information about
685  texture wrapping.
686 
687  Note that the RM implementation allows specification of onlye a
688  single wrap mode. The one wrap mode is used for all texture
689  dimensions. In this API, it is not possible to specify different wrap
690  policies for each texture axis, although OpenGL does allow for this
691  possibility. This RM policy reflects a simplification to the OpenGL
692  API.
693 
694  @dend
695  * ----------------------------------------------------
696  */
697 RMenum
rmTextureSetWrapMode(RMtexture * t,GLenum wrap_mode)698 rmTextureSetWrapMode (RMtexture *t,
699 		      GLenum wrap_mode)
700 {
701     if (RM_ASSERT(t, "rmTextureSetWrapMode() error: input texture is NULL. ") == RM_WHACKED)
702 	return(RM_WHACKED);
703 
704     t->wrap_mode = wrap_mode;
705     return(RM_CHILL);
706 }
707 
708 
709 /*
710  * ----------------------------------------------------
711  * @Name rmTextureGetWrapMode
712  @pstart
713  RMenum rmTextureGetWrapMode (const RMtexture *toQuery,
714 		              GLenum *wrapModeReturn)
715  @pend
716 
717  @astart
718  const RMtexture *toQuery - a handle to an RMtexture object that will
719    be queried (input).
720 
721  GLenum *wrapModeReturn - a handle to a GLenum (result).
722  @aend
723 
724  @dstart
725 
726  Use this routine to obtain the texture wrap mode of an RMtexture
727  object.  Upon success, RM_CHILL is returned, and the texture wrap
728  mode is copied from the RMtexture object into the caller-supplied
729  GLenum. Otherwise, RM_WHACKED is returned.
730 
731  @dend
732  * ----------------------------------------------------
733  */
734 RMenum
rmTextureGetWrapMode(const RMtexture * t,GLenum * wrap_mode)735 rmTextureGetWrapMode (const RMtexture *t,
736 		      GLenum *wrap_mode)
737 {
738     if (RM_ASSERT(t, "rmTextureGetWrapMode() error: input texture is NULL. ") == RM_WHACKED)
739 	return(RM_WHACKED);
740 
741     if (wrap_mode != NULL)
742        *wrap_mode = t->wrap_mode;
743 
744     return(RM_CHILL);
745 }
746 
747 
748 /*
749  * ----------------------------------------------------
750  * @Name rmTextureSetEnv
751  @pstart
752  RMenum rmTextureSetEnv (RMtexture *toModify,
753 		         GLenum envMode,
754 			 const RMcolor4D *blendColor)
755  @pend
756 
757  @astart
758  RMtexture *toModify - a handle to an RMtexture object to modify
759     (modified).
760 
761  GLenum envMode - a GLenum value specifying one of several texture
762      mapping modes. May be one of GL_DECAL, GL_REPLACE, GL_MODULATE or
763      GL_BLEND (input).
764 
765  const RMcolor4D *blendColor - an handle to an RMcolor4D object (NULL
766      is acceptable) (input).
767  @aend
768 
769  @dstart
770 
771  Sets texture environment parameters in an RMtexture object. Returns
772  RM_CHILL upon success, or RM_WHACKED upon failure.
773 
774  The "texture environment" specifies how, precisely, the color of a
775  texture is combined with the color of a pixel fragment. Please refer
776  to the OpenGL Red Book for more information about the effect of each
777  of the texture environment modes GL_DECAL, GL_REPLACE, GL_MODULATE
778  and GL_BLEND.
779 
780  The blendColor parameter is optional, and takes effect only when
781  GL_BLEND is used for the texturing method. The default value for
782  blendColor when left unspecified by the application is (0,0,0,0).  If
783  blendColor is NULL, the existing blendColor in the RMtexture object,
784  if any, remains unmodified.
785 
786  @dend
787  * ----------------------------------------------------
788  */
789 RMenum
rmTextureSetEnv(RMtexture * t,GLenum envMode,const RMcolor4D * blendColor)790 rmTextureSetEnv (RMtexture *t,
791 		 GLenum envMode,
792 		 const RMcolor4D *blendColor)
793 {
794     if (RM_ASSERT(t, "rmTextureSetEnv() error: the input texture is NULL") == RM_WHACKED)
795 	return(RM_WHACKED);
796 
797     t->envMode = envMode;
798 
799     if (blendColor != NULL)
800     {
801 	if (t->blendColor != NULL)
802 	{
803 	    rmColor4DDelete(t->blendColor);
804 	    t->blendColor = NULL;
805 	}
806 
807 	t->blendColor = rmColor4DNew(1);
808 	*(t->blendColor) = *blendColor;
809     }
810     return(RM_CHILL);
811 }
812 
813 
814 /*
815  * ----------------------------------------------------
816  * @Name rmTextureGetEnv
817  @pstart
818  RMenum rmTextureGetEnv (const RMtexture *toQuery,
819 		         GLenum *envModeReturn,
820 			 RMcolor4D *blendColorReturn)
821  @pend
822 
823  @astart
824  const RMtexture *toQuery - a handle to an RMtexture object (input).
825 
826  GLenum *envModeReturn - a handle to a GLenum (return).
827 
828  RMcolor4D *blendColorReturn - a handle to an RMcolor4D object
829     (return).
830  @aend
831 
832  @dstart
833 
834  Use this routine to obtain the texture environment parameters of an
835  RMtexture object. Upon success, RM_CHILL is returned, and the texture
836  environment mode and blend color are copied into caller-supplied
837  memory. Otherwise, RM_WHACKED is returned.
838 
839  @dend
840  * ----------------------------------------------------
841  */
842 RMenum
rmTextureGetEnv(const RMtexture * t,GLenum * envMode,RMcolor4D * blendColor)843 rmTextureGetEnv (const RMtexture *t,
844 		 GLenum *envMode,
845 		 RMcolor4D *blendColor)
846 {
847     if (RM_ASSERT(t, "rmTextureGetEnv() error: the input texture is NULL") == RM_WHACKED)
848 	return(RM_WHACKED);
849 
850     if (envMode != NULL)
851 	*envMode = t->envMode;
852 
853     if (blendColor != NULL && t->blendColor != NULL)
854 	*blendColor = *(t->blendColor);
855 
856     return(RM_CHILL);
857 }
858 
859 
860 /*
861  * ----------------------------------------------------
862  * @Name rmTextureSetGLTexelFormat
863  @pstart
864  RMenum rmTextureSetGLTexelFormat (RMtexture *toModify,
865 			           GLenum internalTexelFormat)
866  @pend
867 
868  @astart
869  RMtexture *toModify - a handle to an RMtexture object (modified).
870 
871  GLenum internalTexelFormat - a GLenum pixel format descriptor. See
872     below for acceptable values (input).
873  @aend
874 
875  @dstart
876 
877  Use this routine to tell OpenGL how texture pixel data will be stored
878  in OpenGL texture memory. Returns RM_CHILL upon success, or
879  RM_WHACKED upon failure.
880 
881  The permissible values for internalTexelFormat are a function of the
882  particular OpenGL implementation that you are using. The set of
883  GL_LUMINANCE, GL_LUMINANCE_ALPHA, GL_RGB, GL_RGBA are supported
884  across all implementations. Some implementations support more
885  specific values, such as GL_RGBA4, meaning that 4 bits of space are
886  used for each of the R, G, B and A components of the texture.
887 
888  OpenGL converts from the source image format (in the RMimage object)
889  to the format requested by this routine. The application need not be
890  concerned with performing this pixel reformatting.
891 
892  By default, RM uses GL_RGBA unless overridden by the application's
893  use of this routine.
894 
895  @dend
896  * ----------------------------------------------------
897  */
898 RMenum
rmTextureSetGLTexelFormat(RMtexture * t,GLenum texelFormat)899 rmTextureSetGLTexelFormat (RMtexture *t,
900 			   GLenum texelFormat)
901 {
902     if (RM_ASSERT(t, "rmTextureSetGLTexelFormat error: the input RMtexture pointer is NULL") == RM_WHACKED)
903 	return(RM_WHACKED);
904 
905     if (t->oglTexelFormat == NULL)
906 	t->oglTexelFormat = (GLenum *)malloc(sizeof(GLenum));
907 
908     *(t->oglTexelFormat) = texelFormat;
909 
910     return(RM_CHILL);
911 }
912 
913 
914 /*
915  * ----------------------------------------------------
916  * @Name rmTextureGetGLTexelFormat
917  @pstart
918  RMenum rmTextureGetGLTexelFormat (const RMtexture *toQuery,
919 			           GLenum *returnTexelFormat)
920  @pend
921 
922  @astart
923  const RMtexture *toQuery - a handle to an RMtexture object (input).
924 
925  GLenum *returnTexelFormat - a handle to a GLenum value (return).
926  @aend
927 
928  @dstart
929 
930  Use this routine to obtain the texel storage format used by the
931  RMtexture object toQuery. Upon success, the texel storage format will
932  be copied into caller-supplied memory and RM_CHILL will be
933  returned. Otherwise, RM_WHACKED is returned.
934 
935  @dend
936  * ----------------------------------------------------
937  */
938 RMenum
rmTextureGetGLTexelFormat(const RMtexture * t,GLenum * returnTexelFormat)939 rmTextureGetGLTexelFormat (const RMtexture *t,
940 			   GLenum *returnTexelFormat)
941 {
942     if ((RM_ASSERT(t, "rmTextureGetGLTexelFormat error: the input RMtexture pointer is NULL") == RM_WHACKED) ||
943 	(RM_ASSERT(returnTexelFormat, "rmTextureGLGetTexelFormat error: the return texel format enumerator pointer is NULL.") == RM_WHACKED))
944 	return(RM_WHACKED);
945 
946     if (returnTexelFormat != NULL)
947     {
948 	if (t->oglTexelFormat == NULL)
949 	    return(RM_WHACKED);
950 	else
951 	{
952 	    *returnTexelFormat = *(t->oglTexelFormat);
953 	    return(RM_CHILL);
954 	}
955     }
956     return(RM_CHILL);
957 }
958 
959 /*
960  * ----------------------------------------------------
961  * @Name rmTextureGetTextureID
962  @pstart
963  RMenum rmTextureGetTextureID (const RMtexture *toQuery,
964 			       GLuint *returnTextureID)
965  @pend
966 
967  @astart
968  const RMtexture *toQuery - a handle to an RMtexture object (input).
969  GLuint *returnTetureID - a handle to a GLuint, application-provided memory (result).
970  @aend
971 
972  @dstart
973 
974  Use this routine to obtain the GL textureID handle associated with an
975  RMtexture as specified by an earlier call to rmTextureSetTextureID.
976  This routine does NOT return the GL textureID for textures built and
977  managed by OpenRM/RM.
978 
979  Upon success, this routine returns RM_CHILL, and the value of the
980  application-supplied GL textureID will be copied into caller-supplied
981  memory. Upon failure, RM_WHACKED is returned, and caller-supplied memory
982  remains unmodified.
983 
984  See the documentation for rmTextureSetTextureID for more information about
985  application-supplied textures.
986 
987  @dend
988  * ----------------------------------------------------
989  */
990 RMenum
rmTextureGetTextureID(const RMtexture * toQuery,GLuint * returnTextureID)991 rmTextureGetTextureID (const RMtexture *toQuery,
992 		       GLuint *returnTextureID)
993 {
994     if ((RM_ASSERT(toQuery, "rmTextureGetTextureID error: the input RMtexture pointer is NULL") == RM_WHACKED) ||
995 	(RM_ASSERT(returnTextureID, "rmTextureGetTextureID error: the returnTextureID parameter is NULL")))
996 	return RM_WHACKED;
997 
998     if (toQuery->appTextureID == NULL)
999 	return RM_WHACKED;
1000 
1001     *returnTextureID = *(toQuery->appTextureID);
1002 
1003     return RM_CHILL;
1004 }
1005 
1006 /*
1007  * ----------------------------------------------------
1008  * @Name rmTextureSetTextureID
1009  @pstart
1010  RMenum rmTextureSetTextureID (RMtexture *toModify,
1011 			       GLuint *textureID)
1012  @pend
1013 
1014  @astart
1015  RMtexture *toModify - a handle to an RMtexture object (input).
1016  GLuint *textureID - a pointer to a GLuint texture ID (input).
1017  @aend
1018 
1019  @dstart
1020 
1021  Use this routine to assign an application-generated GL texture ID to an
1022  RMtexture object in lieu of providing RMimage texel data with
1023  rmTextureSetImages. The intent of this approach to texturing is to help
1024  support those applications that use third-party tools to create and
1025  load textures to OpenGL external to OpenRM.
1026 
1027  You may specify a value of NULL for the textureID parameter, in which
1028  case the application-supplied textureID field will be removed from the
1029  RMtexture object "toModify."
1030 
1031  This routine returns RM_CHILL upon success, and RM_WHACKED upon failure.
1032 
1033  The procedure to use for texturing with application-supplied textures
1034  is as follows:
1035  1. (Required) Create the RMtexture with rmTextureNew(ndims). Use ndims=1
1036  for 1D textures, 2 for 2D textures or 3 for 3D textures.
1037  2. (Optional) Specify texturing environment parameters using rmTextureSet*
1038  routines.
1039  3. (Required) Assign the application-supplied GL texture ID with
1040  rmTextureSetTextureID.
1041  4. (Required) Assign the RMtexture as a scene parameter to an RMnode.
1042 
1043  The application-supplied texture must be created only after OpenGL is
1044  active, which means that an OpenGL context has been created and made
1045  current. Usually, this set of conditions is met after the application
1046  makes a call to rmPipeMakeCurrent().
1047 
1048  Also note that your RMprimitive must have texture coordinates of the
1049  "same species" as the GL texture. In other words, use 1D texture coordinates
1050  with 1D textures, and so forth.
1051 
1052  @dend
1053  * ----------------------------------------------------
1054  */
1055 RMenum
rmTextureSetTextureID(RMtexture * toModify,GLuint * textureID)1056 rmTextureSetTextureID (RMtexture *toModify,
1057 		       GLuint *textureID)
1058 {
1059     if (RM_ASSERT(toModify, "rmTextureSetTextureID error: the input RMtexture pointer is NULL") == RM_WHACKED)
1060 	return RM_WHACKED;
1061 
1062     /*
1063      * While we can't check for a valid GL texture ID right now, since
1064      * we might not be the rendering thread or have an active, bound OpenGL
1065      * context, we can check for obviously bogus values.
1066      */
1067 
1068     if ((textureID == NULL) || (*textureID <= 0))
1069     {
1070 	rmError("rmTextureSetTextureID() error - the input textureID value is less than or equal to zero. ");
1071 	return RM_WHACKED;
1072     }
1073 
1074     if (toModify->appTextureID != NULL)
1075     {
1076 	free((void *)(toModify->appTextureID));
1077 	toModify->appTextureID = NULL;
1078     }
1079 
1080     if (textureID != NULL)
1081     {
1082 	if ((toModify->appTextureID = (GLuint *)private_rmMemDup((void *)textureID, sizeof(GLuint))) == NULL)
1083 	    return RM_WHACKED;
1084     }
1085 
1086     return RM_CHILL;
1087 }
1088 
1089 /*
1090  * PRIVATE
1091  * download 3D textures to OpenGL
1092  */
1093 void
private_rmTexture3DDownload(RMpipe * p,RMtexture * t,int isNew)1094 private_rmTexture3DDownload(RMpipe *p,
1095 			    RMtexture *t,
1096 			    int isNew)
1097 {
1098     RMvisMap *vmap=NULL;
1099     GLenum srcGLTexelFormat, dstGLTexelFormat;
1100     int i;
1101 
1102     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_S, t->wrap_mode);
1103     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_T, t->wrap_mode);
1104     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_WRAP_R_EXT, t->wrap_mode);
1105     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAG_FILTER, t->mag_filter_mode);
1106     glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MIN_FILTER, t->min_filter_mode);
1107 
1108     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, t->envMode);
1109 
1110     if (t->blendColor != NULL)
1111 	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat *)(t->blendColor));
1112 
1113     for (i = 0; i < private_rmTextureGetNMipMaps(t); i++)
1114     {
1115 	int w,h,d;
1116 
1117 	if (t->images[i] == NULL)
1118 	{
1119 	    char buf[128];
1120 	    sprintf(buf," the RMimage at mipmap level %d for a 3D texture is missing. The texture download likely did not succeed, and your texturing will not be correct. \n",i);
1121 	    rmError(buf);
1122 	    break; /* exit the loop over mipmaps */
1123 	}
1124 
1125 	vmap = private_rmImageGetVismap(t->images[i]);
1126 
1127 	/* convert between RM and OpenGL type enumerators */
1128 	srcGLTexelFormat = private_rmImageGetOGLFormat(t->images[i]);
1129 	rmTextureGetGLTexelFormat(t, &dstGLTexelFormat);
1130 
1131 	if (vmap != NULL)
1132 	    private_rmSetPixelTransferMode(vmap);
1133 	else
1134 	    private_rmUnsetPixelTransferMode();
1135 
1136 	rmImageGetImageSize(t->images[i], NULL, &w, &h, &d, NULL, NULL);
1137 
1138 	/* updates to allow for non-byte input texel data 2/19/02 */
1139 	if (isNew == 1)
1140 	{
1141 	    if (p->caps->rm_glTexImage3D != NULL)
1142 		(*(p->caps->rm_glTexImage3D))(GL_TEXTURE_3D, i, dstGLTexelFormat, w, h, d, t->borderWidth, srcGLTexelFormat, private_rmImageGetOGLType(t->images[i]), (const GLvoid *)(private_rmImageGetPixelData(t->images[i])));
1143 #if 0
1144 	    glTexImage3D(GL_TEXTURE_3D, i, dstGLTexelFormat, w, h, d, t->borderWidth, srcGLTexelFormat, private_rmImageGetOGLType(t->images[i]), (const GLvoid *)(private_rmImageGetPixelData(t->images[i])));
1145 #else
1146 #endif
1147 	    rmGLGetError(" while loading 3D texture(s) ");
1148 	}
1149 	else
1150 	{
1151 #if 0
1152 	    glTexSubImage3D(GL_TEXTURE_3D, i, 0, 0, 0, w, h, d, srcGLTexelFormat, private_rmImageGetOGLType(t->images[0]), (const GLvoid *)(private_rmImageGetPixelData(t->images[i])));
1153 #else
1154 #endif
1155 	    rmGLGetError(" while loading 3D subtexture(s) ");
1156 	}
1157     }
1158 
1159     private_rmUnsetPixelTransferMode();
1160 }
1161 
1162 /*
1163  * PRIVATE
1164  * download 2D textures to OpenGL
1165  */
1166 void
private_rmTexture2DDownload(RMtexture * t,int isNew)1167 private_rmTexture2DDownload(RMtexture *t,
1168 			    int isNew)
1169 {
1170     RMvisMap *vmap=NULL;
1171     GLenum srcGLTexelFormat, dstGLTexelFormat;
1172     int i;
1173 
1174     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, t->wrap_mode);
1175     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, t->wrap_mode);
1176 
1177     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, t->mag_filter_mode);
1178     glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, t->min_filter_mode);
1179 
1180 /*    glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, t->envMode); */
1181 
1182     if (t->blendColor != NULL)
1183 	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat *)(t->blendColor));
1184 
1185     for (i = 0; i < private_rmTextureGetNMipMaps(t); i++)
1186     {
1187 	int w,h;
1188 
1189 	if (t->images[i] == NULL)
1190 	{
1191 	    char buf[128];
1192 	    sprintf(buf," the RMimage at mipmap level %d for a 2D texture is missing. The texture download likely did not succeed, and your texturing will not be correct. \n",i);
1193 	    rmError(buf);
1194 	    break; /* exit the loop over mipmaps */
1195 	}
1196 
1197 	vmap = private_rmImageGetVismap(t->images[i]);
1198 
1199 	/* convert between RM and OpenGL type enumerators */
1200 	srcGLTexelFormat = private_rmImageGetOGLFormat(t->images[i]);
1201 	rmTextureGetGLTexelFormat(t, &dstGLTexelFormat);
1202 
1203 	if (vmap != NULL)
1204 	    private_rmSetPixelTransferMode(vmap);
1205 #if 1
1206 	else
1207 	    private_rmUnsetPixelTransferMode();
1208 #else
1209 	fprintf(stderr,"private_rmTexture2DDownload() - temporarily disabling rmUnsetPixelTransferMode prior to texel download.");
1210 	fflush(stderr);
1211 #endif
1212 
1213 	rmImageGetImageSize(t->images[i], NULL, &w, &h, NULL, NULL, NULL);
1214 
1215 	if (isNew == 1)
1216 	{
1217 	    glTexImage2D(GL_TEXTURE_2D, i, dstGLTexelFormat, w, h, t->borderWidth, srcGLTexelFormat, private_rmImageGetOGLType(t->images[i]), (const GLvoid *)(private_rmImageGetPixelData(t->images[i])));
1218 	    rmGLGetError(" while loading 2D texture(s) ");
1219 	}
1220 	else
1221 	{
1222 	    glTexSubImage2D(GL_TEXTURE_2D, i, 0, 0, w, h, srcGLTexelFormat, private_rmImageGetOGLType(t->images[0]), (const GLvoid *)(private_rmImageGetPixelData(t->images[i])));
1223 	    rmGLGetError(" while loading 2D subtexture(s) ");
1224 	}
1225     }
1226 
1227     private_rmUnsetPixelTransferMode();
1228 }
1229 
1230 /*
1231  * PRIVATE
1232  * download 1D textures to OpenGL
1233  */
1234 void
private_rmTexture1DDownload(RMtexture * t,int isNew)1235 private_rmTexture1DDownload(RMtexture *t,
1236 			    int isNew)
1237 {
1238     RMvisMap *vmap=NULL;
1239     GLenum srcGLTexelFormat, dstGLTexelFormat;
1240     int i;
1241 
1242     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, t->wrap_mode);
1243 
1244     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, t->mag_filter_mode);
1245     glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, t->min_filter_mode);
1246 
1247 
1248     if (t->blendColor != NULL)
1249 	glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, (GLfloat *)(t->blendColor));
1250 
1251     for (i = 0; i < private_rmTextureGetNMipMaps(t); i++)
1252     {
1253 	int w;
1254 
1255 	if (t->images[i] == NULL)
1256 	{
1257 	    char buf[128];
1258 	    sprintf(buf," the RMimage at mipmap level %d for a 2D texture is missing. The texture download likely did not succeed, and your texturing will not be correct. \n",i);
1259 	    rmError(buf);
1260 	    break; /* exit the loop over mipmaps */
1261 	}
1262 
1263 	vmap = private_rmImageGetVismap(t->images[i]);
1264 
1265 	/* convert between RM and OpenGL type enumerators */
1266 	srcGLTexelFormat = private_rmImageGetOGLFormat(t->images[i]);
1267 	rmTextureGetGLTexelFormat(t, &dstGLTexelFormat);
1268 
1269 	if (vmap != NULL)
1270 	    private_rmSetPixelTransferMode(vmap);
1271 #if 1
1272 	else
1273 	    private_rmUnsetPixelTransferMode();
1274 #else
1275 	fprintf(stderr,"private_rmTexture2DDownload() - temporarily disabling rmUnsetPixelTransferMode prior to texel download.");
1276 	fflush(stderr);
1277 #endif
1278 
1279 	rmImageGetImageSize(t->images[i], NULL, &w, NULL, NULL, NULL, NULL);
1280 
1281 	if (isNew == 1)
1282 	{
1283 	    glTexImage1D(GL_TEXTURE_1D, i, dstGLTexelFormat, w, t->borderWidth, srcGLTexelFormat, private_rmImageGetOGLType(t->images[i]), (const GLvoid *)(private_rmImageGetPixelData(t->images[i])));
1284 	    rmGLGetError(" while loading 1D texture(s) ");
1285 	}
1286 	else
1287 	{
1288 	    glTexSubImage1D(GL_TEXTURE_2D, i, 0, w, srcGLTexelFormat, private_rmImageGetOGLType(t->images[0]), (const GLvoid *)(private_rmImageGetPixelData(t->images[i])));
1289 	    rmGLGetError(" while loading 2D subtexture(s) ");
1290 	}
1291     }
1292 
1293     private_rmUnsetPixelTransferMode();
1294 }
1295 
1296 /* PRIVATE
1297  *
1298  * internal routine to push texture data over to OpenGL
1299  */
1300 void
private_rmTextureToOGL(RMpipe * p,RMtexture * t,int isNew)1301 private_rmTextureToOGL (RMpipe *p,
1302 			RMtexture *t,
1303 		        int isNew)
1304 {
1305     if (RM_ASSERT(t->images[0], "an RMtexture was encountered for which no RMimage data has been assigned.") == RM_WHACKED)
1306 	return;
1307 
1308     switch(private_rmTextureGetDims(t))
1309     {
1310     case 3:
1311 	private_rmTexture3DDownload(p, t, isNew);
1312 	break;
1313 
1314     case 2:
1315 	private_rmTexture2DDownload(t, isNew);
1316 	break;
1317 
1318     case 1:
1319 	private_rmTexture1DDownload(t, isNew);
1320 	break;
1321 
1322     default:
1323 	rmError("private_rmTextureToOGL error - the input RMtexture is not 1D, 2D or 3D.");
1324 	break;
1325     }
1326 }
1327 
1328 
1329 /* PRIVATE */
1330 void
private_rmSetPixelTransferMode(const RMvisMap * vm)1331 private_rmSetPixelTransferMode (const RMvisMap *vm)
1332 {
1333     int n;
1334 
1335     if (RM_ASSERT(vm, "private_rmSetPixelTranserMode error: the input colormap is NULL.") == RM_WHACKED)
1336 	return;
1337 
1338     glPixelTransferi(GL_MAP_COLOR, GL_TRUE);
1339 
1340     n = rmVismapGetSize(vm);
1341 
1342     glPixelMapfv(GL_PIXEL_MAP_R_TO_R, n, vm->r);
1343     glPixelMapfv(GL_PIXEL_MAP_G_TO_G, n, vm->g);
1344     glPixelMapfv(GL_PIXEL_MAP_B_TO_B, n, vm->b);
1345     glPixelMapfv(GL_PIXEL_MAP_A_TO_A, n, vm->a);
1346 
1347 }
1348 
1349 
1350 /* PRIVATE */
1351 void
private_rmUnsetPixelTransferMode(void)1352 private_rmUnsetPixelTransferMode (void)
1353 {
1354     glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
1355 
1356 #if 0
1357     /* 1/26/03 - just turn off pixel transfer. No need to set the
1358        map sizes to zero with NULL values, because doing so can cause
1359        an OpenGL error */
1360     glPixelMapfv(GL_PIXEL_MAP_R_TO_R, 0, NULL);
1361     glPixelMapfv(GL_PIXEL_MAP_G_TO_G, 0, NULL);
1362     glPixelMapfv(GL_PIXEL_MAP_B_TO_B, 0, NULL);
1363     glPixelMapfv(GL_PIXEL_MAP_A_TO_A, 0, NULL);
1364 #endif
1365 }
1366 
1367 /* PRIVATE */
1368 /*
1369  * an RMtexture's "reference count" indicates the number of times a given
1370  * RMtexture is used as a shared texture scene parameter at an RMnode.
1371  * When an RMtexture is added as a shared texture scene parameter, the
1372  * RMtexture's reference counter is automatically incremented, and when
1373  * the shared RMtexture scene parameter is removed, it is decremented.
1374  * Deleting RMtextures is prohibited when the RMtexture's reference count
1375  * is a positive integer.
1376  */
1377 void
private_rmTextureSetRefCount(RMtexture * t,int newVal)1378 private_rmTextureSetRefCount(RMtexture *t,
1379 			     int newVal)
1380 {
1381     t->refCount = newVal;
1382 }
1383 
1384 /* PRIVATE */
1385 int
private_rmTextureGetRefCount(const RMtexture * t)1386 private_rmTextureGetRefCount(const RMtexture *t)
1387 {
1388     return t->refCount;
1389 }
1390 
1391 
1392 /* EOF */
1393