Browse Source

straighten out some confusing texture interfaces

David Rose 20 years ago
parent
commit
7d8cbc7a10
34 changed files with 2142 additions and 2390 deletions
  1. 18 21
      panda/src/display/graphicsStateGuardian.cxx
  2. 0 1
      panda/src/display/graphicsStateGuardian.h
  3. 10 25
      panda/src/dxgsg7/dxGraphicsStateGuardian7.cxx
  4. 3 5
      panda/src/dxgsg7/dxGraphicsStateGuardian7.h
  5. 14 22
      panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx
  6. 3 5
      panda/src/dxgsg8/dxGraphicsStateGuardian8.h
  7. 11 22
      panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx
  8. 3 5
      panda/src/dxgsg9/dxGraphicsStateGuardian9.h
  9. 1711 1741
      panda/src/glstuff/glGraphicsStateGuardian_src.cxx
  10. 9 12
      panda/src/glstuff/glGraphicsStateGuardian_src.h
  11. 0 1
      panda/src/glstuff/glTextureContext_src.I
  12. 0 3
      panda/src/glstuff/glTextureContext_src.h
  13. 8 4
      panda/src/gobj/texture.I
  14. 16 9
      panda/src/gobj/texture.cxx
  15. 1 1
      panda/src/gobj/texture.h
  16. 1 1
      panda/src/gobj/textureContext.I
  17. 0 3
      panda/src/gsgbase/graphicsStateGuardianBase.h
  18. 0 3
      panda/src/pgraph/Sources.pp
  19. 0 3
      panda/src/pgraph/config_pgraph.cxx
  20. 12 6
      panda/src/pgraph/lensNode.I
  21. 40 4
      panda/src/pgraph/lensNode.cxx
  22. 4 0
      panda/src/pgraph/lensNode.h
  23. 0 1
      panda/src/pgraph/pgraph_composite4.cxx
  24. 48 74
      panda/src/pgraph/spotlight.cxx
  25. 3 2
      panda/src/pgraph/spotlight.h
  26. 0 40
      panda/src/pgraph/textureApplyAttrib.I
  27. 0 179
      panda/src/pgraph/textureApplyAttrib.cxx
  28. 0 95
      panda/src/pgraph/textureApplyAttrib.h
  29. 106 57
      panda/src/pnmimage/pnmImage.I
  30. 84 21
      panda/src/pnmimage/pnmImage.cxx
  31. 7 0
      panda/src/pnmimage/pnmImage.h
  32. 16 16
      panda/src/pnmimage/pnmImageHeader.I
  33. 7 7
      panda/src/pnmimage/pnmImageHeader.cxx
  34. 7 1
      panda/src/wgldisplay/wglGraphicsStateGuardian.cxx

+ 18 - 21
panda/src/display/graphicsStateGuardian.cxx

@@ -252,34 +252,27 @@ get_prepared_objects() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::prepare_texture
 //     Function: GraphicsStateGuardian::prepare_texture
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: Prepares the indicated texture for retained-mode
-//               rendering.  In the future, this texture may be
-//               applied simply by calling apply_texture() with the
-//               value returned by this function.
+//  Description: Creates whatever structures the GSG requires to
+//               represent the texture internally, and returns a
+//               newly-allocated TextureContext object with this data.
+//               It is the responsibility of the calling function to
+//               later call release_texture() with this same pointer
+//               (which will also delete the pointer).
+//
+//               This function should not be called directly to
+//               prepare a texture.  Instead, call Texture::prepare().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TextureContext *GraphicsStateGuardian::
 TextureContext *GraphicsStateGuardian::
 prepare_texture(Texture *) {
 prepare_texture(Texture *) {
   return (TextureContext *)NULL;
   return (TextureContext *)NULL;
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GraphicsStateGuardian::apply_texture
-//       Access: Public, Virtual
-//  Description: Applies the texture previously indicated via a call
-//               to prepare_texture() to the graphics state, so that
-//               geometry rendered in the future will be rendered with
-//               the given texture.
-////////////////////////////////////////////////////////////////////
-void GraphicsStateGuardian::
-apply_texture(TextureContext *, int index) {
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::release_texture
 //     Function: GraphicsStateGuardian::release_texture
 //       Access: Public, Virtual
 //       Access: Public, Virtual
 //  Description: Frees the resources previously allocated via a call
 //  Description: Frees the resources previously allocated via a call
 //               to prepare_texture(), including deleting the
 //               to prepare_texture(), including deleting the
-//               TextureContext itself, if necessary.
+//               TextureContext itself, if it is non-NULL.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 void GraphicsStateGuardian::
 release_texture(TextureContext *) {
 release_texture(TextureContext *) {
@@ -289,9 +282,10 @@ release_texture(TextureContext *) {
 //     Function: GraphicsStateGuardian::prepare_geom
 //     Function: GraphicsStateGuardian::prepare_geom
 //       Access: Public, Virtual
 //       Access: Public, Virtual
 //  Description: Prepares the indicated Geom for retained-mode
 //  Description: Prepares the indicated Geom for retained-mode
-//               rendering.  The value returned by this function will
-//               be passed back into future calls to draw_tristrip(),
-//               etc., along with the Geom pointer.
+//               rendering, by creating whatever structures are
+//               necessary in the GSG (for instance, vertex buffers).
+//               Returns the newly-allocated GeomContext that can be
+//               used to render the geom.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GeomContext *GraphicsStateGuardian::
 GeomContext *GraphicsStateGuardian::
 prepare_geom(Geom *) {
 prepare_geom(Geom *) {
@@ -303,7 +297,10 @@ prepare_geom(Geom *) {
 //       Access: Public, Virtual
 //       Access: Public, Virtual
 //  Description: Frees the resources previously allocated via a call
 //  Description: Frees the resources previously allocated via a call
 //               to prepare_geom(), including deleting the GeomContext
 //               to prepare_geom(), including deleting the GeomContext
-//               itself, if necessary.
+//               itself, if it is non-NULL.
+//
+//               This function should not be called directly to
+//               prepare a Geom.  Instead, call Geom::prepare().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void GraphicsStateGuardian::
 void GraphicsStateGuardian::
 release_geom(GeomContext *) {
 release_geom(GeomContext *) {

+ 0 - 1
panda/src/display/graphicsStateGuardian.h

@@ -107,7 +107,6 @@ public:
   virtual PreparedGraphicsObjects *get_prepared_objects();
   virtual PreparedGraphicsObjects *get_prepared_objects();
 
 
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual TextureContext *prepare_texture(Texture *tex);
-  virtual void apply_texture(TextureContext *tc, int index=0);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
 
 
   virtual GeomContext *prepare_geom(Geom *geom);
   virtual GeomContext *prepare_geom(Geom *geom);

+ 10 - 25
panda/src/dxgsg7/dxGraphicsStateGuardian7.cxx

@@ -598,7 +598,7 @@ dx_init( void) {
     // must do SetTSS here because redundant states are filtered out by our code based on current values above, so
     // must do SetTSS here because redundant states are filtered out by our code based on current values above, so
     // initial conditions must be correct
     // initial conditions must be correct
 
 
-    _CurTexBlendMode = TextureApplyAttrib::M_modulate;
+    _CurTexBlendMode = TextureStage::M_modulate;
     SetTextureBlendMode(_CurTexBlendMode,FALSE);
     SetTextureBlendMode(_CurTexBlendMode,FALSE);
     _texturing_enabled = false;
     _texturing_enabled = false;
     _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);  // disables texturing
     _pScrn->pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);  // disables texturing
@@ -1749,9 +1749,7 @@ draw_sprite(GeomSprite *geom, GeomContext *gc) {
     Texture *tex = geom->get_texture();
     Texture *tex = geom->get_texture();
     if(tex !=NULL) {
     if(tex !=NULL) {
       // set up the texture-rendering state
       // set up the texture-rendering state
-      modify_state(RenderState::make
-                   (TextureAttrib::make(tex),
-                    TextureApplyAttrib::make(TextureApplyAttrib::M_modulate)));
+      modify_state(RenderState::make(TextureAttrib::make(tex)));
       tex_xsize = tex->get_x_size();
       tex_xsize = tex->get_x_size();
       tex_ysize = tex->get_y_size();
       tex_ysize = tex->get_y_size();
     }
     }
@@ -3315,7 +3313,7 @@ prepare_texture(Texture *tex) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian7::apply_texture
 //     Function: DXGraphicsStateGuardian7::apply_texture
-//       Access: Public, Virtual
+//       Access: Public
 //  Description: Makes the texture the currently available texture for
 //  Description: Makes the texture the currently available texture for
 //               rendering.
 //               rendering.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -3583,13 +3581,9 @@ apply_fog(Fog *fog) {
   }
   }
 }
 }
 
 
-void DXGraphicsStateGuardian7::SetTextureBlendMode(TextureApplyAttrib::Mode TexBlendMode,bool bCanJustEnable) {
+void DXGraphicsStateGuardian7::SetTextureBlendMode(TextureStage::Mode TexBlendMode,bool bCanJustEnable) {
 
 
-/*class TextureApplyAttrib {
-  enum Mode {
-    M_modulate,M_decal,M_blend,M_replace,M_add};
-*/
-    static D3DTEXTUREOP TexBlendColorOp1[/* TextureApplyAttrib::Mode maxval*/ 10] =
+    static D3DTEXTUREOP TexBlendColorOp1[/* TextureStage::Mode maxval*/ 10] =
     {D3DTOP_MODULATE,D3DTOP_BLENDTEXTUREALPHA,D3DTOP_MODULATE,D3DTOP_SELECTARG1,D3DTOP_ADD};
     {D3DTOP_MODULATE,D3DTOP_BLENDTEXTUREALPHA,D3DTOP_MODULATE,D3DTOP_SELECTARG1,D3DTOP_ADD};
 
 
     //if bCanJustEnable, then we only need to make sure ColorOp is turned on and set properly
     //if bCanJustEnable, then we only need to make sure ColorOp is turned on and set properly
@@ -3603,7 +3597,7 @@ void DXGraphicsStateGuardian7::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
 
 
     switch (TexBlendMode) {
     switch (TexBlendMode) {
 
 
-        case TextureApplyAttrib::M_modulate:
+        case TextureStage::M_modulate:
             // emulates GL_MODULATE glTexEnv mode
             // emulates GL_MODULATE glTexEnv mode
             // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv)
             // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv)
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
@@ -3613,7 +3607,7 @@ void DXGraphicsStateGuardian7::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
 
 
             break;
             break;
-        case TextureApplyAttrib::M_decal:
+        case TextureStage::M_decal:
             // emulates GL_DECAL glTexEnv mode
             // emulates GL_DECAL glTexEnv mode
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
@@ -3622,13 +3616,13 @@ void DXGraphicsStateGuardian7::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
 
 
             break;
             break;
-        case TextureApplyAttrib::M_replace:
+        case TextureStage::M_replace:
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
 
 
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
             break;
             break;
-        case TextureApplyAttrib::M_add:
+        case TextureStage::M_add:
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
 
 
@@ -3638,7 +3632,7 @@ void DXGraphicsStateGuardian7::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
             _pScrn->pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
 
 
             break;
             break;
-        case TextureApplyAttrib::M_blend:
+        case TextureStage::M_blend:
             dxgsg7_cat.error()
             dxgsg7_cat.error()
             << "Impossible to emulate GL_BLEND in DX exactly " << (int) TexBlendMode << endl;
             << "Impossible to emulate GL_BLEND in DX exactly " << (int) TexBlendMode << endl;
 /*
 /*
@@ -3845,15 +3839,6 @@ issue_rescale_normal(const RescaleNormalAttrib *attrib) {
   }
   }
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian7::issue_texture_apply
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian7::
-issue_texture_apply(const TextureApplyAttrib *attrib) {
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian7::issue_depth_test
 //     Function: DXGraphicsStateGuardian7::issue_depth_test
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 3 - 5
panda/src/dxgsg7/dxGraphicsStateGuardian7.h

@@ -32,7 +32,6 @@
 #include "material.h"
 #include "material.h"
 #include "depthTestAttrib.h"
 #include "depthTestAttrib.h"
 #include "renderModeAttrib.h"
 #include "renderModeAttrib.h"
-#include "textureApplyAttrib.h"
 #include "fog.h"
 #include "fog.h"
 #include "pointerToArray.h"
 #include "pointerToArray.h"
 #include "graphicsWindow.h"
 #include "graphicsWindow.h"
@@ -88,7 +87,7 @@ public:
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
 
 
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual TextureContext *prepare_texture(Texture *tex);
-  virtual void apply_texture(TextureContext *tc);
+  void apply_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
 
 
   virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
@@ -106,7 +105,6 @@ public:
   virtual void issue_material(const MaterialAttrib *attrib);
   virtual void issue_material(const MaterialAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
-  virtual void issue_texture_apply(const TextureApplyAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
   virtual void issue_depth_test(const DepthTestAttrib *attrib);
   virtual void issue_depth_test(const DepthTestAttrib *attrib);
   virtual void issue_depth_write(const DepthWriteAttrib *attrib);
   virtual void issue_depth_write(const DepthWriteAttrib *attrib);
@@ -293,7 +291,7 @@ protected:
   // GraphicsChannel *_panda_gfx_channel;  // cache the 1 channel dx supports
   // GraphicsChannel *_panda_gfx_channel;  // cache the 1 channel dx supports
 
 
   // Cur Texture State
   // Cur Texture State
-  TextureApplyAttrib::Mode _CurTexBlendMode;
+  TextureStage::Mode _CurTexBlendMode;
   D3DTEXTUREMAGFILTER _CurTexMagFilter;
   D3DTEXTUREMAGFILTER _CurTexMagFilter;
   D3DTEXTUREMINFILTER _CurTexMinFilter;
   D3DTEXTUREMINFILTER _CurTexMinFilter;
   D3DTEXTUREMIPFILTER _CurTexMipFilter;
   D3DTEXTUREMIPFILTER _CurTexMipFilter;
@@ -332,7 +330,7 @@ public:
   void adjust_view_rect(int x, int y);
   void adjust_view_rect(int x, int y);
   INLINE void SetDXReady(bool stat)  {  _dx_ready = stat; }
   INLINE void SetDXReady(bool stat)  {  _dx_ready = stat; }
   INLINE bool GetDXReady(void)  { return _dx_ready;}
   INLINE bool GetDXReady(void)  { return _dx_ready;}
-  void DXGraphicsStateGuardian7::SetTextureBlendMode(TextureApplyAttrib::Mode TexBlendMode,bool bJustEnable);
+  void DXGraphicsStateGuardian7::SetTextureBlendMode(TextureStage::Mode TexBlendMode,bool bJustEnable);
 
 
   void  dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled);
   void  dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled);
 
 

+ 14 - 22
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -535,7 +535,7 @@ dx_init(void) {
     // must do SetTSS here because redundant states are filtered out by our code based on current values above, so
     // must do SetTSS here because redundant states are filtered out by our code based on current values above, so
     // initial conditions must be correct
     // initial conditions must be correct
 
 
-    _CurTexBlendMode = TextureApplyAttrib::M_modulate;
+    _CurTexBlendMode = TextureStage::M_modulate;
     SetTextureBlendMode(_CurTexBlendMode,false);
     SetTextureBlendMode(_CurTexBlendMode,false);
     _texturing_enabled = false;
     _texturing_enabled = false;
     _pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);  // disables texturing
     _pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);  // disables texturing
@@ -1607,9 +1607,7 @@ draw_sprite(GeomSprite *geom, GeomContext *gc) {
   Texture *tex = geom->get_texture();
   Texture *tex = geom->get_texture();
   if(tex !=NULL) {
   if(tex !=NULL) {
     // set up the texture-rendering state
     // set up the texture-rendering state
-    modify_state(RenderState::make
-                 (TextureAttrib::make(tex),
-                  TextureApplyAttrib::make(TextureApplyAttrib::M_modulate)));
+    modify_state(RenderState::make(TextureAttrib::make(tex)));
     tex_xsize = tex->get_x_size();
     tex_xsize = tex->get_x_size();
     tex_ysize = tex->get_y_size();
     tex_ysize = tex->get_y_size();
   }
   }
@@ -3178,6 +3176,9 @@ end_draw_primitives() {
 //               responsibility of the calling function to later
 //               responsibility of the calling function to later
 //               call release_texture() with this same pointer (which
 //               call release_texture() with this same pointer (which
 //               will also delete the pointer).
 //               will also delete the pointer).
+//
+//               This function should not be called directly to
+//               prepare a texture.  Instead, call Texture::prepare().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 TextureContext *DXGraphicsStateGuardian8::
 TextureContext *DXGraphicsStateGuardian8::
 prepare_texture(Texture *tex) {
 prepare_texture(Texture *tex) {
@@ -3192,7 +3193,7 @@ prepare_texture(Texture *tex) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::apply_texture
 //     Function: DXGraphicsStateGuardian8::apply_texture
-//       Access: Public, Virtual
+//       Access: Public
 //  Description: Makes the texture the currently available texture for
 //  Description: Makes the texture the currently available texture for
 //               rendering.
 //               rendering.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -3790,13 +3791,13 @@ apply_fog(Fog *fog) {
     }
     }
 }
 }
 
 
-void DXGraphicsStateGuardian8::SetTextureBlendMode(TextureApplyAttrib::Mode TexBlendMode,bool bCanJustEnable) {
+void DXGraphicsStateGuardian8::SetTextureBlendMode(TextureStage::Mode TexBlendMode,bool bCanJustEnable) {
 
 
-/*class TextureApplyAttrib {
+/*class TextureStage {
   enum Mode {
   enum Mode {
     M_modulate,M_decal,M_blend,M_replace,M_add};
     M_modulate,M_decal,M_blend,M_replace,M_add};
 */
 */
-    static D3DTEXTUREOP TexBlendColorOp1[/* TextureApplyAttrib::Mode maxval*/ 10] =
+    static D3DTEXTUREOP TexBlendColorOp1[/* TextureStage::Mode maxval*/ 10] =
     {D3DTOP_MODULATE,D3DTOP_BLENDTEXTUREALPHA,D3DTOP_MODULATE,D3DTOP_SELECTARG1,D3DTOP_ADD};
     {D3DTOP_MODULATE,D3DTOP_BLENDTEXTUREALPHA,D3DTOP_MODULATE,D3DTOP_SELECTARG1,D3DTOP_ADD};
 
 
     //if bCanJustEnable, then we only need to make sure ColorOp is turned on and set properly
     //if bCanJustEnable, then we only need to make sure ColorOp is turned on and set properly
@@ -3810,7 +3811,7 @@ void DXGraphicsStateGuardian8::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
 
 
     switch (TexBlendMode) {
     switch (TexBlendMode) {
 
 
-        case TextureApplyAttrib::M_modulate:
+        case TextureStage::M_modulate:
             // emulates GL_MODULATE glTexEnv mode
             // emulates GL_MODULATE glTexEnv mode
             // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv)
             // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv)
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
@@ -3820,7 +3821,7 @@ void DXGraphicsStateGuardian8::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
 
 
             break;
             break;
-        case TextureApplyAttrib::M_decal:
+        case TextureStage::M_decal:
             // emulates GL_DECAL glTexEnv mode
             // emulates GL_DECAL glTexEnv mode
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
@@ -3829,13 +3830,13 @@ void DXGraphicsStateGuardian8::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
 
 
             break;
             break;
-        case TextureApplyAttrib::M_replace:
+        case TextureStage::M_replace:
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
 
 
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
             break;
             break;
-        case TextureApplyAttrib::M_add:
+        case TextureStage::M_add:
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
 
 
@@ -3845,7 +3846,7 @@ void DXGraphicsStateGuardian8::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
 
 
             break;
             break;
-        case TextureApplyAttrib::M_blend:
+        case TextureStage::M_blend:
             dxgsg8_cat.error()
             dxgsg8_cat.error()
             << "Impossible to emulate GL_BLEND in DX exactly " << (int) TexBlendMode << endl;
             << "Impossible to emulate GL_BLEND in DX exactly " << (int) TexBlendMode << endl;
 /*
 /*
@@ -4096,15 +4097,6 @@ issue_rescale_normal(const RescaleNormalAttrib *attrib) {
   }
   }
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian8::issue_texture_apply
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian8::
-issue_texture_apply(const TextureApplyAttrib *attrib) {
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian8::issue_depth_test
 //     Function: DXGraphicsStateGuardian8::issue_depth_test
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 3 - 5
panda/src/dxgsg8/dxGraphicsStateGuardian8.h

@@ -34,7 +34,6 @@
 #include "depthTestAttrib.h"
 #include "depthTestAttrib.h"
 #include "cullFaceAttrib.h"
 #include "cullFaceAttrib.h"
 #include "renderModeAttrib.h"
 #include "renderModeAttrib.h"
-#include "textureApplyAttrib.h"
 #include "fog.h"
 #include "fog.h"
 #include "pointerToArray.h"
 #include "pointerToArray.h"
 
 
@@ -105,7 +104,7 @@ public:
   virtual void end_draw_primitives();
   virtual void end_draw_primitives();
 
 
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual TextureContext *prepare_texture(Texture *tex);
-  virtual void apply_texture(TextureContext *tc);
+  void apply_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
 
 
   virtual VertexBufferContext *prepare_vertex_buffer(qpGeomVertexArrayData *data);
   virtual VertexBufferContext *prepare_vertex_buffer(qpGeomVertexArrayData *data);
@@ -132,7 +131,6 @@ public:
   virtual void issue_material(const MaterialAttrib *attrib);
   virtual void issue_material(const MaterialAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
-  virtual void issue_texture_apply(const TextureApplyAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
   virtual void issue_depth_test(const DepthTestAttrib *attrib);
   virtual void issue_depth_test(const DepthTestAttrib *attrib);
   virtual void issue_depth_write(const DepthWriteAttrib *attrib);
   virtual void issue_depth_write(const DepthWriteAttrib *attrib);
@@ -330,7 +328,7 @@ protected:
   //GraphicsChannel *_panda_gfx_channel;  // cache the 1 channel dx supports
   //GraphicsChannel *_panda_gfx_channel;  // cache the 1 channel dx supports
 
 
   // Cur Texture State
   // Cur Texture State
-  TextureApplyAttrib::Mode _CurTexBlendMode;
+  TextureStage::Mode _CurTexBlendMode;
   D3DTEXTUREFILTERTYPE _CurTexMagFilter,_CurTexMinFilter,_CurTexMipFilter;
   D3DTEXTUREFILTERTYPE _CurTexMagFilter,_CurTexMinFilter,_CurTexMipFilter;
   DWORD _CurTexAnisoDegree;
   DWORD _CurTexAnisoDegree;
   Texture::WrapMode _CurTexWrapModeU,_CurTexWrapModeV;
   Texture::WrapMode _CurTexWrapModeU,_CurTexWrapModeV;
@@ -368,7 +366,7 @@ public:
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
   INLINE void SetDXReady(bool status)  { _bDXisReady = status; }
   INLINE void SetDXReady(bool status)  { _bDXisReady = status; }
   INLINE bool GetDXReady(void)  { return _bDXisReady;}
   INLINE bool GetDXReady(void)  { return _bDXisReady;}
-  void DXGraphicsStateGuardian8::SetTextureBlendMode(TextureApplyAttrib::Mode TexBlendMode,bool bJustEnable);
+  void DXGraphicsStateGuardian8::SetTextureBlendMode(TextureStage::Mode TexBlendMode,bool bJustEnable);
 
 
   void  dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled);
   void  dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled);
   void reset_panda_gsg(void);
   void reset_panda_gsg(void);

+ 11 - 22
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -486,7 +486,7 @@ dx_init(void) {
     // must do SetTSS here because redundant states are filtered out by our code based on current values above, so
     // must do SetTSS here because redundant states are filtered out by our code based on current values above, so
     // initial conditions must be correct
     // initial conditions must be correct
 
 
-    _CurTexBlendMode = TextureApplyAttrib::M_modulate;
+    _CurTexBlendMode = TextureStage::M_modulate;
     SetTextureBlendMode(_CurTexBlendMode,false);
     SetTextureBlendMode(_CurTexBlendMode,false);
     _texturing_enabled = false;
     _texturing_enabled = false;
     _pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);  // disables texturing
     _pD3DDevice->SetTextureStageState(0,D3DTSS_COLOROP,D3DTOP_DISABLE);  // disables texturing
@@ -1527,9 +1527,7 @@ draw_sprite(GeomSprite *geom, GeomContext *gc) {
     Texture *tex = geom->get_texture();
     Texture *tex = geom->get_texture();
     if(tex !=NULL) {
     if(tex !=NULL) {
       // set up the texture-rendering state
       // set up the texture-rendering state
-      modify_state(RenderState::make
-                   (TextureAttrib::make(tex),
-                    TextureApplyAttrib::make(TextureApplyAttrib::M_modulate)));
+      modify_state(RenderState::make(TextureAttrib::make(tex)));
       tex_xsize = tex->get_x_size();
       tex_xsize = tex->get_x_size();
       tex_ysize = tex->get_y_size();
       tex_ysize = tex->get_y_size();
     }
     }
@@ -2581,7 +2579,7 @@ prepare_texture(Texture *tex) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian9::apply_texture
 //     Function: DXGraphicsStateGuardian9::apply_texture
-//       Access: Public, Virtual
+//       Access: Public
 //  Description: Makes the texture the currently available texture for
 //  Description: Makes the texture the currently available texture for
 //               rendering.
 //               rendering.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -2974,13 +2972,13 @@ apply_fog(Fog *fog) {
     }
     }
 }
 }
 
 
-void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureApplyAttrib::Mode TexBlendMode,bool bCanJustEnable) {
+void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureStage::Mode TexBlendMode,bool bCanJustEnable) {
 
 
-/*class TextureApplyAttrib {
+/*class TextureStage {
   enum Mode {
   enum Mode {
     M_modulate,M_decal,M_blend,M_replace,M_add};
     M_modulate,M_decal,M_blend,M_replace,M_add};
 */
 */
-    static D3DTEXTUREOP TexBlendColorOp1[/* TextureApplyAttrib::Mode maxval*/ 10] =
+    static D3DTEXTUREOP TexBlendColorOp1[/* TextureStage::Mode maxval*/ 10] =
     {D3DTOP_MODULATE,D3DTOP_BLENDTEXTUREALPHA,D3DTOP_MODULATE,D3DTOP_SELECTARG1,D3DTOP_ADD};
     {D3DTOP_MODULATE,D3DTOP_BLENDTEXTUREALPHA,D3DTOP_MODULATE,D3DTOP_SELECTARG1,D3DTOP_ADD};
 
 
     //if bCanJustEnable, then we only need to make sure ColorOp is turned on and set properly
     //if bCanJustEnable, then we only need to make sure ColorOp is turned on and set properly
@@ -2996,7 +2994,7 @@ void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
 
 
     switch (TexBlendMode) {
     switch (TexBlendMode) {
 
 
-        case TextureApplyAttrib::M_modulate:
+        case TextureStage::M_modulate:
             // emulates GL_MODULATE glTexEnv mode
             // emulates GL_MODULATE glTexEnv mode
             // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv)
             // want to multiply tex-color*pixel color to emulate GL modulate blend (see glTexEnv)
             /*
             /*
@@ -3017,7 +3015,7 @@ void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
             _pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
             _pD3DDevice->SetTextureStageState(1, D3DTSS_COLOROP, D3DTOP_MODULATE);
             //dxgsg9_cat.info() << "--------------modulating--------------" << endl;
             //dxgsg9_cat.info() << "--------------modulating--------------" << endl;
             break;
             break;
-        case TextureApplyAttrib::M_decal:
+        case TextureStage::M_decal:
             // emulates GL_DECAL glTexEnv mode
             // emulates GL_DECAL glTexEnv mode
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
@@ -3026,13 +3024,13 @@ void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_DIFFUSE );
 
 
             break;
             break;
-        case TextureApplyAttrib::M_replace:
+        case TextureStage::M_replace:
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
 
 
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAOP,   D3DTOP_SELECTARG1 );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG1, D3DTA_TEXTURE );
             break;
             break;
-        case TextureApplyAttrib::M_add:
+        case TextureStage::M_add:
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG1, D3DTA_TEXTURE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_COLORARG2, D3DTA_DIFFUSE );
 
 
@@ -3042,7 +3040,7 @@ void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureApplyAttrib::Mode TexB
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
             _pD3DDevice->SetTextureStageState( 0, D3DTSS_ALPHAARG2, D3DTA_DIFFUSE );
 
 
             break;
             break;
-        case TextureApplyAttrib::M_blend:
+        case TextureStage::M_blend:
             dxgsg9_cat.error()
             dxgsg9_cat.error()
             << "Impossible to emulate GL_BLEND in DX exactly " << (int) TexBlendMode << endl;
             << "Impossible to emulate GL_BLEND in DX exactly " << (int) TexBlendMode << endl;
 /*
 /*
@@ -3281,15 +3279,6 @@ issue_rescale_normal(const RescaleNormalAttrib *attrib) {
   }
   }
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: DXGraphicsStateGuardian9::issue_texture_apply
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void DXGraphicsStateGuardian9::
-issue_texture_apply(const TextureApplyAttrib *attrib) {
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: DXGraphicsStateGuardian9::issue_depth_test
 //     Function: DXGraphicsStateGuardian9::issue_depth_test
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 3 - 5
panda/src/dxgsg9/dxGraphicsStateGuardian9.h

@@ -34,7 +34,6 @@
 #include "material.h"
 #include "material.h"
 #include "depthTestAttrib.h"
 #include "depthTestAttrib.h"
 #include "renderModeAttrib.h"
 #include "renderModeAttrib.h"
-#include "textureApplyAttrib.h"
 #include "fog.h"
 #include "fog.h"
 #include "pointerToArray.h"
 #include "pointerToArray.h"
 
 
@@ -91,7 +90,7 @@ public:
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
   virtual void draw_sphere(GeomSphere *geom, GeomContext *gc);
 
 
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual TextureContext *prepare_texture(Texture *tex);
-  virtual void apply_texture(TextureContext *tc, int index=0);
+  void apply_texture(TextureContext *tc, int index);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
 
 
   virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
   virtual void framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
@@ -109,7 +108,6 @@ public:
   virtual void issue_material(const MaterialAttrib *attrib);
   virtual void issue_material(const MaterialAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
-  virtual void issue_texture_apply(const TextureApplyAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
   virtual void issue_depth_test(const DepthTestAttrib *attrib);
   virtual void issue_depth_test(const DepthTestAttrib *attrib);
   virtual void issue_depth_write(const DepthWriteAttrib *attrib);
   virtual void issue_depth_write(const DepthWriteAttrib *attrib);
@@ -296,7 +294,7 @@ protected:
   //GraphicsChannel *_panda_gfx_channel;  // cache the 1 channel dx supports
   //GraphicsChannel *_panda_gfx_channel;  // cache the 1 channel dx supports
 
 
   // Cur Texture State
   // Cur Texture State
-  TextureApplyAttrib::Mode _CurTexBlendMode;
+  TextureStage::Mode _CurTexBlendMode;
   D3DTEXTUREFILTERTYPE _CurTexMagFilter,_CurTexMinFilter,_CurTexMipFilter;
   D3DTEXTUREFILTERTYPE _CurTexMagFilter,_CurTexMinFilter,_CurTexMipFilter;
   DWORD _CurTexAnisoDegree;
   DWORD _CurTexAnisoDegree;
   Texture::WrapMode _CurTexWrapModeU,_CurTexWrapModeV;
   Texture::WrapMode _CurTexWrapModeU,_CurTexWrapModeV;
@@ -332,7 +330,7 @@ public:
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
   INLINE void SetDXReady(bool status)  { _bDXisReady = status; }
   INLINE void SetDXReady(bool status)  { _bDXisReady = status; }
   INLINE bool GetDXReady(void)  { return _bDXisReady;}
   INLINE bool GetDXReady(void)  { return _bDXisReady;}
-  void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureApplyAttrib::Mode TexBlendMode,bool bJustEnable);
+  void DXGraphicsStateGuardian9::SetTextureBlendMode(TextureStage::Mode TexBlendMode,bool bJustEnable);
 
 
   void  dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled);
   void  dx_cleanup(bool bRestoreDisplayMode,bool bAtExitFnCalled);
   void reset_panda_gsg(void);
   void reset_panda_gsg(void);

+ 1711 - 1741
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -1439,9 +1439,7 @@ draw_sprite(GeomSprite *geom, GeomContext *) {
   Texture *tex = geom->get_texture();
   Texture *tex = geom->get_texture();
   if(tex != NULL) {
   if(tex != NULL) {
     // set up the texture-rendering state
     // set up the texture-rendering state
-    modify_state(RenderState::make
-                 (TextureAttrib::make(tex),
-                  TextureApplyAttrib::make(TextureApplyAttrib::M_modulate)));
+    modify_state(RenderState::make(TextureAttrib::make(tex)));
     tex_x_size = tex->get_x_size();
     tex_x_size = tex->get_x_size();
     tex_y_size = tex->get_y_size();
     tex_y_size = tex->get_y_size();
   }
   }
@@ -2759,12 +2757,12 @@ end_draw_primitives() {
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::prepare_texture
 //     Function: GLGraphicsStateGuardian::prepare_texture
 //       Access: Public, Virtual
 //       Access: Public, Virtual
-//  Description: Creates a new retained-mode representation of the
-//               given texture, and returns a newly-allocated
-//               TextureContext pointer to reference it.  It is the
-//               responsibility of the calling function to later
-//               call release_texture() with this same pointer (which
-//               will also delete the pointer).
+//  Description: Creates whatever structures the GSG requires to
+//               represent the texture internally, and returns a
+//               newly-allocated TextureContext object with this data.
+//               It is the responsibility of the calling function to
+//               later call release_texture() with this same pointer
+//               (which will also delete the pointer).
 //
 //
 //               This function should not be called directly to
 //               This function should not be called directly to
 //               prepare a texture.  Instead, call Texture::prepare().
 //               prepare a texture.  Instead, call Texture::prepare().
@@ -2773,42 +2771,10 @@ TextureContext *CLP(GraphicsStateGuardian)::
 prepare_texture(Texture *tex) {
 prepare_texture(Texture *tex) {
   CLP(TextureContext) *gtc = new CLP(TextureContext)(tex);
   CLP(TextureContext) *gtc = new CLP(TextureContext)(tex);
   GLP(GenTextures)(1, &gtc->_index);
   GLP(GenTextures)(1, &gtc->_index);
-
-  bind_texture(gtc);
-  GLP(PrioritizeTextures)(1, &gtc->_index, &gtc->_priority);
-  specify_texture(tex);
-  apply_texture_immediate(gtc, tex);
-
   report_my_gl_errors();
   report_my_gl_errors();
-  return gtc;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::apply_texture
-//       Access: Public, Virtual
-//  Description: Makes the texture the currently available texture for
-//               rendering.
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-apply_texture(TextureContext *tc, int index) {
-  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-
-  add_to_texture_record(gtc);
-  bind_texture(gtc);
-
-  int dirty = gtc->get_dirty_flags();
-  if ((dirty & (Texture::DF_wrap | Texture::DF_filter | Texture::DF_border)) != 0) {
-    // We need to re-specify the texture properties.
-    specify_texture(gtc->_texture);
-  }
-  if ((dirty & (Texture::DF_image | Texture::DF_mipmap | Texture::DF_border)) != 0) {
-    // We need to re-apply the image.
-    apply_texture_immediate(gtc, gtc->_texture);
-  }
 
 
-  gtc->clear_dirty_flags();
-
-  report_my_gl_errors();
+  apply_texture(gtc);
+  return gtc;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -3283,7 +3249,14 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr,
 
 
   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   nassertv(tc != (TextureContext *)NULL);
   nassertv(tc != (TextureContext *)NULL);
-  bind_texture(tc);
+
+  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+  GLenum target = get_texture_target(tex->get_texture_type());
+  if (target == GL_NONE) {
+    // Invalid texture, can't copy to it.
+    return;
+  }
+  GLP(BindTexture)(target, gtc->_index);
 
 
   if (z >= 0) {
   if (z >= 0) {
     // Copy to a cube map face.
     // Copy to a cube map face.
@@ -3439,7 +3412,8 @@ framebuffer_copy_to_ram(Texture *tex, int z, const DisplayRegion *dr,
 //       Access: Public, Virtual
 //       Access: Public, Virtual
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::apply_material(const Material *material) {
+void CLP(GraphicsStateGuardian)::
+apply_material(const Material *material) {
   GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT;
   GLenum face = material->get_twoside() ? GL_FRONT_AND_BACK : GL_FRONT;
 
 
   GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data());
   GLP(Materialfv)(face, GL_SPECULAR, material->get_specular().get_data());
@@ -3783,18 +3757,6 @@ issue_rescale_normal(const RescaleNormalAttrib *attrib) {
   report_my_gl_errors();
   report_my_gl_errors();
 }
 }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::issue_texture_apply
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-issue_texture_apply(const TextureApplyAttrib *) {
-  // This attrib is no longer used; it is replaced by the parameters
-  // within TextureStage.
-  return;
-}
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: GLGraphicsStateGuardian::issue_color_write
 //     Function: GLGraphicsStateGuardian::issue_color_write
 //       Access: Public, Virtual
 //       Access: Public, Virtual
@@ -4391,1991 +4353,1999 @@ set_read_buffer(const RenderBuffer &rb) {
 }
 }
 
 
 
 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::bind_texture
-//       Access: Protected
-//  Description:
+//     Function: GLGraphicsStateGuardian::get_numeric_type
+//       Access: Protected, Static
+//  Description: Maps from the Geom's internal numeric type symbols
+//               to GL's.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-bind_texture(TextureContext *tc) {
-  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
-  report_my_gl_errors();
+GLenum CLP(GraphicsStateGuardian)::
+get_numeric_type(qpGeom::NumericType numeric_type) {
+  switch (numeric_type) {
+  case qpGeom::NT_uint16:
+    return GL_UNSIGNED_SHORT;
 
 
-#ifdef GSG_VERBOSE
-  Texture *tex = tc->_texture;
-  GLCAT.spam()
-    << "glBindTexture(): " << tex->get_name() << "(" << (int)gtc->_index
-    << ")" << endl;
-#endif
+  case qpGeom::NT_uint32:
+    return GL_UNSIGNED_INT;
 
 
-  GLenum target = get_texture_target(tc->_texture->get_texture_type());
-  if (target != GL_NONE) {
-    GLP(BindTexture)(target, gtc->_index);
+  case qpGeom::NT_uint8:
+  case qpGeom::NT_packed_dcba:
+  case qpGeom::NT_packed_dabc:
+    return GL_UNSIGNED_BYTE;
+    
+  case qpGeom::NT_float32:
+    return GL_FLOAT;
   }
   }
 
 
-  report_my_gl_errors();
+  GLCAT.error()
+    << "Invalid NumericType value (" << (int)numeric_type << ")\n";
+  return GL_UNSIGNED_BYTE;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::specify_texture
+//     Function: GLGraphicsStateGuardian::get_texture_target
 //       Access: Protected
 //       Access: Protected
-//  Description:
+//  Description: Maps from the Texture's texture type symbols to
+//               GL's.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-specify_texture(Texture *tex) {
-  GLenum target = get_texture_target(tex->get_texture_type());
-  if (target == GL_NONE) {
-    // Unsupported target (e.g. 3-d texturing on GL 1.1).
-    return;
-  }
-
-  GLP(TexParameteri)(target, GL_TEXTURE_WRAP_S,
-                     get_texture_wrap_mode(tex->get_wrap_u()));
-  if (target != GL_TEXTURE_1D) {
-    GLP(TexParameteri)(target, GL_TEXTURE_WRAP_T,
-                       get_texture_wrap_mode(tex->get_wrap_v()));
-  }
-  if (target == GL_TEXTURE_3D) {
-    GLP(TexParameteri)(target, GL_TEXTURE_WRAP_R,
-                       get_texture_wrap_mode(tex->get_wrap_w()));
-  }
-
-  Colorf border_color = tex->get_border_color();
-  GLP(TexParameterfv)(target, GL_TEXTURE_BORDER_COLOR,
-                      border_color.get_data());
-
-  Texture::FilterType minfilter = tex->get_minfilter();
-  Texture::FilterType magfilter = tex->get_magfilter();
-  bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps);
+GLenum CLP(GraphicsStateGuardian)::
+get_texture_target(Texture::TextureType texture_type) const {
+  switch (texture_type) {
+  case Texture::TT_1d_texture:
+    return GL_TEXTURE_1D;
 
 
-#ifndef NDEBUG
-  if (CLP(force_mipmaps)) {
-    minfilter = Texture::FT_linear_mipmap_linear;
-    magfilter = Texture::FT_linear;
-    uses_mipmaps = true;
-  }
-#endif
+  case Texture::TT_2d_texture:
+    return GL_TEXTURE_2D;
 
 
-  if (_supports_generate_mipmap && 
-      (auto_generate_mipmaps || !tex->might_have_ram_image())) {
-    // If the hardware can automatically generate mipmaps, ask it to
-    // do so now, but only if the texture requires them.
-    GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, uses_mipmaps);
+  case Texture::TT_3d_texture:
+    if (_supports_3d_texture) {
+      return GL_TEXTURE_3D;
+    } else {
+      return GL_NONE;
+    }
 
 
-  } else if (!tex->might_have_ram_image()) {
-    // If the hardware can't automatically generate mipmaps, but it's
-    // a dynamically generated texture (that is, the RAM image isn't
-    // available so it didn't pass through the CPU), then we'd better
-    // not try to enable mipmap filtering, since we can't generate
-    // mipmaps.
-    uses_mipmaps = false;
+  case Texture::TT_cube_map:
+    if (_supports_cube_map) {
+      return GL_TEXTURE_CUBE_MAP;
+    } else {
+      return GL_NONE;
+    }
   }
   }
- 
-  GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER,
-                     get_texture_filter_type(minfilter, !uses_mipmaps));
-  GLP(TexParameteri)(target, GL_TEXTURE_MAG_FILTER,
-                     get_texture_filter_type(magfilter, true));
 
 
-  report_my_gl_errors();
+  GLCAT.error() << "Invalid Texture::TextureType value!\n";
+  return GL_TEXTURE_2D;
 }
 }
 
 
-#ifndef NDEBUG
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: compute_gl_image_size
-//  Description: Calculates how many bytes GL will expect to read for
-//               a texture image, based on the number of pixels and
-//               the GL format and type.  This is only used for
-//               debugging.
+//     Function: GLGraphicsStateGuardian::get_texture_wrap_mode
+//       Access: Protected, Static
+//  Description: Maps from the Texture's internal wrap mode symbols to
+//               GL's.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-static int
-compute_gl_image_size(int x_size, int y_size, int z_size, 
-                      int external_format, int type) {
-  int num_components = 0;
-  switch (external_format) {
-  case GL_COLOR_INDEX:
-  case GL_STENCIL_INDEX:
-  case GL_DEPTH_COMPONENT:
-  case GL_RED:
-  case GL_GREEN:
-  case GL_BLUE:
-  case GL_ALPHA:
-  case GL_LUMINANCE:
-    num_components = 1;
-    break;
-
-  case GL_LUMINANCE_ALPHA:
-    num_components = 2;
-    break;
-
-  case GL_BGR:
-  case GL_RGB:
-    num_components = 3;
-    break;
-
-  case GL_BGRA:
-  case GL_RGBA:
-    num_components = 4;
-    break;
+GLenum CLP(GraphicsStateGuardian)::
+get_texture_wrap_mode(Texture::WrapMode wm) {
+  if (CLP(ignore_clamp)) {
+    return GL_REPEAT;
   }
   }
+  switch (wm) {
+  case Texture::WM_clamp:
+    return _edge_clamp;
 
 
-  int pixel_width = 0;
-  switch (type) {
-  case GL_UNSIGNED_BYTE:
-    pixel_width = 1 * num_components;
-    break;
+  case Texture::WM_repeat:
+    return GL_REPEAT;
 
 
-  case GL_UNSIGNED_SHORT:
-    pixel_width = 2 * num_components;
-    break;
+  case Texture::WM_mirror:
+    return _mirror_repeat;
 
 
-  case GL_UNSIGNED_BYTE_3_3_2:
-    nassertr(num_components == 3, 0);
-    pixel_width = 1;
-    break;
+  case Texture::WM_mirror_once:
+    return _mirror_border_clamp;
 
 
-  case GL_FLOAT:
-    pixel_width = 4 * num_components;
+  case Texture::WM_border_color:
+    return _border_clamp;
+
+  case Texture::WM_invalid:
     break;
     break;
   }
   }
-
-  return x_size * y_size * z_size * pixel_width;
+  GLCAT.error() << "Invalid Texture::WrapMode value!\n";
+  return _edge_clamp;
 }
 }
-#endif  // NDEBUG
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::apply_texture_immediate
-//       Access: Protected
-//  Description: Sends the texture image to GL.  This can be used to
-//               render a texture in immediate mode, or as part of the
-//               process of creating a GL texture object.
-//
-//               The return value is true if successful, or false if
-//               the texture has no image.
+//     Function: GLGraphicsStateGuardian::get_texture_filter_type
+//       Access: Protected, Static
+//  Description: Maps from the Texture's internal filter type symbols
+//               to GL's.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool CLP(GraphicsStateGuardian)::
-apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex) {
-  CPTA_uchar image = tex->get_ram_image();
-  if (image.is_null()) {
-    return false;
-  }
-
-  int width = tex->get_x_size();
-  int height = tex->get_y_size();
-  int depth = tex->get_z_size();
-
-  GLint internal_format = get_internal_image_format(tex->get_format());
-  GLint external_format = get_external_image_format(tex->get_format());
-  GLenum component_type = get_component_type(tex->get_component_type());
+GLenum CLP(GraphicsStateGuardian)::
+get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps) {
+  if (CLP(ignore_filters)) {
+    return GL_NEAREST;
 
 
-  // Ensure that the texture fits within the GL's specified limits.
-  int max_dimension;
-  switch (tex->get_texture_type()) {
-  case Texture::TT_3d_texture:
-    max_dimension = _max_3d_texture_dimension;
-    break;
-
-  case Texture::TT_cube_map:
-    max_dimension = _max_cube_map_dimension;
-    break;
-
-  default:
-    max_dimension = _max_texture_dimension;
-  }
+  } else if (ignore_mipmaps) {
+    switch (ft) {
+    case Texture::FT_nearest_mipmap_nearest:
+    case Texture::FT_nearest:
+      return GL_NEAREST;
+    case Texture::FT_linear:
+    case Texture::FT_linear_mipmap_nearest:
+    case Texture::FT_nearest_mipmap_linear:
+    case Texture::FT_linear_mipmap_linear:
+      return GL_LINEAR;
+    case Texture::FT_invalid:
+      break;
+    }
 
 
-  if (max_dimension == 0) {
-    // Guess this GL doesn't support cube mapping/3d textures.
-    report_my_gl_errors();
-    return false;
+  } else {
+    switch (ft) {
+    case Texture::FT_nearest:
+      return GL_NEAREST;
+    case Texture::FT_linear:
+      return GL_LINEAR;
+    case Texture::FT_nearest_mipmap_nearest:
+      return GL_NEAREST_MIPMAP_NEAREST;
+    case Texture::FT_linear_mipmap_nearest:
+      return GL_LINEAR_MIPMAP_NEAREST;
+    case Texture::FT_nearest_mipmap_linear:
+      return GL_NEAREST_MIPMAP_LINEAR;
+    case Texture::FT_linear_mipmap_linear:
+      return GL_LINEAR_MIPMAP_LINEAR;
+    case Texture::FT_invalid:
+      break;
+    }
   }
   }
+  GLCAT.error() << "Invalid Texture::FilterType value!\n";
+  return GL_NEAREST;
+}
 
 
-  int texel_size = tex->get_num_components() * tex->get_component_width();
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_component_type
+//       Access: Protected, Static
+//  Description: Maps from the Texture's internal ComponentType symbols
+//               to GL's.
+////////////////////////////////////////////////////////////////////
+GLenum CLP(GraphicsStateGuardian)::
+get_component_type(Texture::ComponentType component_type) {
+  switch (component_type) {
+  case Texture::T_unsigned_byte:
+    return GL_UNSIGNED_BYTE;
+  case Texture::T_unsigned_short:
+    return GL_UNSIGNED_SHORT;
+  case Texture::T_float:
+    return GL_FLOAT;
 
 
-  // If it doesn't fit, we have to reduce it on-the-fly.  This is kind
-  // of expensive and it doesn't look great; it would have been better
-  // if the user had specified max-texture-dimension to reduce the
-  // texture at load time instead.  Of course, the user doesn't always
-  // know ahead of time what the hardware limits are.
-  if (max_dimension > 0) {
-    if (width > max_dimension) {
-      int byte_chunk = texel_size;
-      int stride = 1;
-      int new_width = width;
-      while (new_width > max_dimension) {
-        stride <<= 1;
-        new_width >>= 1;
-      }
-      GLCAT.info()
-        << "Reducing width of " << tex->get_name()
-        << " from " << width << " to " << new_width << "\n";
-      image = reduce_image(image, byte_chunk, stride);
-      width = new_width;
-    }
-    if (height > max_dimension) {
-      int byte_chunk = width * texel_size;
-      int stride = 1;
-      int new_height = height;
-      while (new_height > max_dimension) {
-        stride <<= 1;
-        new_height >>= 1;
-      }
-      GLCAT.info()
-        << "Reducing height of " << tex->get_name()
-        << " from " << height << " to " << new_height << "\n";
-      image = reduce_image(image, byte_chunk, stride);
-      height = new_height;
-    }
-    if (depth > max_dimension) {
-      int byte_chunk = height * width * texel_size;
-      int stride = 1;
-      int new_depth = depth;
-      while (new_depth > max_dimension) {
-        stride <<= 1;
-        new_depth >>= 1;
-      }
-      GLCAT.info()
-        << "Reducing depth of " << tex->get_name()
-        << " from " << depth << " to " << new_depth << "\n";
-      image = reduce_image(image, byte_chunk, stride);
-      depth = new_depth;
-    }
+  default:
+    GLCAT.error() << "Invalid Texture::Type value!\n";
+    return GL_UNSIGNED_BYTE;
   }
   }
+}
 
 
-  if (!_supports_bgr) {
-    // If the GL doesn't claim to support BGR, we may have to reverse
-    // the component ordering of the image.
-    image = fix_component_ordering(image, external_format, tex);
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_external_image_format
+//       Access: Protected
+//  Description: Maps from the Texture's Format symbols
+//               to GL's.
+////////////////////////////////////////////////////////////////////
+GLint CLP(GraphicsStateGuardian)::
+get_external_image_format(Texture::Format format) const {
+  switch (format) {
+  case Texture::F_color_index:
+    return GL_COLOR_INDEX;
+  case Texture::F_stencil_index:
+    return GL_STENCIL_INDEX;
+  case Texture::F_depth_component:
+    return GL_DEPTH_COMPONENT;
+  case Texture::F_red:
+    return GL_RED;
+  case Texture::F_green:
+    return GL_GREEN;
+  case Texture::F_blue:
+    return GL_BLUE;
+  case Texture::F_alpha:
+    return GL_ALPHA;
+  case Texture::F_rgb:
+  case Texture::F_rgb5:
+  case Texture::F_rgb8:
+  case Texture::F_rgb12:
+  case Texture::F_rgb332:
+    return _supports_bgr ? GL_BGR : GL_RGB;
+  case Texture::F_rgba:
+  case Texture::F_rgbm:
+  case Texture::F_rgba4:
+  case Texture::F_rgba5:
+  case Texture::F_rgba8:
+  case Texture::F_rgba12:
+    return _supports_bgr ? GL_BGRA : GL_RGBA;
+  case Texture::F_luminance:
+    return GL_LUMINANCE;
+  case Texture::F_luminance_alphamask:
+  case Texture::F_luminance_alpha:
+    return GL_LUMINANCE_ALPHA;
   }
   }
+  GLCAT.error()
+    << "Invalid Texture::Format value in get_external_image_format(): "
+    << (int)format << "\n";
+  return GL_RGB;
+}
 
 
-#ifndef NDEBUG
-  int wanted_size = 
-    compute_gl_image_size(width, height, depth, external_format, component_type);
-  nassertr(wanted_size == (int)image.size(), false);
-#endif  // NDEBUG
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_internal_image_format
+//       Access: Protected, Static
+//  Description: Maps from the Texture's Format symbols to a
+//               suitable internal format for GL textures.
+////////////////////////////////////////////////////////////////////
+GLint CLP(GraphicsStateGuardian)::
+get_internal_image_format(Texture::Format format) {
+  switch (format) {
+  case Texture::F_rgba:
+  case Texture::F_rgbm:
+    return GL_RGBA;
+  case Texture::F_rgba4:
+    return GL_RGBA4;
+  case Texture::F_rgba8:
+    return GL_RGBA8;
+  case Texture::F_rgba12:
+    return GL_RGBA12;
 
 
-  GLP(PixelStorei)(GL_UNPACK_ALIGNMENT, 1);
+  case Texture::F_rgb:
+    return GL_RGB;
+  case Texture::F_rgb5:
+    return GL_RGB5;
+  case Texture::F_rgba5:
+    return GL_RGB5_A1;
+  case Texture::F_rgb8:
+    return GL_RGB8;
+  case Texture::F_rgb12:
+    return GL_RGB12;
+  case Texture::F_rgb332:
+    return GL_R3_G3_B2;
 
 
-  bool uses_mipmaps = (tex->uses_mipmaps() && !CLP(ignore_mipmaps)) || CLP(force_mipmaps);
+  case Texture::F_alpha:
+    return GL_ALPHA;
 
 
-#ifndef NDEBUG
-  if (CLP(force_mipmaps)) {
-    uses_mipmaps = true;
+  case Texture::F_red:
+  case Texture::F_green:
+  case Texture::F_blue:
+  case Texture::F_luminance:
+    return GL_LUMINANCE;
+  case Texture::F_luminance_alpha:
+  case Texture::F_luminance_alphamask:
+    return GL_LUMINANCE_ALPHA;
+
+  default:
+    GLCAT.error()
+      << "Invalid image format in get_internal_image_format(): "
+      << (int)format << "\n";
+    return GL_RGB;
   }
   }
-#endif
+}
 
 
-  bool success = true;
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_external_texture_bytes
+//       Access: Protected, Static
+//  Description: Computes the number of bytes that should be in the
+//               "external", or local, texture buffer before
+//               transferring to OpenGL.  This is just used for
+//               sending data to PStats.
+////////////////////////////////////////////////////////////////////
+int CLP(GraphicsStateGuardian)::
+get_external_texture_bytes(int width, int height, int depth,
+                           GLint external_format, GLenum component_type) {
+  int num_components;
+  switch (external_format) {
+  case GL_COLOR_INDEX:
+  case GL_STENCIL_INDEX:
+  case GL_DEPTH_COMPONENT:
+  case GL_RED:
+  case GL_GREEN:
+  case GL_BLUE:
+  case GL_ALPHA:
+  case GL_LUMINANCE:
+    num_components = 1;
+    break;
 
 
-  if (tex->get_texture_type() == Texture::TT_cube_map) {
-    // A cube map must load six different 2-d images (which are stored
-    // as the six pages of the system ram image).
-    if (!_supports_cube_map) {
-      report_my_gl_errors();
-      return false;
-    }
+  case GL_LUMINANCE_ALPHA:
+    num_components = 2;
+    break;
 
 
-    size_t page_size = height * width * texel_size;
-    const unsigned char *image_base = image;
-    
-    success = success && upload_texture_image
-      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
-       internal_format, width, height, depth, external_format, component_type,
-       image_base);
-    image_base += page_size;
-    
-    success = success && upload_texture_image
-      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
-       internal_format, width, height, depth, external_format, component_type,
-       image_base);
-    image_base += page_size;
-    
-    success = success && upload_texture_image
-      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
-       internal_format, width, height, depth, external_format, component_type,
-       image_base);
-    image_base += page_size;
-    
-    success = success && upload_texture_image
-      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
-       internal_format, width, height, depth, external_format, component_type,
-       image_base);
-    image_base += page_size;
-    
-    success = success && upload_texture_image
-      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
-       internal_format, width, height, depth, external_format, component_type,
-       image_base);
-    image_base += page_size;
-    
-    success = success && upload_texture_image
-      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
-       internal_format, width, height, depth, external_format, component_type,
-       image_base);
-    image_base += page_size;
-    
-    nassertr((size_t)(image_base - image) == image.size(), false);
+  case GL_BGR: 
+  case GL_RGB:
+    num_components = 3;
+    break;
 
 
-  } else {
-    // Any other kind of texture can be loaded all at once.
-    success = upload_texture_image
-      (gtc, uses_mipmaps, get_texture_target(tex->get_texture_type()),
-       internal_format, width, height, depth, external_format, component_type,
-       image);
+  case GL_BGRA: 
+  case GL_RGBA:
+    num_components = 4;
+    break;
+    
+  default:
+    GLCAT.error()
+      << "Unexpected external_format in get_external_texture_bytes(): "
+      << hex << external_format << dec << "\n";
+    num_components = 3;
   }
   }
 
 
-  if (success) {
-    gtc->_already_applied = true;
-    gtc->_internal_format = internal_format;
-    gtc->_width = width;
-    gtc->_height = height;
-    gtc->_depth = depth;
+  int component_width;
+  switch (component_type) {
+  case GL_UNSIGNED_BYTE:
+    component_width = 1;
+    break;
 
 
-#ifndef NDEBUG
-    if (uses_mipmaps && CLP(save_mipmaps)) {
-      save_mipmap_images(tex);
-    }
-#endif
+  case GL_UNSIGNED_SHORT:
+    component_width = 2;
+    break;
 
 
-    report_my_gl_errors();
-    return true;
+  case GL_FLOAT:
+    component_width = 4;
+    break;
+
+  default:
+    GLCAT.error()
+      << "Unexpected component_type in get_external_texture_bytes(): "
+      << hex << component_type << dec << "\n";
+    component_width = 1;
   }
   }
 
 
-  report_my_gl_errors();
-  return false;
+  return width * height * depth * num_components * component_width;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::upload_texture_image
-//       Access: Protected
-//  Description: Loads a texture image, or one page of a cube map
-//               image, from system RAM to texture memory.
+//     Function: GLGraphicsStateGuardian::get_texture_apply_mode_type
+//       Access: Protected, Static
+//  Description: Maps from the texture stage's mode types
+//               to the corresponding OpenGL ids
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-bool CLP(GraphicsStateGuardian)::
-upload_texture_image(CLP(TextureContext) *gtc, 
-                     bool uses_mipmaps, 
-                     GLenum target, GLint internal_format, 
-                     int width, int height, int depth,
-                     GLint external_format, GLenum component_type, 
-                     const unsigned char *image) {
-  if (target == GL_NONE) {
-    // Unsupported target (e.g. 3-d texturing on GL 1.1).
-    return false;
+GLint CLP(GraphicsStateGuardian)::
+get_texture_apply_mode_type(TextureStage::Mode am) {
+  switch (am) {
+  case TextureStage::M_modulate: return GL_MODULATE;
+  case TextureStage::M_decal: return GL_DECAL;
+  case TextureStage::M_blend: return GL_BLEND;
+  case TextureStage::M_replace: return GL_REPLACE;
+  case TextureStage::M_add: return GL_ADD;
+  case TextureStage::M_combine: return GL_COMBINE;
+  case TextureStage::M_blend_color_scale: return GL_BLEND;
   }
   }
-  PStatTimer timer(_load_texture_pcollector);
-
-  if (uses_mipmaps) {
-#ifndef NDEBUG
-    if (CLP(show_mipmaps) && target == GL_TEXTURE_2D) {
-      build_phony_mipmaps(gtc->_texture);
-      report_my_gl_errors();
-      return true;
-      
-    } else 
-#endif 
-      if (!_supports_generate_mipmap || !auto_generate_mipmaps) {
-        // We only need to build the mipmaps by hand if the GL
-        // doesn't support generating them automatically.
-        bool success = true;
-#ifdef DO_PSTATS
-        _data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type) * 4 / 3);
-#endif
-        switch (target) {
-        case GL_TEXTURE_1D:
-          GLUP(Build1DMipmaps)(target, internal_format, width,
-                               external_format, component_type, image);
-          break;
 
 
-        case GL_TEXTURE_3D:
-#ifdef GLU_VERSION_1_3
-          GLUP(Build3DMipmaps)(target, internal_format,
-                               width, height, depth,
-                               external_format, component_type, image);
-#else  // GLU_VERSION_1_3
-          // Prior to GLU 1.3, there was no gluBuild3DMipmaps() call.
-          // Just fall through and load the texture without mipmaps.
-          GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-          success = false;
-#endif  // GLU_VERSION_1_3
-          break;
+  GLCAT.error()
+    << "Invalid TextureStage::Mode value" << endl;
+  return GL_MODULATE;
+}
 
 
-        default:
-          GLUP(Build2DMipmaps)(target, internal_format,
-                               width, height,
-                               external_format, component_type, image);
-        }
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_texture_combine_type
+//       Access: Protected, Static
+//  Description: Maps from the texture stage's CombineMode types
+//               to the corresponding OpenGL ids
+////////////////////////////////////////////////////////////////////
+GLint CLP(GraphicsStateGuardian)::
+get_texture_combine_type(TextureStage::CombineMode cm) {
+  switch (cm) {
+  case TextureStage::CM_undefined: // fall through
+  case TextureStage::CM_replace: return GL_REPLACE;
+  case TextureStage::CM_modulate: return GL_MODULATE;
+  case TextureStage::CM_add: return GL_ADD;
+  case TextureStage::CM_add_signed: return GL_ADD_SIGNED;
+  case TextureStage::CM_interpolate: return GL_INTERPOLATE;
+  case TextureStage::CM_subtract: return GL_SUBTRACT;
+  case TextureStage::CM_dot3_rgb: return GL_DOT3_RGB;
+  case TextureStage::CM_dot3_rgba: return GL_DOT3_RGBA;
+  }
+  GLCAT.error()
+    << "Invalid TextureStage::CombineMode value" << endl;
+  return GL_REPLACE;
+}
 
 
-        report_my_gl_errors();
-        if (success) {
-          return true;
-        }
-      }
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_texture_src_type
+//       Access: Protected, Static
+//  Description: Maps from the texture stage's CombineSource types
+//               to the corresponding OpenGL ids
+////////////////////////////////////////////////////////////////////
+GLint CLP(GraphicsStateGuardian)::
+get_texture_src_type(TextureStage::CombineSource cs) {
+  switch (cs) {
+  case TextureStage::CS_undefined: // fall through
+  case TextureStage::CS_texture: return GL_TEXTURE;
+  case TextureStage::CS_constant: return GL_CONSTANT;
+  case TextureStage::CS_primary_color: return GL_PRIMARY_COLOR;
+  case TextureStage::CS_previous: return GL_PREVIOUS;
+  case TextureStage::CS_constant_color_scale: return GL_CONSTANT;
   }
   }
 
 
-  if (!gtc->_already_applied || 
-      gtc->_internal_format != internal_format ||
-      gtc->_width != width ||
-      gtc->_height != height ||
-      gtc->_depth != depth) {
-    // We need to reload a new image.
-#ifdef DO_PSTATS
-    _data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type));
-#endif
-    switch (target) {
-    case GL_TEXTURE_1D:
-      GLP(TexImage1D)(target, 0, internal_format,
-                      width, 0,
-                      external_format, component_type, image);
-      break;
+  GLCAT.error()
+    << "Invalid TextureStage::CombineSource value" << endl;
+  return GL_TEXTURE;
+}
 
 
-    case GL_TEXTURE_3D:
-      if (_supports_3d_texture) {
-        _glTexImage3D(target, 0, internal_format,
-                      width, height, depth, 0,
-                      external_format, component_type, image);
-      } else {
-        report_my_gl_errors();
-        return false;
-      }
-      break;
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_texture_operand_type
+//       Access: Protected, Static
+//  Description: Maps from the texture stage's CombineOperand types
+//               to the corresponding OpenGL ids
+////////////////////////////////////////////////////////////////////
+GLint CLP(GraphicsStateGuardian)::
+get_texture_operand_type(TextureStage::CombineOperand co) {
+  switch (co) {
+  case TextureStage::CO_undefined: // fall through
+  case TextureStage::CO_src_alpha: return GL_SRC_ALPHA;
+  case TextureStage::CO_one_minus_src_alpha: return GL_ONE_MINUS_SRC_ALPHA;
+  case TextureStage::CO_src_color: return GL_SRC_COLOR;
+  case TextureStage::CO_one_minus_src_color: return GL_ONE_MINUS_SRC_COLOR;
+  }
 
 
-    default:
-      GLP(TexImage2D)(target, 0, internal_format,
-                      width, height, 0,
-                      external_format, component_type, image);
-    }
-
-  } else {
-    // We can reload the image over the previous image, possibly
-    // saving on texture memory fragmentation.
-    switch (target) {
-    case GL_TEXTURE_1D:
-      GLP(TexSubImage1D)(target, 0, 0, width, 
-                         external_format, component_type, image);
-      break;
-
-    case GL_TEXTURE_3D:
-      if (_supports_3d_texture) {
-        _glTexSubImage3D(target, 0, 0, 0, 0, width, height, depth,
-                         external_format, component_type, image);
-      } else {
-        report_my_gl_errors();
-        return false;
-      }
-      break;
+  GLCAT.error()
+    << "Invalid TextureStage::CombineOperand value" << endl;
+  return GL_SRC_COLOR;
+}
 
 
-    default:
-      GLP(TexSubImage2D)(target, 0, 0, 0, width, height,
-                         external_format, component_type, image);
-      break;
-    }
-  }
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::get_fog_mode_type
+//       Access: Protected, Static
+//  Description: Maps from the fog types to gl version
+////////////////////////////////////////////////////////////////////
+GLenum CLP(GraphicsStateGuardian)::
+get_fog_mode_type(Fog::Mode m) {
+  switch(m) {
+  case Fog::M_linear: return GL_LINEAR;
+  case Fog::M_exponential: return GL_EXP;
+  case Fog::M_exponential_squared: return GL_EXP2;
+    /*
+      case Fog::M_spline: return GL_FOG_FUNC_SGIS;
+    */
 
 
-  // Report the error message explicitly if the GL texture creation
-  // failed.
-  GLenum error_code = GLP(GetError)();
-  if (error_code != GL_NO_ERROR) {
-    const GLubyte *error_string = GLUP(ErrorString)(error_code);
-    GLCAT.error()
-      << "GL texture creation failed for " << gtc->_texture->get_name();
-    if (error_string != (const GLubyte *)NULL) {
-      GLCAT.error(false)
-        << " : " << error_string;
-    }
-    GLCAT.error(false)
-      << "\n";
+  default:
+    GLCAT.error() << "Invalid Fog::Mode value" << endl;
+    return GL_EXP;
   }
   }
-
-  return true;
 }
 }
 
 
-
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_numeric_type
+//     Function: GLGraphicsStateGuardian::get_blend_equation_type
 //       Access: Protected, Static
 //       Access: Protected, Static
-//  Description: Maps from the Geom's internal numeric type symbols
-//               to GL's.
+//  Description: Maps from ColorBlendAttrib::Mode to glBlendEquation
+//               value.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GLenum CLP(GraphicsStateGuardian)::
 GLenum CLP(GraphicsStateGuardian)::
-get_numeric_type(qpGeom::NumericType numeric_type) {
-  switch (numeric_type) {
-  case qpGeom::NT_uint16:
-    return GL_UNSIGNED_SHORT;
-
-  case qpGeom::NT_uint32:
-    return GL_UNSIGNED_INT;
-
-  case qpGeom::NT_uint8:
-  case qpGeom::NT_packed_dcba:
-  case qpGeom::NT_packed_dabc:
-    return GL_UNSIGNED_BYTE;
+get_blend_equation_type(ColorBlendAttrib::Mode mode) {
+  switch (mode) {
+  case ColorBlendAttrib::M_none:
+  case ColorBlendAttrib::M_add:
+    return GL_FUNC_ADD;
     
     
-  case qpGeom::NT_float32:
-    return GL_FLOAT;
-  }
+  case ColorBlendAttrib::M_subtract:
+    return GL_FUNC_SUBTRACT;
+    
+  case ColorBlendAttrib::M_inv_subtract:
+    return GL_FUNC_REVERSE_SUBTRACT;
+    
+  case ColorBlendAttrib::M_min:
+    return GL_MIN;
+    
+  case ColorBlendAttrib::M_max:
+    return GL_MAX;
+  }    
 
 
   GLCAT.error()
   GLCAT.error()
-    << "Invalid NumericType value (" << (int)numeric_type << ")\n";
-  return GL_UNSIGNED_BYTE;
+    << "Unknown color blend mode " << (int)mode << endl;
+  return GL_FUNC_ADD;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_texture_target
-//       Access: Protected
-//  Description: Maps from the Texture's texture type symbols to
-//               GL's.
+//     Function: GLGraphicsStateGuardian::get_blend_func
+//       Access: Protected, Static
+//  Description: Maps from ColorBlendAttrib::Operand to glBlendFunc
+//               value.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GLenum CLP(GraphicsStateGuardian)::
 GLenum CLP(GraphicsStateGuardian)::
-get_texture_target(Texture::TextureType texture_type) const {
-  switch (texture_type) {
-  case Texture::TT_1d_texture:
-    return GL_TEXTURE_1D;
+get_blend_func(ColorBlendAttrib::Operand operand) {
+  switch (operand) {
+  case ColorBlendAttrib::O_zero:
+    return GL_ZERO;
 
 
-  case Texture::TT_2d_texture:
-    return GL_TEXTURE_2D;
+  case ColorBlendAttrib::O_one:
+    return GL_ONE;
 
 
-  case Texture::TT_3d_texture:
-    if (_supports_3d_texture) {
-      return GL_TEXTURE_3D;
-    } else {
-      return GL_NONE;
-    }
+  case ColorBlendAttrib::O_incoming_color:
+    return GL_SRC_COLOR;
 
 
-  case Texture::TT_cube_map:
-    if (_supports_cube_map) {
-      return GL_TEXTURE_CUBE_MAP;
-    } else {
-      return GL_NONE;
-    }
+  case ColorBlendAttrib::O_one_minus_incoming_color:
+    return GL_ONE_MINUS_SRC_COLOR;
+
+  case ColorBlendAttrib::O_fbuffer_color:
+    return GL_DST_COLOR;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_color:
+    return GL_ONE_MINUS_DST_COLOR;
+
+  case ColorBlendAttrib::O_incoming_alpha:
+    return GL_SRC_ALPHA;
+
+  case ColorBlendAttrib::O_one_minus_incoming_alpha:
+    return GL_ONE_MINUS_SRC_ALPHA;
+
+  case ColorBlendAttrib::O_fbuffer_alpha:
+    return GL_DST_ALPHA;
+
+  case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
+    return GL_ONE_MINUS_DST_ALPHA;
+
+  case ColorBlendAttrib::O_constant_color:
+  case ColorBlendAttrib::O_color_scale:
+    return GL_CONSTANT_COLOR;
+
+  case ColorBlendAttrib::O_one_minus_constant_color:
+  case ColorBlendAttrib::O_one_minus_color_scale:
+    return GL_ONE_MINUS_CONSTANT_COLOR;
+
+  case ColorBlendAttrib::O_constant_alpha:
+  case ColorBlendAttrib::O_alpha_scale:
+    return GL_CONSTANT_ALPHA;
+
+  case ColorBlendAttrib::O_one_minus_constant_alpha:
+  case ColorBlendAttrib::O_one_minus_alpha_scale:
+    return GL_ONE_MINUS_CONSTANT_ALPHA;
+
+  case ColorBlendAttrib::O_incoming_color_saturate:
+    return GL_SRC_ALPHA_SATURATE;
   }
   }
 
 
-  GLCAT.error() << "Invalid Texture::TextureType value!\n";
-  return GL_TEXTURE_2D;
+  GLCAT.error()
+    << "Unknown color blend operand " << (int)operand << endl;
+  return GL_ZERO;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_texture_wrap_mode
-//       Access: Protected, Static
-//  Description: Maps from the Texture's internal wrap mode symbols to
-//               GL's.
+//     Function: GLGraphicsStateGuardian::get_usage
+//       Access: Public, Static
+//  Description: Maps from UsageHint to the GL symbol.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 GLenum CLP(GraphicsStateGuardian)::
 GLenum CLP(GraphicsStateGuardian)::
-get_texture_wrap_mode(Texture::WrapMode wm) {
-  if (CLP(ignore_clamp)) {
-    return GL_REPEAT;
-  }
-  switch (wm) {
-  case Texture::WM_clamp:
-    return _edge_clamp;
-
-  case Texture::WM_repeat:
-    return GL_REPEAT;
-
-  case Texture::WM_mirror:
-    return _mirror_repeat;
+get_usage(qpGeom::UsageHint usage_hint) {
+  switch (usage_hint) {
+  case qpGeom::UH_stream:
+    return GL_STREAM_DRAW;
 
 
-  case Texture::WM_mirror_once:
-    return _mirror_border_clamp;
+  case qpGeom::UH_static:
+  case qpGeom::UH_unspecified:
+    return GL_STATIC_DRAW;
 
 
-  case Texture::WM_border_color:
-    return _border_clamp;
+  case qpGeom::UH_dynamic:
+    return GL_DYNAMIC_DRAW;
 
 
-  case Texture::WM_invalid:
+  case qpGeom::UH_client:
     break;
     break;
   }
   }
-  GLCAT.error() << "Invalid Texture::WrapMode value!\n";
-  return _edge_clamp;
+
+  GLCAT.error()
+    << "Unexpected usage_hint " << (int)usage_hint << endl;
+  return GL_STATIC_DRAW;
 }
 }
 
 
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_texture_filter_type
-//       Access: Protected, Static
-//  Description: Maps from the Texture's internal filter type symbols
-//               to GL's.
+//     Function: GLGraphicsStateGuardian::print_gfx_visual
+//       Access: Public
+//  Description: Prints a description of the current visual selected.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLenum CLP(GraphicsStateGuardian)::
-get_texture_filter_type(Texture::FilterType ft, bool ignore_mipmaps) {
-  if (CLP(ignore_filters)) {
-    return GL_NEAREST;
-
-  } else if (ignore_mipmaps) {
-    switch (ft) {
-    case Texture::FT_nearest_mipmap_nearest:
-    case Texture::FT_nearest:
-      return GL_NEAREST;
-    case Texture::FT_linear:
-    case Texture::FT_linear_mipmap_nearest:
-    case Texture::FT_nearest_mipmap_linear:
-    case Texture::FT_linear_mipmap_linear:
-      return GL_LINEAR;
-    case Texture::FT_invalid:
-      break;
-    }
+void CLP(GraphicsStateGuardian)::
+print_gfx_visual() {
+  GLint i;
+  GLboolean j;
+  cout << "Graphics Visual Info (# bits of each):" << endl;
 
 
-  } else {
-    switch (ft) {
-    case Texture::FT_nearest:
-      return GL_NEAREST;
-    case Texture::FT_linear:
-      return GL_LINEAR;
-    case Texture::FT_nearest_mipmap_nearest:
-      return GL_NEAREST_MIPMAP_NEAREST;
-    case Texture::FT_linear_mipmap_nearest:
-      return GL_LINEAR_MIPMAP_NEAREST;
-    case Texture::FT_nearest_mipmap_linear:
-      return GL_NEAREST_MIPMAP_LINEAR;
-    case Texture::FT_linear_mipmap_linear:
-      return GL_LINEAR_MIPMAP_LINEAR;
-    case Texture::FT_invalid:
-      break;
-    }
+  cout << "RGBA: ";
+  GLP(GetIntegerv)( GL_RED_BITS, &i ); cout << i << " ";
+  GLP(GetIntegerv)( GL_GREEN_BITS, &i ); cout << i << " ";
+  GLP(GetIntegerv)( GL_BLUE_BITS, &i ); cout << i << " ";
+  GLP(GetIntegerv)( GL_ALPHA_BITS, &i ); cout << i << endl;
+
+  cout << "Accum RGBA: ";
+  GLP(GetIntegerv)( GL_ACCUM_RED_BITS, &i ); cout << i << " ";
+  GLP(GetIntegerv)( GL_ACCUM_GREEN_BITS, &i ); cout << i << " ";
+  GLP(GetIntegerv)( GL_ACCUM_BLUE_BITS, &i ); cout << i << " ";
+  GLP(GetIntegerv)( GL_ACCUM_ALPHA_BITS, &i ); cout << i << endl;
+
+  GLP(GetIntegerv)( GL_INDEX_BITS, &i ); cout << "Color Index: " << i << endl;
+
+  GLP(GetIntegerv)( GL_DEPTH_BITS, &i ); cout << "Depth: " << i << endl;
+  GLP(GetIntegerv)( GL_ALPHA_BITS, &i ); cout << "Alpha: " << i << endl;
+  GLP(GetIntegerv)( GL_STENCIL_BITS, &i ); cout << "Stencil: " << i << endl;
+
+  GLP(GetBooleanv)( GL_DOUBLEBUFFER, &j ); cout << "DoubleBuffer? "
+                                             << (int)j << endl;
+
+  GLP(GetBooleanv)( GL_STEREO, &j ); cout << "Stereo? " << (int)j << endl;
+
+  if (_supports_multisample) {
+    GLP(GetBooleanv)( GL_MULTISAMPLE, &j ); cout << "Multisample? " << (int)j << endl;
+    GLP(GetIntegerv)( GL_SAMPLES, &i ); cout << "Samples: " << i << endl;
   }
   }
-  GLCAT.error() << "Invalid Texture::FilterType value!\n";
-  return GL_NEAREST;
+
+  GLP(GetBooleanv)( GL_BLEND, &j ); cout << "Blend? " << (int)j << endl;
+  GLP(GetBooleanv)( GL_POINT_SMOOTH, &j ); cout << "Point Smooth? "
+                                             << (int)j << endl;
+  GLP(GetBooleanv)( GL_LINE_SMOOTH, &j ); cout << "Line Smooth? "
+                                            << (int)j << endl;
+
+  GLP(GetIntegerv)( GL_AUX_BUFFERS, &i ); cout << "Aux Buffers: " << i << endl;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_component_type
-//       Access: Protected, Static
-//  Description: Maps from the Texture's internal ComponentType symbols
-//               to GL's.
+//     Function: GLGraphicsStateGuardian::issue_scaled_color
+//       Access: Public
+//  Description: Transform the color by the current color matrix, and
+//               calls the appropriate glColor function.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLenum CLP(GraphicsStateGuardian)::
-get_component_type(Texture::ComponentType component_type) {
-  switch (component_type) {
-  case Texture::T_unsigned_byte:
-    return GL_UNSIGNED_BYTE;
-  case Texture::T_unsigned_short:
-    return GL_UNSIGNED_SHORT;
-  case Texture::T_float:
-    return GL_FLOAT;
+void CLP(GraphicsStateGuardian)::
+issue_scaled_color(const Colorf &color) const {
+  Colorf transformed
+    (color[0] * _current_color_scale[0],
+     color[1] * _current_color_scale[1],
+     color[2] * _current_color_scale[2],
+     color[3] * _current_color_scale[3]);
 
 
-  default:
-    GLCAT.error() << "Invalid Texture::Type value!\n";
-    return GL_UNSIGNED_BYTE;
-  }
+  GLP(Color4fv)(transformed.get_data());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_external_image_format
-//       Access: Protected
-//  Description: Maps from the Texture's Format symbols
-//               to GL's.
+//     Function: GLGraphicsStateGuardian::slot_new_light
+//       Access: Protected, Virtual
+//  Description: This will be called by the base class before a
+//               particular light id will be used for the first time.
+//               It is intended to allow the derived class to reserve
+//               any additional resources, if required, for the new
+//               light; and also to indicate whether the hardware
+//               supports this many simultaneous lights.
+//
+//               The return value should be true if the additional
+//               light is supported, or false if it is not.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLint CLP(GraphicsStateGuardian)::
-get_external_image_format(Texture::Format format) const {
-  switch (format) {
-  case Texture::F_color_index:
-    return GL_COLOR_INDEX;
-  case Texture::F_stencil_index:
-    return GL_STENCIL_INDEX;
-  case Texture::F_depth_component:
-    return GL_DEPTH_COMPONENT;
-  case Texture::F_red:
-    return GL_RED;
-  case Texture::F_green:
-    return GL_GREEN;
-  case Texture::F_blue:
-    return GL_BLUE;
-  case Texture::F_alpha:
-    return GL_ALPHA;
-  case Texture::F_rgb:
-  case Texture::F_rgb5:
-  case Texture::F_rgb8:
-  case Texture::F_rgb12:
-  case Texture::F_rgb332:
-    return _supports_bgr ? GL_BGR : GL_RGB;
-  case Texture::F_rgba:
-  case Texture::F_rgbm:
-  case Texture::F_rgba4:
-  case Texture::F_rgba5:
-  case Texture::F_rgba8:
-  case Texture::F_rgba12:
-    return _supports_bgr ? GL_BGRA : GL_RGBA;
-  case Texture::F_luminance:
-    return GL_LUMINANCE;
-  case Texture::F_luminance_alphamask:
-  case Texture::F_luminance_alpha:
-    return GL_LUMINANCE_ALPHA;
-  }
-  GLCAT.error()
-    << "Invalid Texture::Format value in get_external_image_format(): "
-    << (int)format << "\n";
-  return GL_RGB;
+bool CLP(GraphicsStateGuardian)::
+slot_new_light(int light_id) {
+  return (light_id < _max_lights);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_internal_image_format
-//       Access: Protected, Static
-//  Description: Maps from the Texture's Format symbols to a
-//               suitable internal format for GL textures.
+//     Function: GLGraphicsStateGuardian::enable_lighting
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by a derived class to
+//               enable or disable the use of lighting overall.  This
+//               is called by issue_light() according to whether any
+//               lights are in use or not.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLint CLP(GraphicsStateGuardian)::
-get_internal_image_format(Texture::Format format) {
-  switch (format) {
-  case Texture::F_rgba:
-  case Texture::F_rgbm:
-    return GL_RGBA;
-  case Texture::F_rgba4:
-    return GL_RGBA4;
-  case Texture::F_rgba8:
-    return GL_RGBA8;
-  case Texture::F_rgba12:
-    return GL_RGBA12;
-
-  case Texture::F_rgb:
-    return GL_RGB;
-  case Texture::F_rgb5:
-    return GL_RGB5;
-  case Texture::F_rgba5:
-    return GL_RGB5_A1;
-  case Texture::F_rgb8:
-    return GL_RGB8;
-  case Texture::F_rgb12:
-    return GL_RGB12;
-  case Texture::F_rgb332:
-    return GL_R3_G3_B2;
-
-  case Texture::F_alpha:
-    return GL_ALPHA;
-
-  case Texture::F_red:
-  case Texture::F_green:
-  case Texture::F_blue:
-  case Texture::F_luminance:
-    return GL_LUMINANCE;
-  case Texture::F_luminance_alpha:
-  case Texture::F_luminance_alphamask:
-    return GL_LUMINANCE_ALPHA;
-
-  default:
-    GLCAT.error()
-      << "Invalid image format in get_internal_image_format(): "
-      << (int)format << "\n";
-    return GL_RGB;
+void CLP(GraphicsStateGuardian)::
+enable_lighting(bool enable) {
+  if (enable) {
+    GLP(Enable)(GL_LIGHTING);
+  } else {
+    GLP(Disable)(GL_LIGHTING);
   }
   }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_external_texture_bytes
-//       Access: Protected, Static
-//  Description: Computes the number of bytes that should be in the
-//               "external", or local, texture buffer before
-//               transferring to OpenGL.  This is just used for
-//               sending data to PStats.
+//     Function: GLGraphicsStateGuardian::set_ambient_light
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by a derived class to
+//               indicate the color of the ambient light that should
+//               be in effect.  This is called by issue_light() after
+//               all other lights have been enabled or disabled.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-int CLP(GraphicsStateGuardian)::
-get_external_texture_bytes(int width, int height, int depth,
-                           GLint external_format, GLenum component_type) {
-  int num_components;
-  switch (external_format) {
-  case GL_COLOR_INDEX:
-  case GL_STENCIL_INDEX:
-  case GL_DEPTH_COMPONENT:
-  case GL_RED:
-  case GL_GREEN:
-  case GL_BLUE:
-  case GL_ALPHA:
-  case GL_LUMINANCE:
-    num_components = 1;
-    break;
-
-  case GL_LUMINANCE_ALPHA:
-    num_components = 2;
-    break;
+void CLP(GraphicsStateGuardian)::
+set_ambient_light(const Colorf &color) {
+  GLP(LightModelfv)(GL_LIGHT_MODEL_AMBIENT, color.get_data());
+}
 
 
-  case GL_BGR: 
-  case GL_RGB:
-    num_components = 3;
-    break;
-
-  case GL_BGRA: 
-  case GL_RGBA:
-    num_components = 4;
-    break;
-    
-  default:
-    GLCAT.error()
-      << "Unexpected external_format in get_external_texture_bytes(): "
-      << hex << external_format << dec << "\n";
-    num_components = 3;
-  }
-
-  int component_width;
-  switch (component_type) {
-  case GL_UNSIGNED_BYTE:
-    component_width = 1;
-    break;
-
-  case GL_UNSIGNED_SHORT:
-    component_width = 2;
-    break;
-
-  case GL_FLOAT:
-    component_width = 4;
-    break;
-
-  default:
-    GLCAT.error()
-      << "Unexpected component_type in get_external_texture_bytes(): "
-      << hex << component_type << dec << "\n";
-    component_width = 1;
-  }
-
-  return width * height * depth * num_components * component_width;
-}
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::enable_light
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by a derived class to
+//               enable the indicated light id.  A specific Light will
+//               already have been bound to this id via bind_light().
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+enable_light(int light_id, bool enable) {
+  if (enable) {
+    GLP(Enable)(get_light_id(light_id));
+  } else {
+    GLP(Disable)(get_light_id(light_id));
+  }
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_texture_apply_mode_type
-//       Access: Protected, Static
-//  Description: Maps from the texture stage's mode types
-//               to the corresponding OpenGL ids
+//     Function: GLGraphicsStateGuardian::begin_bind_lights
+//       Access: Protected, Virtual
+//  Description: Called immediately before bind_light() is called,
+//               this is intended to provide the derived class a hook
+//               in which to set up some state (like transform) that
+//               might apply to several lights.
+//
+//               The sequence is: begin_bind_lights() will be called,
+//               then one or more bind_light() calls, then
+//               end_bind_lights().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLint CLP(GraphicsStateGuardian)::
-get_texture_apply_mode_type(TextureStage::Mode am) {
-  switch (am) {
-  case TextureStage::M_modulate: return GL_MODULATE;
-  case TextureStage::M_decal: return GL_DECAL;
-  case TextureStage::M_blend: return GL_BLEND;
-  case TextureStage::M_replace: return GL_REPLACE;
-  case TextureStage::M_add: return GL_ADD;
-  case TextureStage::M_combine: return GL_COMBINE;
-  case TextureStage::M_blend_color_scale: return GL_BLEND;
-  }
-
-  GLCAT.error()
-    << "Invalid TextureStage::Mode value" << endl;
-  return GL_MODULATE;
+void CLP(GraphicsStateGuardian)::
+begin_bind_lights() {
+  // We need to temporarily load a new matrix so we can define the
+  // light in a known coordinate system.  We pick the transform of the
+  // root.  (Alternatively, we could leave the current transform where
+  // it is and compute the light position relative to that transform
+  // instead of relative to the root, by composing with the matrix
+  // computed by _transform->invert_compose(render_transform).  But I
+  // think loading a completely new matrix is simpler.)
+  GLP(MatrixMode)(GL_MODELVIEW);
+  GLP(PushMatrix)();
+  GLP(LoadMatrixf)(_scene_setup->get_render_transform()->get_mat().get_data());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_texture_combine_type
-//       Access: Protected, Static
-//  Description: Maps from the texture stage's CombineMode types
-//               to the corresponding OpenGL ids
+//     Function: GLGraphicsStateGuardian::end_bind_lights
+//       Access: Protected, Virtual
+//  Description: Called after before bind_light() has been called one
+//               or more times (but before any geometry is issued or
+//               additional state is changed), this is intended to
+//               clean up any temporary changes to the state that may
+//               have been made by begin_bind_lights().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLint CLP(GraphicsStateGuardian)::
-get_texture_combine_type(TextureStage::CombineMode cm) {
-  switch (cm) {
-  case TextureStage::CM_undefined: // fall through
-  case TextureStage::CM_replace: return GL_REPLACE;
-  case TextureStage::CM_modulate: return GL_MODULATE;
-  case TextureStage::CM_add: return GL_ADD;
-  case TextureStage::CM_add_signed: return GL_ADD_SIGNED;
-  case TextureStage::CM_interpolate: return GL_INTERPOLATE;
-  case TextureStage::CM_subtract: return GL_SUBTRACT;
-  case TextureStage::CM_dot3_rgb: return GL_DOT3_RGB;
-  case TextureStage::CM_dot3_rgba: return GL_DOT3_RGBA;
-  }
-  GLCAT.error()
-    << "Invalid TextureStage::CombineMode value" << endl;
-  return GL_REPLACE;
+void CLP(GraphicsStateGuardian)::
+end_bind_lights() {
+  GLP(MatrixMode)(GL_MODELVIEW);
+  GLP(PopMatrix)();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_texture_src_type
-//       Access: Protected, Static
-//  Description: Maps from the texture stage's CombineSource types
-//               to the corresponding OpenGL ids
+//     Function: GLGraphicsStateGuardian::slot_new_clip_plane
+//       Access: Protected, Virtual
+//  Description: This will be called by the base class before a
+//               particular clip plane id will be used for the first
+//               time.  It is intended to allow the derived class to
+//               reserve any additional resources, if required, for
+//               the new clip plane; and also to indicate whether the
+//               hardware supports this many simultaneous clipping
+//               planes.
+//
+//               The return value should be true if the additional
+//               plane is supported, or false if it is not.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLint CLP(GraphicsStateGuardian)::
-get_texture_src_type(TextureStage::CombineSource cs) {
-  switch (cs) {
-  case TextureStage::CS_undefined: // fall through
-  case TextureStage::CS_texture: return GL_TEXTURE;
-  case TextureStage::CS_constant: return GL_CONSTANT;
-  case TextureStage::CS_primary_color: return GL_PRIMARY_COLOR;
-  case TextureStage::CS_previous: return GL_PREVIOUS;
-  case TextureStage::CS_constant_color_scale: return GL_CONSTANT;
-  }
-
-  GLCAT.error()
-    << "Invalid TextureStage::CombineSource value" << endl;
-  return GL_TEXTURE;
+bool CLP(GraphicsStateGuardian)::
+slot_new_clip_plane(int plane_id) {
+  return (plane_id < _max_clip_planes);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_texture_operand_type
-//       Access: Protected, Static
-//  Description: Maps from the texture stage's CombineOperand types
-//               to the corresponding OpenGL ids
+//     Function: GLGraphicsStateGuardian::enable_clip_plane
+//       Access: Protected, Virtual
+//  Description: Intended to be overridden by a derived class to
+//               enable the indicated clip_plane id.  A specific
+//               PlaneNode will already have been bound to this id via
+//               bind_clip_plane().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLint CLP(GraphicsStateGuardian)::
-get_texture_operand_type(TextureStage::CombineOperand co) {
-  switch (co) {
-  case TextureStage::CO_undefined: // fall through
-  case TextureStage::CO_src_alpha: return GL_SRC_ALPHA;
-  case TextureStage::CO_one_minus_src_alpha: return GL_ONE_MINUS_SRC_ALPHA;
-  case TextureStage::CO_src_color: return GL_SRC_COLOR;
-  case TextureStage::CO_one_minus_src_color: return GL_ONE_MINUS_SRC_COLOR;
+void CLP(GraphicsStateGuardian)::
+enable_clip_plane(int plane_id, bool enable) {
+  if (enable) {
+    GLP(Enable)(get_clip_plane_id(plane_id));
+  } else {
+    GLP(Disable)(get_clip_plane_id(plane_id));
   }
   }
-
-  GLCAT.error()
-    << "Invalid TextureStage::CombineOperand value" << endl;
-  return GL_SRC_COLOR;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_fog_mode_type
-//       Access: Protected, Static
-//  Description: Maps from the fog types to gl version
+//     Function: GLGraphicsStateGuardian::begin_bind_clip_planes
+//       Access: Protected, Virtual
+//  Description: Called immediately before bind_clip_plane() is called,
+//               this is intended to provide the derived class a hook
+//               in which to set up some state (like transform) that
+//               might apply to several clip_planes.
+//
+//               The sequence is: begin_bind_clip_planes() will be called,
+//               then one or more bind_clip_plane() calls, then
+//               end_bind_clip_planes().
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLenum CLP(GraphicsStateGuardian)::
-get_fog_mode_type(Fog::Mode m) {
-  switch(m) {
-  case Fog::M_linear: return GL_LINEAR;
-  case Fog::M_exponential: return GL_EXP;
-  case Fog::M_exponential_squared: return GL_EXP2;
-    /*
-      case Fog::M_spline: return GL_FOG_FUNC_SGIS;
-    */
-
-  default:
-    GLCAT.error() << "Invalid Fog::Mode value" << endl;
-    return GL_EXP;
-  }
+void CLP(GraphicsStateGuardian)::
+begin_bind_clip_planes() {
+  // We need to temporarily load a new matrix so we can define the
+  // clip_plane in a known coordinate system.  We pick the transform of the
+  // root.  (Alternatively, we could leave the current transform where
+  // it is and compute the clip_plane position relative to that transform
+  // instead of relative to the root, by composing with the matrix
+  // computed by _transform->invert_compose(render_transform).  But I
+  // think loading a completely new matrix is simpler.)
+  GLP(MatrixMode)(GL_MODELVIEW);
+  GLP(PushMatrix)();
+  GLP(LoadMatrixf)(_scene_setup->get_render_transform()->get_mat().get_data());
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_blend_equation_type
-//       Access: Protected, Static
-//  Description: Maps from ColorBlendAttrib::Mode to glBlendEquation
-//               value.
+//     Function: GLGraphicsStateGuardian::bind_clip_plane
+//       Access: Protected, Virtual
+//  Description: Called the first time a particular clip_plane has been
+//               bound to a given id within a frame, this should set
+//               up the associated hardware clip_plane with the clip_plane's
+//               properties.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLenum CLP(GraphicsStateGuardian)::
-get_blend_equation_type(ColorBlendAttrib::Mode mode) {
-  switch (mode) {
-  case ColorBlendAttrib::M_none:
-  case ColorBlendAttrib::M_add:
-    return GL_FUNC_ADD;
-    
-  case ColorBlendAttrib::M_subtract:
-    return GL_FUNC_SUBTRACT;
-    
-  case ColorBlendAttrib::M_inv_subtract:
-    return GL_FUNC_REVERSE_SUBTRACT;
-    
-  case ColorBlendAttrib::M_min:
-    return GL_MIN;
-    
-  case ColorBlendAttrib::M_max:
-    return GL_MAX;
-  }    
+void CLP(GraphicsStateGuardian)::
+bind_clip_plane(const NodePath &plane, int plane_id) {
+  GLenum id = get_clip_plane_id(plane_id);
 
 
-  GLCAT.error()
-    << "Unknown color blend mode " << (int)mode << endl;
-  return GL_FUNC_ADD;
+  CPT(TransformState) transform = plane.get_transform(_scene_setup->get_scene_root());
+  const PlaneNode *plane_node;
+  DCAST_INTO_V(plane_node, plane.node());
+  Planef xformed_plane = plane_node->get_plane() * transform->get_mat();
+
+  Planed double_plane(LCAST(double, xformed_plane));
+  GLP(ClipPlane)(id, double_plane.get_data());
+
+  report_my_gl_errors();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_blend_func
-//       Access: Protected, Static
-//  Description: Maps from ColorBlendAttrib::Operand to glBlendFunc
-//               value.
-////////////////////////////////////////////////////////////////////
-GLenum CLP(GraphicsStateGuardian)::
-get_blend_func(ColorBlendAttrib::Operand operand) {
-  switch (operand) {
-  case ColorBlendAttrib::O_zero:
-    return GL_ZERO;
-
-  case ColorBlendAttrib::O_one:
-    return GL_ONE;
-
-  case ColorBlendAttrib::O_incoming_color:
-    return GL_SRC_COLOR;
-
-  case ColorBlendAttrib::O_one_minus_incoming_color:
-    return GL_ONE_MINUS_SRC_COLOR;
-
-  case ColorBlendAttrib::O_fbuffer_color:
-    return GL_DST_COLOR;
-
-  case ColorBlendAttrib::O_one_minus_fbuffer_color:
-    return GL_ONE_MINUS_DST_COLOR;
-
-  case ColorBlendAttrib::O_incoming_alpha:
-    return GL_SRC_ALPHA;
-
-  case ColorBlendAttrib::O_one_minus_incoming_alpha:
-    return GL_ONE_MINUS_SRC_ALPHA;
-
-  case ColorBlendAttrib::O_fbuffer_alpha:
-    return GL_DST_ALPHA;
-
-  case ColorBlendAttrib::O_one_minus_fbuffer_alpha:
-    return GL_ONE_MINUS_DST_ALPHA;
-
-  case ColorBlendAttrib::O_constant_color:
-  case ColorBlendAttrib::O_color_scale:
-    return GL_CONSTANT_COLOR;
-
-  case ColorBlendAttrib::O_one_minus_constant_color:
-  case ColorBlendAttrib::O_one_minus_color_scale:
-    return GL_ONE_MINUS_CONSTANT_COLOR;
-
-  case ColorBlendAttrib::O_constant_alpha:
-  case ColorBlendAttrib::O_alpha_scale:
-    return GL_CONSTANT_ALPHA;
-
-  case ColorBlendAttrib::O_one_minus_constant_alpha:
-  case ColorBlendAttrib::O_one_minus_alpha_scale:
-    return GL_ONE_MINUS_CONSTANT_ALPHA;
-
-  case ColorBlendAttrib::O_incoming_color_saturate:
-    return GL_SRC_ALPHA_SATURATE;
-  }
-
-  GLCAT.error()
-    << "Unknown color blend operand " << (int)operand << endl;
-  return GL_ZERO;
+//     Function: GLGraphicsStateGuardian::end_bind_clip_planes
+//       Access: Protected, Virtual
+//  Description: Called after before bind_clip_plane() has been called one
+//               or more times (but before any geometry is issued or
+//               additional state is changed), this is intended to
+//               clean up any temporary changes to the state that may
+//               have been made by begin_bind_clip_planes().
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+end_bind_clip_planes() {
+  GLP(MatrixMode)(GL_MODELVIEW);
+  GLP(PopMatrix)();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_usage
-//       Access: Public, Static
-//  Description: Maps from UsageHint to the GL symbol.
+//     Function: GLGraphicsStateGuardian::set_blend_mode
+//       Access: Protected, Virtual
+//  Description: Called after any of the things that might change
+//               blending state have changed, this function is
+//               responsible for setting the appropriate color
+//               blending mode based on the current properties.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-GLenum CLP(GraphicsStateGuardian)::
-get_usage(qpGeom::UsageHint usage_hint) {
-  switch (usage_hint) {
-  case qpGeom::UH_stream:
-    return GL_STREAM_DRAW;
+void CLP(GraphicsStateGuardian)::
+set_blend_mode() {
+  // If color_write_mode is off, we disable writing to the color using
+  // blending.  This case is only used if we can't use GLP(ColorMask) to
+  // disable the color writing for some reason (usually a driver
+  // problem).
+  if (_color_write_mode == ColorWriteAttrib::M_off) {
+    enable_multisample_alpha_one(false);
+    enable_multisample_alpha_mask(false);
+    enable_blend(true);
+    _glBlendEquation(GL_FUNC_ADD);
+    GLP(BlendFunc)(GL_ZERO, GL_ONE);
+   return;
+  }
 
 
-  case qpGeom::UH_static:
-  case qpGeom::UH_unspecified:
-    return GL_STATIC_DRAW;
+  // Is there a color blend set?
+  if (_color_blend_mode != ColorBlendAttrib::M_none) {
+    enable_multisample_alpha_one(false);
+    enable_multisample_alpha_mask(false);
+    enable_blend(true);
+    _glBlendEquation(get_blend_equation_type(_color_blend_mode));
+    GLP(BlendFunc)(get_blend_func(_color_blend->get_operand_a()),
+                   get_blend_func(_color_blend->get_operand_b()));
 
 
-  case qpGeom::UH_dynamic:
-    return GL_DYNAMIC_DRAW;
+    if (_color_blend_involves_color_scale) {
+      // Apply the current color scale to the blend mode.
+      _glBlendColor(_current_color_scale[0], _current_color_scale[1], 
+                    _current_color_scale[2], _current_color_scale[3]);
+      
+    } else {
+      Colorf c = _color_blend->get_color();
+      _glBlendColor(c[0], c[1], c[2], c[3]);
+    }
+    return;
+  }
 
 
-  case qpGeom::UH_client:
+  // No color blend; is there a transparency set?
+  switch (_transparency_mode) {
+  case TransparencyAttrib::M_none:
+  case TransparencyAttrib::M_binary:
+    break;
+    
+  case TransparencyAttrib::M_alpha:
+  case TransparencyAttrib::M_dual:
+    enable_multisample_alpha_one(false);
+    enable_multisample_alpha_mask(false);
+    enable_blend(true);
+    _glBlendEquation(GL_FUNC_ADD);
+    GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    return;
+    
+  case TransparencyAttrib::M_multisample:
+    // We need to enable *both* of these in M_multisample case.
+    enable_multisample_alpha_one(true);
+    enable_multisample_alpha_mask(true);
+    enable_blend(false);
+    return;
+    
+  case TransparencyAttrib::M_multisample_mask:
+    enable_multisample_alpha_one(false);
+    enable_multisample_alpha_mask(true);
+    enable_blend(false);
+    return;
+    
+  default:
+    GLCAT.error()
+      << "invalid transparency mode " << (int)_transparency_mode << endl;
     break;
     break;
   }
   }
 
 
-  GLCAT.error()
-    << "Unexpected usage_hint " << (int)usage_hint << endl;
-  return GL_STATIC_DRAW;
-}
+  if (_line_smooth_enabled || _point_smooth_enabled) {
+    // If we have either of these turned on, we also need to have
+    // blend mode enabled in order to see it.
+    enable_multisample_alpha_one(false);
+    enable_multisample_alpha_mask(false);
+    enable_blend(true);
+    _glBlendEquation(GL_FUNC_ADD);
+    GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+    return;
+  }
+
+  // For best polygon smoothing, we need:
+  // (1) a frame buffer that supports alpha
+  // (2) sort polygons front-to-back
+  // (3) glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
+  //
+  // Since these modes have other implications for the application, we
+  // don't attempt to do this by default.  If you really want good
+  // polygon smoothing (and you don't have multisample support), do
+  // all this yourself.
 
 
+  // Nothing's set, so disable blending.
+  enable_multisample_alpha_one(false);
+  enable_multisample_alpha_mask(false);
+  enable_blend(false);
+}
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::print_gfx_visual
-//       Access: Public
-//  Description: Prints a description of the current visual selected.
+//     Function: GLGraphicsStateGuardian::finish_modify_state
+//       Access: Protected, Virtual
+//  Description: Called after the GSG state has been modified via
+//               modify_state() or set_state(), this hook is provided
+//               for the derived class to do any further state setup
+//               work.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
-print_gfx_visual() {
-  GLint i;
-  GLboolean j;
-  cout << "Graphics Visual Info (# bits of each):" << endl;
-
-  cout << "RGBA: ";
-  GLP(GetIntegerv)( GL_RED_BITS, &i ); cout << i << " ";
-  GLP(GetIntegerv)( GL_GREEN_BITS, &i ); cout << i << " ";
-  GLP(GetIntegerv)( GL_BLUE_BITS, &i ); cout << i << " ";
-  GLP(GetIntegerv)( GL_ALPHA_BITS, &i ); cout << i << endl;
-
-  cout << "Accum RGBA: ";
-  GLP(GetIntegerv)( GL_ACCUM_RED_BITS, &i ); cout << i << " ";
-  GLP(GetIntegerv)( GL_ACCUM_GREEN_BITS, &i ); cout << i << " ";
-  GLP(GetIntegerv)( GL_ACCUM_BLUE_BITS, &i ); cout << i << " ";
-  GLP(GetIntegerv)( GL_ACCUM_ALPHA_BITS, &i ); cout << i << endl;
+finish_modify_state() {
+  GraphicsStateGuardian::finish_modify_state();
 
 
-  GLP(GetIntegerv)( GL_INDEX_BITS, &i ); cout << "Color Index: " << i << endl;
+  // Apply the texture, if it needs to be reapplied.
+  if (_texture_stale) {
+    _texture_stale = false;
+    do_issue_texture();
+  }
 
 
-  GLP(GetIntegerv)( GL_DEPTH_BITS, &i ); cout << "Depth: " << i << endl;
-  GLP(GetIntegerv)( GL_ALPHA_BITS, &i ); cout << "Alpha: " << i << endl;
-  GLP(GetIntegerv)( GL_STENCIL_BITS, &i ); cout << "Stencil: " << i << endl;
+  // If one of the previously-loaded TexGen modes modified the texture
+  // matrix, then if either state changed, we have to change both of
+  // them now.
+  if (_tex_gen_modifies_mat &&
+      (_needs_tex_mat || _needs_tex_gen)) {
+    _needs_tex_mat = true;
+    _needs_tex_gen = true;
+  }
 
 
-  GLP(GetBooleanv)( GL_DOUBLEBUFFER, &j ); cout << "DoubleBuffer? "
-                                             << (int)j << endl;
+  // Apply the texture matrix, if needed.
+  if (_needs_tex_mat) {
+    _needs_tex_mat = false;
 
 
-  GLP(GetBooleanv)( GL_STEREO, &j ); cout << "Stereo? " << (int)j << endl;
+    int num_stages = _current_texture->get_num_on_stages();
+    nassertv(num_stages <= _max_texture_stages);
+    
+    for (int i = 0; i < num_stages; i++) {
+      TextureStage *stage = _current_texture->get_on_stage(i);
+      _glActiveTexture(GL_TEXTURE0 + i);
+      
+      GLP(MatrixMode)(GL_TEXTURE);
+      if (_current_tex_mat->has_stage(stage)) {
+        GLP(LoadMatrixf)(_current_tex_mat->get_mat(stage).get_data());
+      } else {
+        GLP(LoadIdentity)();
 
 
-  if (_supports_multisample) {
-    GLP(GetBooleanv)( GL_MULTISAMPLE, &j ); cout << "Multisample? " << (int)j << endl;
-    GLP(GetIntegerv)( GL_SAMPLES, &i ); cout << "Samples: " << i << endl;
+        // For some reason, the glLoadIdentity() call doesn't work on
+        // my Dell laptop's IBM OpenGL driver, when used in
+        // conjunction with glTexGen(), below.  But explicitly loading
+        // an identity matrix does work.  But this buggy-driver
+        // workaround might have other performance implications, so I
+        // leave it out.
+        //GLP(LoadMatrixf)(LMatrix4f::ident_mat().get_data());
+      }
+    }
+    report_my_gl_errors();
   }
   }
 
 
-  GLP(GetBooleanv)( GL_BLEND, &j ); cout << "Blend? " << (int)j << endl;
-  GLP(GetBooleanv)( GL_POINT_SMOOTH, &j ); cout << "Point Smooth? "
-                                             << (int)j << endl;
-  GLP(GetBooleanv)( GL_LINE_SMOOTH, &j ); cout << "Line Smooth? "
-                                            << (int)j << endl;
+  if (_needs_tex_gen) {
+    _needs_tex_gen = false;
+    bool force_normal = false;
 
 
-  GLP(GetIntegerv)( GL_AUX_BUFFERS, &i ); cout << "Aux Buffers: " << i << endl;
-}
+    int num_stages = _current_texture->get_num_on_stages();
+    nassertv(num_stages <= _max_texture_stages);
+    
+    // These are passed in for the four OBJECT_PLANE or EYE_PLANE
+    // values; they effectively define an identity matrix that maps
+    // the spatial coordinates one-for-one to UV's.  If you want a
+    // mapping other than identity, use a TexMatrixAttrib (or a
+    // TexProjectorEffect).
+    static const float s_data[4] = { 1, 0, 0, 0 };
+    static const float t_data[4] = { 0, 1, 0, 0 };
+    static const float r_data[4] = { 0, 0, 1, 0 };
+    static const float q_data[4] = { 0, 0, 0, 1 };
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::issue_scaled_color
-//       Access: Public
-//  Description: Transform the color by the current color matrix, and
-//               calls the appropriate glColor function.
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-issue_scaled_color(const Colorf &color) const {
-  Colorf transformed
-    (color[0] * _current_color_scale[0],
-     color[1] * _current_color_scale[1],
-     color[2] * _current_color_scale[2],
-     color[3] * _current_color_scale[3]);
+    _tex_gen_modifies_mat = false;
 
 
-  GLP(Color4fv)(transformed.get_data());
-}
+    bool got_point_sprites = false;
+    
+    for (int i = 0; i < num_stages; i++) {
+      TextureStage *stage = _current_texture->get_on_stage(i);
+      _glActiveTexture(GL_TEXTURE0 + i);
+      GLP(Disable)(GL_TEXTURE_GEN_S);
+      GLP(Disable)(GL_TEXTURE_GEN_T);
+      GLP(Disable)(GL_TEXTURE_GEN_R);
+      GLP(Disable)(GL_TEXTURE_GEN_Q);
+      if (_supports_point_sprite) {
+        GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
+      }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::slot_new_light
-//       Access: Protected, Virtual
-//  Description: This will be called by the base class before a
-//               particular light id will be used for the first time.
-//               It is intended to allow the derived class to reserve
-//               any additional resources, if required, for the new
-//               light; and also to indicate whether the hardware
-//               supports this many simultaneous lights.
-//
-//               The return value should be true if the additional
-//               light is supported, or false if it is not.
-////////////////////////////////////////////////////////////////////
-bool CLP(GraphicsStateGuardian)::
-slot_new_light(int light_id) {
-  return (light_id < _max_lights);
-}
+      TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage);
+      switch (mode) {
+      case TexGenAttrib::M_off:
+        break;
+        
+      case TexGenAttrib::M_eye_sphere_map:
+        GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+        GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+        GLP(Enable)(GL_TEXTURE_GEN_S);
+        GLP(Enable)(GL_TEXTURE_GEN_T);
+        force_normal = true;
+        break;
+        
+      case TexGenAttrib::M_eye_cube_map:
+      case TexGenAttrib::M_world_cube_map:
+        if (_supports_cube_map) {
+          if (mode != TexGenAttrib::M_eye_cube_map) {
+            // We dynamically transform normals from eye space to
+            // world space by applying the appropriate rotation
+            // transform to the current texture matrix.  Although it's
+            // tempting to try, we can't safely convert to object
+            // space, since this method doesn't get called with each
+            // different object.
+            CPT(TransformState) transform = _scene_setup->get_render_transform();
+            transform = transform->invert_compose(TransformState::make_identity());
+            LMatrix4f mat = transform->get_mat();
+            mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
+            GLP(MatrixMode)(GL_TEXTURE);
+            GLP(MultMatrixf)(mat.get_data());
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::enable_lighting
-//       Access: Protected, Virtual
-//  Description: Intended to be overridden by a derived class to
-//               enable or disable the use of lighting overall.  This
-//               is called by issue_light() according to whether any
-//               lights are in use or not.
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-enable_lighting(bool enable) {
-  if (enable) {
-    GLP(Enable)(GL_LIGHTING);
-  } else {
-    GLP(Disable)(GL_LIGHTING);
-  }
-}
+            // Now we need to reset the texture matrix next time
+            // around to undo this.
+            _tex_gen_modifies_mat = true;
+          }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::set_ambient_light
-//       Access: Protected, Virtual
-//  Description: Intended to be overridden by a derived class to
-//               indicate the color of the ambient light that should
-//               be in effect.  This is called by issue_light() after
-//               all other lights have been enabled or disabled.
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-set_ambient_light(const Colorf &color) {
-  GLP(LightModelfv)(GL_LIGHT_MODEL_AMBIENT, color.get_data());
-}
+          GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
+          GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
+          GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
+          GLP(Enable)(GL_TEXTURE_GEN_S);
+          GLP(Enable)(GL_TEXTURE_GEN_T);
+          GLP(Enable)(GL_TEXTURE_GEN_R);
+          force_normal = true;
+        }
+        break;
+        
+      case TexGenAttrib::M_eye_normal:
+      case TexGenAttrib::M_world_normal:
+        if (_supports_cube_map) {
+          if (mode != TexGenAttrib::M_eye_normal) {
+            // We dynamically transform normals from eye space to
+            // world space by applying the appropriate rotation
+            // transform to the current texture matrix.  Although it's
+            // tempting to try, we can't safely convert to object
+            // space, since this method doesn't get called with each
+            // different object.
+            CPT(TransformState) transform = _scene_setup->get_render_transform();
+            transform = transform->invert_compose(TransformState::make_identity());
+            LMatrix4f mat = transform->get_mat();
+            mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
+            GLP(MatrixMode)(GL_TEXTURE);
+            GLP(MultMatrixf)(mat.get_data());
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::enable_light
-//       Access: Protected, Virtual
-//  Description: Intended to be overridden by a derived class to
-//               enable the indicated light id.  A specific Light will
-//               already have been bound to this id via bind_light().
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-enable_light(int light_id, bool enable) {
-  if (enable) {
-    GLP(Enable)(get_light_id(light_id));
-  } else {
-    GLP(Disable)(get_light_id(light_id));
-  }
-}
+            // Now we need to reset the texture matrix next time
+            // around to undo this.
+            _tex_gen_modifies_mat = true;
+          }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::begin_bind_lights
-//       Access: Protected, Virtual
-//  Description: Called immediately before bind_light() is called,
-//               this is intended to provide the derived class a hook
-//               in which to set up some state (like transform) that
-//               might apply to several lights.
-//
-//               The sequence is: begin_bind_lights() will be called,
-//               then one or more bind_light() calls, then
-//               end_bind_lights().
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-begin_bind_lights() {
-  // We need to temporarily load a new matrix so we can define the
-  // light in a known coordinate system.  We pick the transform of the
-  // root.  (Alternatively, we could leave the current transform where
-  // it is and compute the light position relative to that transform
-  // instead of relative to the root, by composing with the matrix
-  // computed by _transform->invert_compose(render_transform).  But I
-  // think loading a completely new matrix is simpler.)
-  GLP(MatrixMode)(GL_MODELVIEW);
-  GLP(PushMatrix)();
-  GLP(LoadMatrixf)(_scene_setup->get_render_transform()->get_mat().get_data());
-}
+          GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
+          GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
+          GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
+          GLP(Enable)(GL_TEXTURE_GEN_S);
+          GLP(Enable)(GL_TEXTURE_GEN_T);
+          GLP(Enable)(GL_TEXTURE_GEN_R);
+          force_normal = true;
+        }
+        break;
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::end_bind_lights
-//       Access: Protected, Virtual
-//  Description: Called after before bind_light() has been called one
-//               or more times (but before any geometry is issued or
-//               additional state is changed), this is intended to
-//               clean up any temporary changes to the state that may
-//               have been made by begin_bind_lights().
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-end_bind_lights() {
-  GLP(MatrixMode)(GL_MODELVIEW);
-  GLP(PopMatrix)();
-}
+      case TexGenAttrib::M_object_position:
+        GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+        GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+        GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+        GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
+        
+        GLP(TexGenfv)(GL_S, GL_OBJECT_PLANE, s_data);
+        GLP(TexGenfv)(GL_T, GL_OBJECT_PLANE, t_data);
+        GLP(TexGenfv)(GL_R, GL_OBJECT_PLANE, r_data);
+        GLP(TexGenfv)(GL_Q, GL_OBJECT_PLANE, q_data);
+        
+        GLP(Enable)(GL_TEXTURE_GEN_S);
+        GLP(Enable)(GL_TEXTURE_GEN_T);
+        GLP(Enable)(GL_TEXTURE_GEN_R);
+        GLP(Enable)(GL_TEXTURE_GEN_Q);
+        break;
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::slot_new_clip_plane
-//       Access: Protected, Virtual
-//  Description: This will be called by the base class before a
-//               particular clip plane id will be used for the first
-//               time.  It is intended to allow the derived class to
-//               reserve any additional resources, if required, for
-//               the new clip plane; and also to indicate whether the
-//               hardware supports this many simultaneous clipping
-//               planes.
-//
-//               The return value should be true if the additional
-//               plane is supported, or false if it is not.
-////////////////////////////////////////////////////////////////////
-bool CLP(GraphicsStateGuardian)::
-slot_new_clip_plane(int plane_id) {
-  return (plane_id < _max_clip_planes);
-}
+      case TexGenAttrib::M_eye_position:
+        // To represent eye position correctly, we need to temporarily
+        // load the coordinate-system transform.
+        GLP(MatrixMode)(GL_MODELVIEW);
+        GLP(PushMatrix)();
+        GLP(LoadMatrixf)(_scene_setup->get_cs_transform()->get_mat().get_data());
+
+        GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+        GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+        GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+        GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+        
+        GLP(TexGenfv)(GL_S, GL_EYE_PLANE, s_data);
+        GLP(TexGenfv)(GL_T, GL_EYE_PLANE, t_data);
+        GLP(TexGenfv)(GL_R, GL_EYE_PLANE, r_data);
+        GLP(TexGenfv)(GL_Q, GL_EYE_PLANE, q_data);
+        
+        GLP(Enable)(GL_TEXTURE_GEN_S);
+        GLP(Enable)(GL_TEXTURE_GEN_T);
+        GLP(Enable)(GL_TEXTURE_GEN_R);
+        GLP(Enable)(GL_TEXTURE_GEN_Q);
+
+        GLP(MatrixMode)(GL_MODELVIEW);
+        GLP(PopMatrix)();
+        break;
+
+      case TexGenAttrib::M_world_position:
+        // We achieve world position coordinates by using the eye
+        // position mode, and loading the transform of the root
+        // node--thus putting the "eye" at the root.
+        {
+          GLP(MatrixMode)(GL_MODELVIEW);
+          GLP(PushMatrix)();
+          CPT(TransformState) root_transform = _scene_setup->get_render_transform();
+          GLP(LoadMatrixf)(root_transform->get_mat().get_data());
+          GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+          GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+          GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+          GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
+        
+          GLP(TexGenfv)(GL_S, GL_EYE_PLANE, s_data);
+          GLP(TexGenfv)(GL_T, GL_EYE_PLANE, t_data);
+          GLP(TexGenfv)(GL_R, GL_EYE_PLANE, r_data);
+          GLP(TexGenfv)(GL_Q, GL_EYE_PLANE, q_data);
+          
+          GLP(Enable)(GL_TEXTURE_GEN_S);
+          GLP(Enable)(GL_TEXTURE_GEN_T);
+          GLP(Enable)(GL_TEXTURE_GEN_R);
+          GLP(Enable)(GL_TEXTURE_GEN_Q);
+          
+          GLP(MatrixMode)(GL_MODELVIEW);
+          GLP(PopMatrix)();
+        }
+        break;
+
+      case TexGenAttrib::M_point_sprite:
+        nassertv(_supports_point_sprite);
+        GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
+        got_point_sprites = true;
+        break;
+      }
+    }
+
+    if (got_point_sprites != _tex_gen_point_sprite) {
+      _tex_gen_point_sprite = got_point_sprites;
+      if (_tex_gen_point_sprite) {
+        GLP(Enable)(GL_POINT_SPRITE_ARB);
+      } else {
+        GLP(Disable)(GL_POINT_SPRITE_ARB);
+      }
+    }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::enable_clip_plane
-//       Access: Protected, Virtual
-//  Description: Intended to be overridden by a derived class to
-//               enable the indicated clip_plane id.  A specific
-//               PlaneNode will already have been bound to this id via
-//               bind_clip_plane().
-////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-enable_clip_plane(int plane_id, bool enable) {
-  if (enable) {
-    GLP(Enable)(get_clip_plane_id(plane_id));
-  } else {
-    GLP(Disable)(get_clip_plane_id(plane_id));
+    // Certain texgen modes (sphere_map, cube_map) require forcing the
+    // normal to be sent to the GL while the texgen mode is in effect.
+    if (force_normal != _texgen_forced_normal) {
+      if (force_normal) {
+        force_normals();
+      } else  {
+        undo_force_normals();
+      }
+      _texgen_forced_normal = force_normal;
+    }
+
+    report_my_gl_errors();
   }
   }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::begin_bind_clip_planes
+//     Function: GLGraphicsStateGuardian::free_pointers
 //       Access: Protected, Virtual
 //       Access: Protected, Virtual
-//  Description: Called immediately before bind_clip_plane() is called,
-//               this is intended to provide the derived class a hook
-//               in which to set up some state (like transform) that
-//               might apply to several clip_planes.
-//
-//               The sequence is: begin_bind_clip_planes() will be called,
-//               then one or more bind_clip_plane() calls, then
-//               end_bind_clip_planes().
+//  Description: Frees some memory that was explicitly allocated
+//               within the glgsg.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
-begin_bind_clip_planes() {
-  // We need to temporarily load a new matrix so we can define the
-  // clip_plane in a known coordinate system.  We pick the transform of the
-  // root.  (Alternatively, we could leave the current transform where
-  // it is and compute the clip_plane position relative to that transform
-  // instead of relative to the root, by composing with the matrix
-  // computed by _transform->invert_compose(render_transform).  But I
-  // think loading a completely new matrix is simpler.)
-  GLP(MatrixMode)(GL_MODELVIEW);
-  GLP(PushMatrix)();
-  GLP(LoadMatrixf)(_scene_setup->get_render_transform()->get_mat().get_data());
+free_pointers() {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::bind_clip_plane
-//       Access: Protected, Virtual
-//  Description: Called the first time a particular clip_plane has been
-//               bound to a given id within a frame, this should set
-//               up the associated hardware clip_plane with the clip_plane's
-//               properties.
+//     Function: GLGraphicsStateGuardian::get_untextured_state
+//       Access: Protected, Static
+//  Description: Returns a RenderState object that represents
+//               texturing off.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-bind_clip_plane(const NodePath &plane, int plane_id) {
-  GLenum id = get_clip_plane_id(plane_id);
-
-  CPT(TransformState) transform = plane.get_transform(_scene_setup->get_scene_root());
-  const PlaneNode *plane_node;
-  DCAST_INTO_V(plane_node, plane.node());
-  Planef xformed_plane = plane_node->get_plane() * transform->get_mat();
-
-  Planed double_plane(LCAST(double, xformed_plane));
-  GLP(ClipPlane)(id, double_plane.get_data());
-
-  report_my_gl_errors();
+CPT(RenderState) CLP(GraphicsStateGuardian)::
+get_untextured_state() {
+  static CPT(RenderState) state;
+  if (state == (RenderState *)NULL) {
+    state = RenderState::make(TextureAttrib::make_off());
+  }
+  return state;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::end_bind_clip_planes
-//       Access: Protected, Virtual
-//  Description: Called after before bind_clip_plane() has been called one
-//               or more times (but before any geometry is issued or
-//               additional state is changed), this is intended to
-//               clean up any temporary changes to the state that may
-//               have been made by begin_bind_clip_planes().
+//     Function: GLGraphicsStateGuardian::get_smooth_state
+//       Access: Protected, Static
+//  Description: Returns a RenderState object that represents
+//               smooth, per-vertex shading.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-end_bind_clip_planes() {
-  GLP(MatrixMode)(GL_MODELVIEW);
-  GLP(PopMatrix)();
+CPT(RenderState) CLP(GraphicsStateGuardian)::
+get_smooth_state() {
+  static CPT(RenderState) state;
+  if (state == (RenderState *)NULL) {
+    state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_smooth));
+  }
+  return state;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::set_blend_mode
-//       Access: Protected, Virtual
-//  Description: Called after any of the things that might change
-//               blending state have changed, this function is
-//               responsible for setting the appropriate color
-//               blending mode based on the current properties.
+//     Function: GLGraphicsStateGuardian::get_flat_state
+//       Access: Protected, Static
+//  Description: Returns a RenderState object that represents
+//               flat, per-primitive shading.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-set_blend_mode() {
-  // If color_write_mode is off, we disable writing to the color using
-  // blending.  This case is only used if we can't use GLP(ColorMask) to
-  // disable the color writing for some reason (usually a driver
-  // problem).
-  if (_color_write_mode == ColorWriteAttrib::M_off) {
-    enable_multisample_alpha_one(false);
-    enable_multisample_alpha_mask(false);
-    enable_blend(true);
-    _glBlendEquation(GL_FUNC_ADD);
-    GLP(BlendFunc)(GL_ZERO, GL_ONE);
-   return;
-  }
-
-  // Is there a color blend set?
-  if (_color_blend_mode != ColorBlendAttrib::M_none) {
-    enable_multisample_alpha_one(false);
-    enable_multisample_alpha_mask(false);
-    enable_blend(true);
-    _glBlendEquation(get_blend_equation_type(_color_blend_mode));
-    GLP(BlendFunc)(get_blend_func(_color_blend->get_operand_a()),
-                   get_blend_func(_color_blend->get_operand_b()));
-
-    if (_color_blend_involves_color_scale) {
-      // Apply the current color scale to the blend mode.
-      _glBlendColor(_current_color_scale[0], _current_color_scale[1], 
-                    _current_color_scale[2], _current_color_scale[3]);
-      
-    } else {
-      Colorf c = _color_blend->get_color();
-      _glBlendColor(c[0], c[1], c[2], c[3]);
-    }
-    return;
-  }
-
-  // No color blend; is there a transparency set?
-  switch (_transparency_mode) {
-  case TransparencyAttrib::M_none:
-  case TransparencyAttrib::M_binary:
-    break;
-    
-  case TransparencyAttrib::M_alpha:
-  case TransparencyAttrib::M_dual:
-    enable_multisample_alpha_one(false);
-    enable_multisample_alpha_mask(false);
-    enable_blend(true);
-    _glBlendEquation(GL_FUNC_ADD);
-    GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    return;
-    
-  case TransparencyAttrib::M_multisample:
-    // We need to enable *both* of these in M_multisample case.
-    enable_multisample_alpha_one(true);
-    enable_multisample_alpha_mask(true);
-    enable_blend(false);
-    return;
-    
-  case TransparencyAttrib::M_multisample_mask:
-    enable_multisample_alpha_one(false);
-    enable_multisample_alpha_mask(true);
-    enable_blend(false);
-    return;
-    
-  default:
-    GLCAT.error()
-      << "invalid transparency mode " << (int)_transparency_mode << endl;
-    break;
-  }
-
-  if (_line_smooth_enabled || _point_smooth_enabled) {
-    // If we have either of these turned on, we also need to have
-    // blend mode enabled in order to see it.
-    enable_multisample_alpha_one(false);
-    enable_multisample_alpha_mask(false);
-    enable_blend(true);
-    _glBlendEquation(GL_FUNC_ADD);
-    GLP(BlendFunc)(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-    return;
+CPT(RenderState) CLP(GraphicsStateGuardian)::
+get_flat_state() {
+  static CPT(RenderState) state;
+  if (state == (RenderState *)NULL) {
+    state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_flat));
   }
   }
-
-  // For best polygon smoothing, we need:
-  // (1) a frame buffer that supports alpha
-  // (2) sort polygons front-to-back
-  // (3) glBlendFunc(GL_SRC_ALPHA_SATURATE, GL_ONE);
-  //
-  // Since these modes have other implications for the application, we
-  // don't attempt to do this by default.  If you really want good
-  // polygon smoothing (and you don't have multisample support), do
-  // all this yourself.
-
-  // Nothing's set, so disable blending.
-  enable_multisample_alpha_one(false);
-  enable_multisample_alpha_mask(false);
-  enable_blend(false);
+  return state;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::finish_modify_state
-//       Access: Protected, Virtual
-//  Description: Called after the GSG state has been modified via
-//               modify_state() or set_state(), this hook is provided
-//               for the derived class to do any further state setup
-//               work.
+//     Function: GLGraphicsStateGuardian::do_auto_rescale_normal
+//       Access: Protected
+//  Description: Issues the appropriate GL commands to either rescale
+//               or normalize the normals according to the current
+//               transform.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-finish_modify_state() {
-  GraphicsStateGuardian::finish_modify_state();
-
-  // Apply the texture, if it needs to be reapplied.
-  if (_texture_stale) {
-    _texture_stale = false;
-    do_issue_texture();
-  }
-
-  // If one of the previously-loaded TexGen modes modified the texture
-  // matrix, then if either state changed, we have to change both of
-  // them now.
-  if (_tex_gen_modifies_mat &&
-      (_needs_tex_mat || _needs_tex_gen)) {
-    _needs_tex_mat = true;
-    _needs_tex_gen = true;
-  }
-
-  // Apply the texture matrix, if needed.
-  if (_needs_tex_mat) {
-    _needs_tex_mat = false;
-
-    int num_stages = _current_texture->get_num_on_stages();
-    nassertv(num_stages <= _max_texture_stages);
-    
-    for (int i = 0; i < num_stages; i++) {
-      TextureStage *stage = _current_texture->get_on_stage(i);
-      _glActiveTexture(GL_TEXTURE0 + i);
+void CLP(GraphicsStateGuardian)::
+do_auto_rescale_normal() {
+  if (_transform->has_uniform_scale()) {
+    if (IS_NEARLY_EQUAL(_transform->get_uniform_scale(), 1.0f)) {
+      // If there's no scale at all, don't do anything.
+      GLP(Disable)(GL_NORMALIZE);
+      if (_supports_rescale_normal) {
+        GLP(Disable)(GL_RESCALE_NORMAL);
+      }
       
       
-      GLP(MatrixMode)(GL_TEXTURE);
-      if (_current_tex_mat->has_stage(stage)) {
-        GLP(LoadMatrixf)(_current_tex_mat->get_mat(stage).get_data());
+    } else {
+      // There's a uniform scale; use the rescale feature if available.
+      if (_supports_rescale_normal) {
+        GLP(Enable)(GL_RESCALE_NORMAL);
+        GLP(Disable)(GL_NORMALIZE);
       } else {
       } else {
-        GLP(LoadIdentity)();
-
-        // For some reason, the glLoadIdentity() call doesn't work on
-        // my Dell laptop's IBM OpenGL driver, when used in
-        // conjunction with glTexGen(), below.  But explicitly loading
-        // an identity matrix does work.  But this buggy-driver
-        // workaround might have other performance implications, so I
-        // leave it out.
-        //GLP(LoadMatrixf)(LMatrix4f::ident_mat().get_data());
+        GLP(Enable)(GL_NORMALIZE);
       }
       }
     }
     }
-    report_my_gl_errors();
+
+  } else {
+    // If there's a non-uniform scale, normalize everything.
+    GLP(Enable)(GL_NORMALIZE);
+    if (_supports_rescale_normal) {
+      GLP(Disable)(GL_RESCALE_NORMAL);
+    }
   }
   }
+}
 
 
-  if (_needs_tex_gen) {
-    _needs_tex_gen = false;
-    bool force_normal = false;
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::do_issue_texture
+//       Access: Protected
+//  Description: This is called by finish_modify_state() when the
+//               texture state has changed.
+////////////////////////////////////////////////////////////////////
+void CLP(GraphicsStateGuardian)::
+do_issue_texture() {
+  DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
 
 
-    int num_stages = _current_texture->get_num_on_stages();
-    nassertv(num_stages <= _max_texture_stages);
-    
-    // These are passed in for the four OBJECT_PLANE or EYE_PLANE
-    // values; they effectively define an identity matrix that maps
-    // the spatial coordinates one-for-one to UV's.  If you want a
-    // mapping other than identity, use a TexMatrixAttrib (or a
-    // TexProjectorEffect).
-    static const float s_data[4] = { 1, 0, 0, 0 };
-    static const float t_data[4] = { 0, 1, 0, 0 };
-    static const float r_data[4] = { 0, 0, 1, 0 };
-    static const float q_data[4] = { 0, 0, 0, 1 };
+  CPT(TextureAttrib) new_texture = _pending_texture->filter_to_max(_max_texture_stages);
+  
+  int num_stages = new_texture->get_num_on_stages();
+  int num_old_stages = _current_texture->get_num_on_stages();
 
 
-    _tex_gen_modifies_mat = false;
+  nassertv(num_stages <= _max_texture_stages && 
+           num_old_stages <= _max_texture_stages);
 
 
-    bool got_point_sprites = false;
+  _texture_involves_color_scale = false;
+
+  int i;
+  for (i = 0; i < num_stages; i++) {
+    TextureStage *stage = new_texture->get_on_stage(i);
+    Texture *texture = new_texture->get_on_texture(stage);
+    nassertv(texture != (Texture *)NULL);
     
     
-    for (int i = 0; i < num_stages; i++) {
-      TextureStage *stage = _current_texture->get_on_stage(i);
+    if (i >= num_old_stages ||
+        stage != _current_texture->get_on_stage(i) ||
+        texture != _current_texture->get_on_texture(stage) ||
+        stage->involves_color_scale()) {
+      // Stage i has changed.  Issue the texture on this stage.
       _glActiveTexture(GL_TEXTURE0 + i);
       _glActiveTexture(GL_TEXTURE0 + i);
-      GLP(Disable)(GL_TEXTURE_GEN_S);
-      GLP(Disable)(GL_TEXTURE_GEN_T);
-      GLP(Disable)(GL_TEXTURE_GEN_R);
-      GLP(Disable)(GL_TEXTURE_GEN_Q);
-      if (_supports_point_sprite) {
-        GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_FALSE);
+
+      GLenum target = get_texture_target(texture->get_texture_type());
+
+      // First, turn off the previous texture mode.
+      GLP(Disable)(GL_TEXTURE_1D);
+      GLP(Disable)(GL_TEXTURE_2D);
+      if (_supports_3d_texture) {
+        GLP(Disable)(GL_TEXTURE_3D);
+      }
+      if (_supports_cube_map) {
+        GLP(Disable)(GL_TEXTURE_CUBE_MAP);
       }
       }
 
 
-      TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage);
-      switch (mode) {
-      case TexGenAttrib::M_off:
-        break;
-        
-      case TexGenAttrib::M_eye_sphere_map:
-        GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
-        GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
-        GLP(Enable)(GL_TEXTURE_GEN_S);
-        GLP(Enable)(GL_TEXTURE_GEN_T);
-        force_normal = true;
+      // Then, turn on the current texture mode.
+      if (target == GL_NONE) {
+        // Unsupported texture mode.
         break;
         break;
-        
-      case TexGenAttrib::M_eye_cube_map:
-      case TexGenAttrib::M_world_cube_map:
-        if (_supports_cube_map) {
-          if (mode != TexGenAttrib::M_eye_cube_map) {
-            // We dynamically transform normals from eye space to
-            // world space by applying the appropriate rotation
-            // transform to the current texture matrix.  Although it's
-            // tempting to try, we can't safely convert to object
-            // space, since this method doesn't get called with each
-            // different object.
-            CPT(TransformState) transform = _scene_setup->get_render_transform();
-            transform = transform->invert_compose(TransformState::make_identity());
-            LMatrix4f mat = transform->get_mat();
-            mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
-            GLP(MatrixMode)(GL_TEXTURE);
-            GLP(MultMatrixf)(mat.get_data());
+      }
+      GLP(Enable)(target);
+      
+      TextureContext *tc = texture->prepare_now(_prepared_objects, this);
+      apply_texture(tc);
 
 
-            // Now we need to reset the texture matrix next time
-            // around to undo this.
-            _tex_gen_modifies_mat = true;
-          }
+      if (stage->involves_color_scale() && _color_scale_enabled) {
+        Colorf color = stage->get_color();
+        color.set(color[0] * _current_color_scale[0],
+                  color[1] * _current_color_scale[1],
+                  color[2] * _current_color_scale[2],
+                  color[3] * _current_color_scale[3]);
+        _texture_involves_color_scale = true;
+        GLP(TexEnvfv)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color.get_data());
+      } else {
+        GLP(TexEnvfv)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, stage->get_color().get_data());
+      }
 
 
-          GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
-          GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
-          GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_REFLECTION_MAP);
-          GLP(Enable)(GL_TEXTURE_GEN_S);
-          GLP(Enable)(GL_TEXTURE_GEN_T);
-          GLP(Enable)(GL_TEXTURE_GEN_R);
-          force_normal = true;
+      if (stage->get_mode() == TextureStage::M_decal) {
+        if (texture->get_num_components() < 3) {
+          // Make a special case for 1- and 2-channel decal textures.
+          // OpenGL does not define their use with GL_DECAL for some
+          // reason, so implement them using the combiner instead.
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE);
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
+          
+        } else {
+          // Normal 3- and 4-channel decal textures.
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
         }
         }
-        break;
-        
-      case TexGenAttrib::M_eye_normal:
-      case TexGenAttrib::M_world_normal:
-        if (_supports_cube_map) {
-          if (mode != TexGenAttrib::M_eye_normal) {
-            // We dynamically transform normals from eye space to
-            // world space by applying the appropriate rotation
-            // transform to the current texture matrix.  Although it's
-            // tempting to try, we can't safely convert to object
-            // space, since this method doesn't get called with each
-            // different object.
-            CPT(TransformState) transform = _scene_setup->get_render_transform();
-            transform = transform->invert_compose(TransformState::make_identity());
-            LMatrix4f mat = transform->get_mat();
-            mat.set_row(3, LVecBase3f(0.0f, 0.0f, 0.0f));
-            GLP(MatrixMode)(GL_TEXTURE);
-            GLP(MultMatrixf)(mat.get_data());
 
 
-            // Now we need to reset the texture matrix next time
-            // around to undo this.
-            _tex_gen_modifies_mat = true;
-          }
+      } else if (stage->get_mode() == TextureStage::M_combine) {
+        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
+        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
+        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_RGB_SCALE, stage->get_rgb_scale());
+        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_ALPHA_SCALE, stage->get_alpha_scale());
+        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, 
+                     get_texture_combine_type(stage->get_combine_rgb_mode()));
 
 
-          GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
-          GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
-          GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_NORMAL_MAP);
-          GLP(Enable)(GL_TEXTURE_GEN_S);
-          GLP(Enable)(GL_TEXTURE_GEN_T);
-          GLP(Enable)(GL_TEXTURE_GEN_R);
-          force_normal = true;
-        }
-        break;
+        switch (stage->get_num_combine_rgb_operands()) {
+        case 3:
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_RGB, 
+                       get_texture_src_type(stage->get_combine_rgb_source2()));
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_RGB, 
+                       get_texture_operand_type(stage->get_combine_rgb_operand2()));
+          // fall through
 
 
-      case TexGenAttrib::M_object_position:
-        GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-        GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-        GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-        GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
-        
-        GLP(TexGenfv)(GL_S, GL_OBJECT_PLANE, s_data);
-        GLP(TexGenfv)(GL_T, GL_OBJECT_PLANE, t_data);
-        GLP(TexGenfv)(GL_R, GL_OBJECT_PLANE, r_data);
-        GLP(TexGenfv)(GL_Q, GL_OBJECT_PLANE, q_data);
-        
-        GLP(Enable)(GL_TEXTURE_GEN_S);
-        GLP(Enable)(GL_TEXTURE_GEN_T);
-        GLP(Enable)(GL_TEXTURE_GEN_R);
-        GLP(Enable)(GL_TEXTURE_GEN_Q);
-        break;
+        case 2:
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_RGB, 
+                       get_texture_src_type(stage->get_combine_rgb_source1()));
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, 
+                       get_texture_operand_type(stage->get_combine_rgb_operand1()));
+          // fall through
+
+        case 1:
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_RGB, 
+                       get_texture_src_type(stage->get_combine_rgb_source0()));
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND0_RGB, 
+                       get_texture_operand_type(stage->get_combine_rgb_operand0()));
+          // fall through
+
+        default:
+          break;
+        }
+        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, 
+                     get_texture_combine_type(stage->get_combine_alpha_mode()));
 
 
-      case TexGenAttrib::M_eye_position:
-        // To represent eye position correctly, we need to temporarily
-        // load the coordinate-system transform.
-        GLP(MatrixMode)(GL_MODELVIEW);
-        GLP(PushMatrix)();
-        GLP(LoadMatrixf)(_scene_setup->get_cs_transform()->get_mat().get_data());
+        switch (stage->get_num_combine_alpha_operands()) {
+        case 3:
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_ALPHA, 
+                       get_texture_src_type(stage->get_combine_alpha_source2()));
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, 
+                       get_texture_operand_type(stage->get_combine_alpha_operand2()));
+          // fall through
 
 
-        GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
-        GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
-        GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
-        GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
-        
-        GLP(TexGenfv)(GL_S, GL_EYE_PLANE, s_data);
-        GLP(TexGenfv)(GL_T, GL_EYE_PLANE, t_data);
-        GLP(TexGenfv)(GL_R, GL_EYE_PLANE, r_data);
-        GLP(TexGenfv)(GL_Q, GL_EYE_PLANE, q_data);
-        
-        GLP(Enable)(GL_TEXTURE_GEN_S);
-        GLP(Enable)(GL_TEXTURE_GEN_T);
-        GLP(Enable)(GL_TEXTURE_GEN_R);
-        GLP(Enable)(GL_TEXTURE_GEN_Q);
+        case 2:
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_ALPHA, 
+                       get_texture_src_type(stage->get_combine_alpha_source1()));
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, 
+                       get_texture_operand_type(stage->get_combine_alpha_operand1()));
+          // fall through
 
 
-        GLP(MatrixMode)(GL_MODELVIEW);
-        GLP(PopMatrix)();
-        break;
+        case 1:
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_ALPHA, 
+                       get_texture_src_type(stage->get_combine_alpha_source0()));
+          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, 
+                       get_texture_operand_type(stage->get_combine_alpha_operand0()));
+          // fall through
 
 
-      case TexGenAttrib::M_world_position:
-        // We achieve world position coordinates by using the eye
-        // position mode, and loading the transform of the root
-        // node--thus putting the "eye" at the root.
-        {
-          GLP(MatrixMode)(GL_MODELVIEW);
-          GLP(PushMatrix)();
-          CPT(TransformState) root_transform = _scene_setup->get_render_transform();
-          GLP(LoadMatrixf)(root_transform->get_mat().get_data());
-          GLP(TexGeni)(GL_S, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
-          GLP(TexGeni)(GL_T, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
-          GLP(TexGeni)(GL_R, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
-          GLP(TexGeni)(GL_Q, GL_TEXTURE_GEN_MODE, GL_EYE_LINEAR);
-        
-          GLP(TexGenfv)(GL_S, GL_EYE_PLANE, s_data);
-          GLP(TexGenfv)(GL_T, GL_EYE_PLANE, t_data);
-          GLP(TexGenfv)(GL_R, GL_EYE_PLANE, r_data);
-          GLP(TexGenfv)(GL_Q, GL_EYE_PLANE, q_data);
-          
-          GLP(Enable)(GL_TEXTURE_GEN_S);
-          GLP(Enable)(GL_TEXTURE_GEN_T);
-          GLP(Enable)(GL_TEXTURE_GEN_R);
-          GLP(Enable)(GL_TEXTURE_GEN_Q);
-          
-          GLP(MatrixMode)(GL_MODELVIEW);
-          GLP(PopMatrix)();
+        default:
+          break;
         }
         }
-        break;
 
 
-      case TexGenAttrib::M_point_sprite:
-        nassertv(_supports_point_sprite);
-        GLP(TexEnvi)(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE_ARB, GL_TRUE);
-        got_point_sprites = true;
-        break;
+      } else {
+        GLint glmode = get_texture_apply_mode_type(stage->get_mode());
+        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, glmode);
       }
       }
-    }
 
 
-    if (got_point_sprites != _tex_gen_point_sprite) {
-      _tex_gen_point_sprite = got_point_sprites;
-      if (_tex_gen_point_sprite) {
-        GLP(Enable)(GL_POINT_SPRITE_ARB);
+      GLP(MatrixMode)(GL_TEXTURE);
+      if (_current_tex_mat->has_stage(stage)) {
+        GLP(LoadMatrixf)(_current_tex_mat->get_mat(stage).get_data());
       } else {
       } else {
-        GLP(Disable)(GL_POINT_SPRITE_ARB);
+        GLP(LoadIdentity)();
       }
       }
     }
     }
-
-    // Certain texgen modes (sphere_map, cube_map) require forcing the
-    // normal to be sent to the GL while the texgen mode is in effect.
-    if (force_normal != _texgen_forced_normal) {
-      if (force_normal) {
-        force_normals();
-      } else  {
-        undo_force_normals();
-      }
-      _texgen_forced_normal = force_normal;
+  }
+    
+  // Disable the texture stages that are no longer used.
+  for (i = num_stages; i < num_old_stages; i++) {
+    _glActiveTexture(GL_TEXTURE0 + i);
+    GLP(Disable)(GL_TEXTURE_1D);
+    GLP(Disable)(GL_TEXTURE_2D);
+    if (_supports_3d_texture) {
+      GLP(Disable)(GL_TEXTURE_3D);
+    }
+    if (_supports_cube_map) {
+      GLP(Disable)(GL_TEXTURE_CUBE_MAP);
     }
     }
-
-    report_my_gl_errors();
   }
   }
+
+  _current_texture = new_texture;
+
+  // Changing the set of texture stages will require us to reissue the
+  // texgen and texmat attribs.
+  _needs_tex_gen = true;
+  _needs_tex_mat = true;
+
+  report_my_gl_errors();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::free_pointers
-//       Access: Protected, Virtual
-//  Description: Frees some memory that was explicitly allocated
-//               within the glgsg.
+//     Function: GLGraphicsStateGuardian::specify_texture
+//       Access: Protected
+//  Description: Specifies the texture parameters.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
-free_pointers() {
-}
+specify_texture(Texture *tex) {
+  GLenum target = get_texture_target(tex->get_texture_type());
+  if (target == GL_NONE) {
+    // Unsupported target (e.g. 3-d texturing on GL 1.1).
+    return;
+  }
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_untextured_state
-//       Access: Protected, Static
-//  Description: Returns a RenderState object that represents
-//               texturing off.
-////////////////////////////////////////////////////////////////////
-CPT(RenderState) CLP(GraphicsStateGuardian)::
-get_untextured_state() {
-  static CPT(RenderState) state;
-  if (state == (RenderState *)NULL) {
-    state = RenderState::make(TextureAttrib::make_off());
+  GLP(TexParameteri)(target, GL_TEXTURE_WRAP_S,
+                     get_texture_wrap_mode(tex->get_wrap_u()));
+  if (target != GL_TEXTURE_1D) {
+    GLP(TexParameteri)(target, GL_TEXTURE_WRAP_T,
+                       get_texture_wrap_mode(tex->get_wrap_v()));
   }
   }
-  return state;
+  if (target == GL_TEXTURE_3D) {
+    GLP(TexParameteri)(target, GL_TEXTURE_WRAP_R,
+                       get_texture_wrap_mode(tex->get_wrap_w()));
+  }
+
+  Colorf border_color = tex->get_border_color();
+  GLP(TexParameterfv)(target, GL_TEXTURE_BORDER_COLOR,
+                      border_color.get_data());
+
+  Texture::FilterType minfilter = tex->get_minfilter();
+  Texture::FilterType magfilter = tex->get_magfilter();
+  bool uses_mipmaps = tex->uses_mipmaps() && !CLP(ignore_mipmaps);
+
+#ifndef NDEBUG
+  if (CLP(force_mipmaps)) {
+    minfilter = Texture::FT_linear_mipmap_linear;
+    magfilter = Texture::FT_linear;
+    uses_mipmaps = true;
+  }
+#endif
+
+  if (_supports_generate_mipmap && 
+      (auto_generate_mipmaps || !tex->might_have_ram_image())) {
+    // If the hardware can automatically generate mipmaps, ask it to
+    // do so now, but only if the texture requires them.
+    GLP(TexParameteri)(target, GL_GENERATE_MIPMAP, uses_mipmaps);
+
+  } else if (!tex->might_have_ram_image()) {
+    // If the hardware can't automatically generate mipmaps, but it's
+    // a dynamically generated texture (that is, the RAM image isn't
+    // available so it didn't pass through the CPU), then we'd better
+    // not try to enable mipmap filtering, since we can't generate
+    // mipmaps.
+    uses_mipmaps = false;
+  }
+ 
+  GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER,
+                     get_texture_filter_type(minfilter, !uses_mipmaps));
+  GLP(TexParameteri)(target, GL_TEXTURE_MAG_FILTER,
+                     get_texture_filter_type(magfilter, true));
+
+  report_my_gl_errors();
 }
 }
 
 
+#ifndef NDEBUG
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_smooth_state
-//       Access: Protected, Static
-//  Description: Returns a RenderState object that represents
-//               smooth, per-vertex shading.
+//     Function: compute_gl_image_size
+//  Description: Calculates how many bytes GL will expect to read for
+//               a texture image, based on the number of pixels and
+//               the GL format and type.  This is only used for
+//               debugging.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-CPT(RenderState) CLP(GraphicsStateGuardian)::
-get_smooth_state() {
-  static CPT(RenderState) state;
-  if (state == (RenderState *)NULL) {
-    state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_smooth));
+static int
+compute_gl_image_size(int x_size, int y_size, int z_size, 
+                      int external_format, int type) {
+  int num_components = 0;
+  switch (external_format) {
+  case GL_COLOR_INDEX:
+  case GL_STENCIL_INDEX:
+  case GL_DEPTH_COMPONENT:
+  case GL_RED:
+  case GL_GREEN:
+  case GL_BLUE:
+  case GL_ALPHA:
+  case GL_LUMINANCE:
+    num_components = 1;
+    break;
+
+  case GL_LUMINANCE_ALPHA:
+    num_components = 2;
+    break;
+
+  case GL_BGR:
+  case GL_RGB:
+    num_components = 3;
+    break;
+
+  case GL_BGRA:
+  case GL_RGBA:
+    num_components = 4;
+    break;
   }
   }
-  return state;
-}
 
 
-////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::get_flat_state
-//       Access: Protected, Static
-//  Description: Returns a RenderState object that represents
-//               flat, per-primitive shading.
-////////////////////////////////////////////////////////////////////
-CPT(RenderState) CLP(GraphicsStateGuardian)::
-get_flat_state() {
-  static CPT(RenderState) state;
-  if (state == (RenderState *)NULL) {
-    state = RenderState::make(ShadeModelAttrib::make(ShadeModelAttrib::M_flat));
+  int pixel_width = 0;
+  switch (type) {
+  case GL_UNSIGNED_BYTE:
+    pixel_width = 1 * num_components;
+    break;
+
+  case GL_UNSIGNED_SHORT:
+    pixel_width = 2 * num_components;
+    break;
+
+  case GL_UNSIGNED_BYTE_3_3_2:
+    nassertr(num_components == 3, 0);
+    pixel_width = 1;
+    break;
+
+  case GL_FLOAT:
+    pixel_width = 4 * num_components;
+    break;
   }
   }
-  return state;
+
+  return x_size * y_size * z_size * pixel_width;
 }
 }
+#endif  // NDEBUG
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::do_auto_rescale_normal
+//     Function: GLGraphicsStateGuardian::apply_texture
 //       Access: Protected
 //       Access: Protected
-//  Description: Issues the appropriate GL commands to either rescale
-//               or normalize the normals according to the current
-//               transform.
+//  Description: Updates OpenGL with the current information for this
+//               texture, and makes it the current texture available
+//               for rendering.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void CLP(GraphicsStateGuardian)::
 void CLP(GraphicsStateGuardian)::
-do_auto_rescale_normal() {
-  if (_transform->has_uniform_scale()) {
-    if (IS_NEARLY_EQUAL(_transform->get_uniform_scale(), 1.0f)) {
-      // If there's no scale at all, don't do anything.
-      GLP(Disable)(GL_NORMALIZE);
-      if (_supports_rescale_normal) {
-        GLP(Disable)(GL_RESCALE_NORMAL);
-      }
-      
-    } else {
-      // There's a uniform scale; use the rescale feature if available.
-      if (_supports_rescale_normal) {
-        GLP(Enable)(GL_RESCALE_NORMAL);
-        GLP(Disable)(GL_NORMALIZE);
-      } else {
-        GLP(Enable)(GL_NORMALIZE);
-      }
-    }
+apply_texture(TextureContext *tc) {
+  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
 
 
-  } else {
-    // If there's a non-uniform scale, normalize everything.
-    GLP(Enable)(GL_NORMALIZE);
-    if (_supports_rescale_normal) {
-      GLP(Disable)(GL_RESCALE_NORMAL);
-    }
+  add_to_texture_record(gtc);
+  GLenum target = get_texture_target(gtc->_texture->get_texture_type());
+  if (target == GL_NONE) {
+    return;
+  }
+  GLP(BindTexture)(target, gtc->_index);
+
+  int dirty = gtc->get_dirty_flags();
+  if ((dirty & (Texture::DF_wrap | Texture::DF_filter | Texture::DF_border)) != 0) {
+    // We need to re-specify the texture properties.
+    specify_texture(gtc->_texture);
+  }
+  if ((dirty & (Texture::DF_image | Texture::DF_mipmap)) != 0) {
+    // We need to re-upload the image.
+    upload_texture(gtc);
   }
   }
+
+  gtc->clear_dirty_flags();
+
+  report_my_gl_errors();
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: GLGraphicsStateGuardian::do_issue_texture
+//     Function: GLGraphicsStateGuardian::upload_texture
 //       Access: Protected
 //       Access: Protected
-//  Description: This is called by finish_modify_state() when the
-//               texture state has changed.
+//  Description: Uploads the entire texture image to OpenGL, including
+//               all pages.
+//
+//               The return value is true if successful, or false if
+//               the texture has no image.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-void CLP(GraphicsStateGuardian)::
-do_issue_texture() {
-  DO_PSTATS_STUFF(_texture_state_pcollector.add_level(1));
+bool CLP(GraphicsStateGuardian)::
+upload_texture(CLP(TextureContext) *gtc) {
+  Texture *tex = gtc->_texture;
+  CPTA_uchar image = tex->get_ram_image();
+  if (image.is_null()) {
+    return false;
+  }
 
 
-  CPT(TextureAttrib) new_texture = _pending_texture->filter_to_max(_max_texture_stages);
-  
-  int num_stages = new_texture->get_num_on_stages();
-  int num_old_stages = _current_texture->get_num_on_stages();
+  int width = tex->get_x_size();
+  int height = tex->get_y_size();
+  int depth = tex->get_z_size();
 
 
-  nassertv(num_stages <= _max_texture_stages && 
-           num_old_stages <= _max_texture_stages);
+  GLint internal_format = get_internal_image_format(tex->get_format());
+  GLint external_format = get_external_image_format(tex->get_format());
+  GLenum component_type = get_component_type(tex->get_component_type());
 
 
-  _texture_involves_color_scale = false;
+  // Ensure that the texture fits within the GL's specified limits.
+  int max_dimension;
+  switch (tex->get_texture_type()) {
+  case Texture::TT_3d_texture:
+    max_dimension = _max_3d_texture_dimension;
+    break;
 
 
-  int i;
-  for (i = 0; i < num_stages; i++) {
-    TextureStage *stage = new_texture->get_on_stage(i);
-    Texture *texture = new_texture->get_on_texture(stage);
-    nassertv(texture != (Texture *)NULL);
-    
-    if (i >= num_old_stages ||
-        stage != _current_texture->get_on_stage(i) ||
-        texture != _current_texture->get_on_texture(stage) ||
-        stage->involves_color_scale()) {
-      // Stage i has changed.  Issue the texture on this stage.
-      _glActiveTexture(GL_TEXTURE0 + i);
+  case Texture::TT_cube_map:
+    max_dimension = _max_cube_map_dimension;
+    break;
 
 
-      GLenum target = get_texture_target(texture->get_texture_type());
+  default:
+    max_dimension = _max_texture_dimension;
+  }
 
 
-      // First, turn off the previous texture mode.
-      GLP(Disable)(GL_TEXTURE_1D);
-      GLP(Disable)(GL_TEXTURE_2D);
-      if (_supports_3d_texture) {
-        GLP(Disable)(GL_TEXTURE_3D);
+  if (max_dimension == 0) {
+    // Guess this GL doesn't support cube mapping/3d textures.
+    report_my_gl_errors();
+    return false;
+  }
+
+  int texel_size = tex->get_num_components() * tex->get_component_width();
+
+  // If it doesn't fit, we have to reduce it on-the-fly.  This is kind
+  // of expensive and it doesn't look great; it would have been better
+  // if the user had specified max-texture-dimension to reduce the
+  // texture at load time instead.  Of course, the user doesn't always
+  // know ahead of time what the hardware limits are.
+  if (max_dimension > 0) {
+    if (width > max_dimension) {
+      int byte_chunk = texel_size;
+      int stride = 1;
+      int new_width = width;
+      while (new_width > max_dimension) {
+        stride <<= 1;
+        new_width >>= 1;
       }
       }
-      if (_supports_cube_map) {
-        GLP(Disable)(GL_TEXTURE_CUBE_MAP);
+      GLCAT.info()
+        << "Reducing width of " << tex->get_name()
+        << " from " << width << " to " << new_width << "\n";
+      image = reduce_image(image, byte_chunk, stride);
+      width = new_width;
+    }
+    if (height > max_dimension) {
+      int byte_chunk = width * texel_size;
+      int stride = 1;
+      int new_height = height;
+      while (new_height > max_dimension) {
+        stride <<= 1;
+        new_height >>= 1;
       }
       }
-
-      // Then, turn on the current texture mode.
-      if (target == GL_NONE) {
-        // Unsupported texture mode.
-        break;
+      GLCAT.info()
+        << "Reducing height of " << tex->get_name()
+        << " from " << height << " to " << new_height << "\n";
+      image = reduce_image(image, byte_chunk, stride);
+      height = new_height;
+    }
+    if (depth > max_dimension) {
+      int byte_chunk = height * width * texel_size;
+      int stride = 1;
+      int new_depth = depth;
+      while (new_depth > max_dimension) {
+        stride <<= 1;
+        new_depth >>= 1;
       }
       }
-      GLP(Enable)(target);
-      
-      TextureContext *tc = texture->prepare_now(_prepared_objects, this);
-      apply_texture(tc);
+      GLCAT.info()
+        << "Reducing depth of " << tex->get_name()
+        << " from " << depth << " to " << new_depth << "\n";
+      image = reduce_image(image, byte_chunk, stride);
+      depth = new_depth;
+    }
+  }
 
 
-      if (stage->involves_color_scale() && _color_scale_enabled) {
-        Colorf color = stage->get_color();
-        color.set(color[0] * _current_color_scale[0],
-                  color[1] * _current_color_scale[1],
-                  color[2] * _current_color_scale[2],
-                  color[3] * _current_color_scale[3]);
-        _texture_involves_color_scale = true;
-        GLP(TexEnvfv)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, color.get_data());
-      } else {
-        GLP(TexEnvfv)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, stage->get_color().get_data());
-      }
+  if (!_supports_bgr) {
+    // If the GL doesn't claim to support BGR, we may have to reverse
+    // the component ordering of the image.
+    image = fix_component_ordering(image, external_format, tex);
+  }
 
 
-      if (stage->get_mode() == TextureStage::M_decal) {
-        if (texture->get_num_components() < 3) {
-          // Make a special case for 1- and 2-channel decal textures.
-          // OpenGL does not define their use with GL_DECAL for some
-          // reason, so implement them using the combiner instead.
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_RGB_SCALE, 1);
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_ALPHA_SCALE, 1);
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_RGB, GL_TEXTURE);
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_RGB, GL_PREVIOUS);
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_COLOR);
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_RGB, GL_TEXTURE);
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_RGB, GL_SRC_ALPHA);
-          
-        } else {
-          // Normal 3- and 4-channel decal textures.
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
-        }
+#ifndef NDEBUG
+  int wanted_size = 
+    compute_gl_image_size(width, height, depth, external_format, component_type);
+  nassertr(wanted_size == (int)image.size(), false);
+#endif  // NDEBUG
+
+  GLP(PixelStorei)(GL_UNPACK_ALIGNMENT, 1);
+
+  bool uses_mipmaps = (tex->uses_mipmaps() && !CLP(ignore_mipmaps)) || CLP(force_mipmaps);
+
+#ifndef NDEBUG
+  if (CLP(force_mipmaps)) {
+    uses_mipmaps = true;
+  }
+#endif
+
+  bool success = true;
+
+  if (tex->get_texture_type() == Texture::TT_cube_map) {
+    // A cube map must load six different 2-d images (which are stored
+    // as the six pages of the system ram image).
+    if (!_supports_cube_map) {
+      report_my_gl_errors();
+      return false;
+    }
+
+    size_t page_size = height * width * texel_size;
+    const unsigned char *image_base = image;
+    
+    success = success && upload_texture_image
+      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+       internal_format, width, height, depth, external_format, component_type,
+       image_base);
+    image_base += page_size;
+    
+    success = success && upload_texture_image
+      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+       internal_format, width, height, depth, external_format, component_type,
+       image_base);
+    image_base += page_size;
+    
+    success = success && upload_texture_image
+      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+       internal_format, width, height, depth, external_format, component_type,
+       image_base);
+    image_base += page_size;
+    
+    success = success && upload_texture_image
+      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+       internal_format, width, height, depth, external_format, component_type,
+       image_base);
+    image_base += page_size;
+    
+    success = success && upload_texture_image
+      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+       internal_format, width, height, depth, external_format, component_type,
+       image_base);
+    image_base += page_size;
+    
+    success = success && upload_texture_image
+      (gtc, uses_mipmaps, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+       internal_format, width, height, depth, external_format, component_type,
+       image_base);
+    image_base += page_size;
+    
+    nassertr((size_t)(image_base - image) == image.size(), false);
 
 
-      } else if (stage->get_mode() == TextureStage::M_combine) {
-        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
-        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_INTERPOLATE);
-        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_RGB_SCALE, stage->get_rgb_scale());
-        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_ALPHA_SCALE, stage->get_alpha_scale());
-        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_RGB, 
-                     get_texture_combine_type(stage->get_combine_rgb_mode()));
+  } else {
+    // Any other kind of texture can be loaded all at once.
+    success = upload_texture_image
+      (gtc, uses_mipmaps, get_texture_target(tex->get_texture_type()),
+       internal_format, width, height, depth, external_format, component_type,
+       image);
+  }
 
 
-        switch (stage->get_num_combine_rgb_operands()) {
-        case 3:
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_RGB, 
-                       get_texture_src_type(stage->get_combine_rgb_source2()));
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_RGB, 
-                       get_texture_operand_type(stage->get_combine_rgb_operand2()));
-          // fall through
+  if (success) {
+    gtc->_already_applied = true;
+    gtc->_internal_format = internal_format;
+    gtc->_width = width;
+    gtc->_height = height;
+    gtc->_depth = depth;
 
 
-        case 2:
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_RGB, 
-                       get_texture_src_type(stage->get_combine_rgb_source1()));
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_RGB, 
-                       get_texture_operand_type(stage->get_combine_rgb_operand1()));
-          // fall through
+#ifndef NDEBUG
+    if (uses_mipmaps && CLP(save_mipmaps)) {
+      save_mipmap_images(tex);
+    }
+#endif
 
 
-        case 1:
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_RGB, 
-                       get_texture_src_type(stage->get_combine_rgb_source0()));
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND0_RGB, 
-                       get_texture_operand_type(stage->get_combine_rgb_operand0()));
-          // fall through
+    report_my_gl_errors();
+    return true;
+  }
 
 
-        default:
-          break;
-        }
-        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_COMBINE_ALPHA, 
-                     get_texture_combine_type(stage->get_combine_alpha_mode()));
+  report_my_gl_errors();
+  return false;
+}
 
 
-        switch (stage->get_num_combine_alpha_operands()) {
-        case 3:
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC2_ALPHA, 
-                       get_texture_src_type(stage->get_combine_alpha_source2()));
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND2_ALPHA, 
-                       get_texture_operand_type(stage->get_combine_alpha_operand2()));
-          // fall through
+////////////////////////////////////////////////////////////////////
+//     Function: GLGraphicsStateGuardian::upload_texture_image
+//       Access: Protected
+//  Description: Loads a texture image, or one page of a cube map
+//               image, from system RAM to texture memory.
+////////////////////////////////////////////////////////////////////
+bool CLP(GraphicsStateGuardian)::
+upload_texture_image(CLP(TextureContext) *gtc, 
+                     bool uses_mipmaps, 
+                     GLenum target, GLint internal_format, 
+                     int width, int height, int depth,
+                     GLint external_format, GLenum component_type, 
+                     const unsigned char *image) {
+  if (target == GL_NONE) {
+    // Unsupported target (e.g. 3-d texturing on GL 1.1).
+    return false;
+  }
+  PStatTimer timer(_load_texture_pcollector);
 
 
-        case 2:
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC1_ALPHA, 
-                       get_texture_src_type(stage->get_combine_alpha_source1()));
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, 
-                       get_texture_operand_type(stage->get_combine_alpha_operand1()));
-          // fall through
+  if (uses_mipmaps) {
+#ifndef NDEBUG
+    if (CLP(show_mipmaps) && target == GL_TEXTURE_2D) {
+      build_phony_mipmaps(gtc->_texture);
+      report_my_gl_errors();
+      return true;
+      
+    } else 
+#endif 
+      if (!_supports_generate_mipmap || !auto_generate_mipmaps) {
+        // We only need to build the mipmaps by hand if the GL
+        // doesn't support generating them automatically.
+        bool success = true;
+#ifdef DO_PSTATS
+        _data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type) * 4 / 3);
+#endif
+        switch (target) {
+        case GL_TEXTURE_1D:
+          GLUP(Build1DMipmaps)(target, internal_format, width,
+                               external_format, component_type, image);
+          break;
 
 
-        case 1:
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_SRC0_ALPHA, 
-                       get_texture_src_type(stage->get_combine_alpha_source0()));
-          GLP(TexEnvi)(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, 
-                       get_texture_operand_type(stage->get_combine_alpha_operand0()));
-          // fall through
+        case GL_TEXTURE_3D:
+#ifdef GLU_VERSION_1_3
+          GLUP(Build3DMipmaps)(target, internal_format,
+                               width, height, depth,
+                               external_format, component_type, image);
+#else  // GLU_VERSION_1_3
+          // Prior to GLU 1.3, there was no gluBuild3DMipmaps() call.
+          // Just fall through and load the texture without mipmaps.
+          GLP(TexParameteri)(target, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+          success = false;
+#endif  // GLU_VERSION_1_3
+          break;
 
 
         default:
         default:
-          break;
+          GLUP(Build2DMipmaps)(target, internal_format,
+                               width, height,
+                               external_format, component_type, image);
+        }
+
+        report_my_gl_errors();
+        if (success) {
+          return true;
         }
         }
+      }
+  }
+
+  if (!gtc->_already_applied || 
+      gtc->_internal_format != internal_format ||
+      gtc->_width != width ||
+      gtc->_height != height ||
+      gtc->_depth != depth) {
+    // We need to reload a new image.
+#ifdef DO_PSTATS
+    _data_transferred_pcollector.add_level(get_external_texture_bytes(width, height, depth, external_format, component_type));
+#endif
+    switch (target) {
+    case GL_TEXTURE_1D:
+      GLP(TexImage1D)(target, 0, internal_format,
+                      width, 0,
+                      external_format, component_type, image);
+      break;
 
 
+    case GL_TEXTURE_3D:
+      if (_supports_3d_texture) {
+        _glTexImage3D(target, 0, internal_format,
+                      width, height, depth, 0,
+                      external_format, component_type, image);
       } else {
       } else {
-        GLint glmode = get_texture_apply_mode_type(stage->get_mode());
-        GLP(TexEnvi)(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, glmode);
+        report_my_gl_errors();
+        return false;
       }
       }
+      break;
 
 
-      GLP(MatrixMode)(GL_TEXTURE);
-      if (_current_tex_mat->has_stage(stage)) {
-        GLP(LoadMatrixf)(_current_tex_mat->get_mat(stage).get_data());
+    default:
+      GLP(TexImage2D)(target, 0, internal_format,
+                      width, height, 0,
+                      external_format, component_type, image);
+    }
+
+  } else {
+    // We can reload the image over the previous image, possibly
+    // saving on texture memory fragmentation.
+    switch (target) {
+    case GL_TEXTURE_1D:
+      GLP(TexSubImage1D)(target, 0, 0, width, 
+                         external_format, component_type, image);
+      break;
+
+    case GL_TEXTURE_3D:
+      if (_supports_3d_texture) {
+        _glTexSubImage3D(target, 0, 0, 0, 0, width, height, depth,
+                         external_format, component_type, image);
       } else {
       } else {
-        GLP(LoadIdentity)();
+        report_my_gl_errors();
+        return false;
       }
       }
+      break;
+
+    default:
+      GLP(TexSubImage2D)(target, 0, 0, 0, width, height,
+                         external_format, component_type, image);
+      break;
     }
     }
   }
   }
-    
-  // Disable the texture stages that are no longer used.
-  for (i = num_stages; i < num_old_stages; i++) {
-    _glActiveTexture(GL_TEXTURE0 + i);
-    GLP(Disable)(GL_TEXTURE_1D);
-    GLP(Disable)(GL_TEXTURE_2D);
-    if (_supports_3d_texture) {
-      GLP(Disable)(GL_TEXTURE_3D);
-    }
-    if (_supports_cube_map) {
-      GLP(Disable)(GL_TEXTURE_CUBE_MAP);
+
+  // Report the error message explicitly if the GL texture creation
+  // failed.
+  GLenum error_code = GLP(GetError)();
+  if (error_code != GL_NO_ERROR) {
+    const GLubyte *error_string = GLUP(ErrorString)(error_code);
+    GLCAT.error()
+      << "GL texture creation failed for " << gtc->_texture->get_name();
+    if (error_string != (const GLubyte *)NULL) {
+      GLCAT.error(false)
+        << " : " << error_string;
     }
     }
+    GLCAT.error(false)
+      << "\n";
   }
   }
 
 
-  _current_texture = new_texture;
-
-  // Changing the set of texture stages will require us to reissue the
-  // texgen and texmat attribs.
-  _needs_tex_gen = true;
-  _needs_tex_mat = true;
-
-  report_my_gl_errors();
+  return true;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 9 - 12
panda/src/glstuff/glGraphicsStateGuardian_src.h

@@ -29,7 +29,6 @@
 #include "texMatrixAttrib.h"
 #include "texMatrixAttrib.h"
 #include "texGenAttrib.h"
 #include "texGenAttrib.h"
 #include "textureStage.h"
 #include "textureStage.h"
-#include "textureApplyAttrib.h"
 #include "antialiasAttrib.h"
 #include "antialiasAttrib.h"
 #include "renderModeAttrib.h"
 #include "renderModeAttrib.h"
 #include "pointerToArray.h"
 #include "pointerToArray.h"
@@ -108,7 +107,6 @@ public:
   INLINE bool draw_display_list(GeomContext *gc);
   INLINE bool draw_display_list(GeomContext *gc);
 
 
   virtual TextureContext *prepare_texture(Texture *tex);
   virtual TextureContext *prepare_texture(Texture *tex);
-  virtual void apply_texture(TextureContext *tc, int index=0);
   virtual void release_texture(TextureContext *tc);
   virtual void release_texture(TextureContext *tc);
 
 
   virtual GeomContext *prepare_geom(Geom *geom);
   virtual GeomContext *prepare_geom(Geom *geom);
@@ -141,7 +139,6 @@ public:
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_render_mode(const RenderModeAttrib *attrib);
   virtual void issue_antialias(const AntialiasAttrib *);
   virtual void issue_antialias(const AntialiasAttrib *);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
   virtual void issue_rescale_normal(const RescaleNormalAttrib *attrib);
-  virtual void issue_texture_apply(const TextureApplyAttrib *attrib);
   virtual void issue_color_write(const ColorWriteAttrib *attrib);
   virtual void issue_color_write(const ColorWriteAttrib *attrib);
   virtual void issue_depth_test(const DepthTestAttrib *attrib);
   virtual void issue_depth_test(const DepthTestAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
   virtual void issue_alpha_test(const AlphaTestAttrib *attrib);
@@ -235,15 +232,6 @@ protected:
   void set_draw_buffer(const RenderBuffer &rb);
   void set_draw_buffer(const RenderBuffer &rb);
   void set_read_buffer(const RenderBuffer &rb);
   void set_read_buffer(const RenderBuffer &rb);
 
 
-  void bind_texture(TextureContext *tc);
-  void specify_texture(Texture *tex);
-  bool apply_texture_immediate(CLP(TextureContext) *gtc, Texture *tex);
-  bool upload_texture_image(CLP(TextureContext) *gtc, bool uses_mipmaps, 
-                            GLenum target, GLint internal_format, 
-                            int width, int height, int depth,
-                            GLint external_format, GLenum component_type, 
-                            const unsigned char *image);
-
   static GLenum get_numeric_type(qpGeom::NumericType numeric_type);
   static GLenum get_numeric_type(qpGeom::NumericType numeric_type);
   GLenum get_texture_target(Texture::TextureType texture_type) const;
   GLenum get_texture_target(Texture::TextureType texture_type) const;
   GLenum get_texture_wrap_mode(Texture::WrapMode wm);
   GLenum get_texture_wrap_mode(Texture::WrapMode wm);
@@ -269,6 +257,15 @@ protected:
 
 
   void do_auto_rescale_normal();
   void do_auto_rescale_normal();
   void do_issue_texture();
   void do_issue_texture();
+  void specify_texture(Texture *tex);
+  void apply_texture(TextureContext *tc);
+  bool upload_texture(CLP(TextureContext) *gtc);
+  bool upload_texture_image(CLP(TextureContext) *gtc, bool uses_mipmaps, 
+                            GLenum target, GLint internal_format, 
+                            int width, int height, int depth,
+                            GLint external_format, GLenum component_type, 
+                            const unsigned char *image);
+
   void do_point_size();
   void do_point_size();
 
 
 #ifndef NDEBUG
 #ifndef NDEBUG

+ 0 - 1
panda/src/glstuff/glTextureContext_src.I

@@ -27,7 +27,6 @@ CLP(TextureContext)(Texture *tex) :
   TextureContext(tex)
   TextureContext(tex)
 {
 {
   _index = 0;
   _index = 0;
-  _priority = 0.5; // For keeping resident in texture memory
 
 
   _already_applied = false;
   _already_applied = false;
 }
 }

+ 0 - 3
panda/src/glstuff/glTextureContext_src.h

@@ -30,9 +30,6 @@ public:
   // This is the GL "name" of the texture object.
   // This is the GL "name" of the texture object.
   GLuint _index;
   GLuint _index;
 
 
-  // This is a GL texture priority.
-  GLfloat _priority;
-
   // These are the parameters that we specified with the last
   // These are the parameters that we specified with the last
   // glTexImage2D() call.  If none of these have changed, we can
   // glTexImage2D() call.  If none of these have changed, we can
   // reload the texture image with a glTexSubImage2D().
   // reload the texture image with a glTexSubImage2D().

+ 8 - 4
panda/src/gobj/texture.I

@@ -105,7 +105,7 @@ setup_3d_texture(int x_size, int y_size, int z_size,
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Texture::
 INLINE void Texture::
 setup_cube_map() {
 setup_cube_map() {
-  setup_cube_map(0, 1, T_unsigned_byte, F_rgb);
+  setup_cube_map(0, T_unsigned_byte, F_rgb);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -114,12 +114,16 @@ setup_cube_map() {
 //  Description: Sets the texture as an empty cube map texture with
 //  Description: Sets the texture as an empty cube map texture with
 //               the specified dimensions and properties.  Follow up
 //               the specified dimensions and properties.  Follow up
 //               with set_ram_image() or modify_ram_image() to fill
 //               with set_ram_image() or modify_ram_image() to fill
-//               the image data.
+//               the image data.  
+//
+//               Note that a cube map should always consist of six
+//               square images, so x_size and y_size will be the same,
+//               and z_size is always 6.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void Texture::
 INLINE void Texture::
-setup_cube_map(int x_size, int y_size, ComponentType component_type, 
+setup_cube_map(int size, ComponentType component_type, 
                Format format) {
                Format format) {
-  setup_texture(TT_cube_map, x_size, y_size, 6, component_type, format);
+  setup_texture(TT_cube_map, size, size, 6, component_type, format);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 16 - 9
panda/src/gobj/texture.cxx

@@ -92,13 +92,17 @@ void Texture::
 setup_texture(Texture::TextureType texture_type, int x_size, int y_size, 
 setup_texture(Texture::TextureType texture_type, int x_size, int y_size, 
               int z_size, Texture::ComponentType component_type, 
               int z_size, Texture::ComponentType component_type, 
               Texture::Format format) {
               Texture::Format format) {
+#ifndef NDEBUG
+  if (texture_type == TT_cube_map) {
+    // Cube maps must always consist of six square images.
+    nassertv(x_size == y_size && z_size == 6);
+  }
+#endif
+
   _texture_type = texture_type;
   _texture_type = texture_type;
   _x_size = x_size;
   _x_size = x_size;
   _y_size = y_size;
   _y_size = y_size;
   _z_size = z_size;
   _z_size = z_size;
-  if (_texture_type == TT_cube_map) {
-    _z_size = 6;
-  }
   set_component_type(component_type);
   set_component_type(component_type);
   set_format(format);
   set_format(format);
 
 
@@ -386,10 +390,9 @@ write_pages(const Filename &fullpath_template) {
 //               multiple times, one for each page (z value).  Cube
 //               multiple times, one for each page (z value).  Cube
 //               maps have exactly 6 pages, while 3-d textures can
 //               maps have exactly 6 pages, while 3-d textures can
 //               have any number and can dynamically grow as each page
 //               have any number and can dynamically grow as each page
-//               is loaded.  For the first page loaded (or when
-//               reloading z == 0), this also sets the texture
-//               parameters; for subsequent pages, the texture
-//               parameters must match those which were loaded
+//               is loaded.  For the first page loaded, this also sets
+//               the texture parameters; for subsequent pages, the
+//               texture parameters must match those which were loaded
 //               previously.
 //               previously.
 //
 //
 //               This also implicitly sets keep_ram_image to false if
 //               This also implicitly sets keep_ram_image to false if
@@ -451,13 +454,17 @@ load(const PNMImage &pnmimage, int z) {
       // Eh?
       // Eh?
       nassertr(false, false);
       nassertr(false, false);
       _format = F_rgb;
       _format = F_rgb;
-    };
+    }
   }
   }
 
 
-  if (!_loaded_from_disk || z == 0) {
+  if (!_loaded_from_disk) {
+#ifndef NDEBUG
     if (_texture_type == TT_1d_texture) {
     if (_texture_type == TT_1d_texture) {
       nassertr(pnmimage.get_y_size() == 1, false);
       nassertr(pnmimage.get_y_size() == 1, false);
+    } else if (_texture_type == TT_cube_map) {
+      nassertr(pnmimage.get_x_size() == pnmimage.get_y_size(), false);
     }
     }
+#endif
     _x_size = pnmimage.get_x_size();
     _x_size = pnmimage.get_x_size();
     _y_size = pnmimage.get_y_size();
     _y_size = pnmimage.get_y_size();
     _num_components = num_components;
     _num_components = num_components;

+ 1 - 1
panda/src/gobj/texture.h

@@ -147,7 +147,7 @@ PUBLISHED:
   INLINE void setup_3d_texture(int x_size, int y_size, int z_size,
   INLINE void setup_3d_texture(int x_size, int y_size, int z_size,
                                ComponentType component_type, Format format);
                                ComponentType component_type, Format format);
   INLINE void setup_cube_map();
   INLINE void setup_cube_map();
-  INLINE void setup_cube_map(int x_size, int y_size,
+  INLINE void setup_cube_map(int size,
                              ComponentType component_type, Format format);
                              ComponentType component_type, Format format);
 
 
   bool read(const Filename &fullpath, int z = 0,
   bool read(const Filename &fullpath, int z = 0,

+ 1 - 1
panda/src/gobj/textureContext.I

@@ -26,7 +26,7 @@ INLINE TextureContext::
 TextureContext(Texture *tex) :
 TextureContext(Texture *tex) :
   _texture(tex)
   _texture(tex)
 {
 {
-  _dirty_flags = 0;
+  _dirty_flags = ~0;
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 0 - 3
panda/src/gsgbase/graphicsStateGuardianBase.h

@@ -76,7 +76,6 @@ class RenderModeAttrib;
 class AntialiasAttrib;
 class AntialiasAttrib;
 class RescaleNormalAttrib;
 class RescaleNormalAttrib;
 class ColorBlendAttrib;
 class ColorBlendAttrib;
-class TextureApplyAttrib;
 class ColorWriteAttrib;
 class ColorWriteAttrib;
 class AlphaTestAttrib;
 class AlphaTestAttrib;
 class DepthTestAttrib;
 class DepthTestAttrib;
@@ -135,7 +134,6 @@ public:
   virtual PreparedGraphicsObjects *get_prepared_objects()=0;
   virtual PreparedGraphicsObjects *get_prepared_objects()=0;
 
 
   virtual TextureContext *prepare_texture(Texture *tex)=0;
   virtual TextureContext *prepare_texture(Texture *tex)=0;
-  virtual void apply_texture(TextureContext *tc, int index=0)=0;
   virtual void release_texture(TextureContext *tc)=0;
   virtual void release_texture(TextureContext *tc)=0;
 
 
   virtual GeomContext *prepare_geom(Geom *geom)=0;
   virtual GeomContext *prepare_geom(Geom *geom)=0;
@@ -222,7 +220,6 @@ public:
   virtual void issue_render_mode(const RenderModeAttrib *) { }
   virtual void issue_render_mode(const RenderModeAttrib *) { }
   virtual void issue_antialias(const AntialiasAttrib *) { }
   virtual void issue_antialias(const AntialiasAttrib *) { }
   virtual void issue_rescale_normal(const RescaleNormalAttrib *) { }
   virtual void issue_rescale_normal(const RescaleNormalAttrib *) { }
-  virtual void issue_texture_apply(const TextureApplyAttrib *) { }
   virtual void issue_color_write(const ColorWriteAttrib *) { }
   virtual void issue_color_write(const ColorWriteAttrib *) { }
   virtual void issue_depth_test(const DepthTestAttrib *) { }
   virtual void issue_depth_test(const DepthTestAttrib *) { }
   virtual void issue_depth_write(const DepthWriteAttrib *) { }
   virtual void issue_depth_write(const DepthWriteAttrib *) { }

+ 0 - 3
panda/src/pgraph/Sources.pp

@@ -94,7 +94,6 @@
     switchNode.I switchNode.h \
     switchNode.I switchNode.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     texProjectorEffect.I texProjectorEffect.h \
     texProjectorEffect.I texProjectorEffect.h \
-    textureApplyAttrib.I textureApplyAttrib.h \
     textureAttrib.I textureAttrib.h \
     textureAttrib.I textureAttrib.h \
     texGenAttrib.I texGenAttrib.h \
     texGenAttrib.I texGenAttrib.h \
     textureCollection.I textureCollection.h \
     textureCollection.I textureCollection.h \
@@ -192,7 +191,6 @@
     switchNode.cxx \
     switchNode.cxx \
     texMatrixAttrib.cxx \
     texMatrixAttrib.cxx \
     texProjectorEffect.cxx \
     texProjectorEffect.cxx \
-    textureApplyAttrib.cxx \
     textureAttrib.cxx \
     textureAttrib.cxx \
     texGenAttrib.cxx \
     texGenAttrib.cxx \
     textureCollection.cxx \
     textureCollection.cxx \
@@ -286,7 +284,6 @@
     switchNode.I switchNode.h \
     switchNode.I switchNode.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     texMatrixAttrib.I texMatrixAttrib.h \
     texProjectorEffect.I texProjectorEffect.h \
     texProjectorEffect.I texProjectorEffect.h \
-    textureApplyAttrib.I textureApplyAttrib.h \
     textureAttrib.I textureAttrib.h \
     textureAttrib.I textureAttrib.h \
     texGenAttrib.I texGenAttrib.h \
     texGenAttrib.I texGenAttrib.h \
     textureCollection.I textureCollection.h \
     textureCollection.I textureCollection.h \

+ 0 - 3
panda/src/pgraph/config_pgraph.cxx

@@ -85,7 +85,6 @@
 #include "switchNode.h"
 #include "switchNode.h"
 #include "texMatrixAttrib.h"
 #include "texMatrixAttrib.h"
 #include "texProjectorEffect.h"
 #include "texProjectorEffect.h"
-#include "textureApplyAttrib.h"
 #include "textureAttrib.h"
 #include "textureAttrib.h"
 #include "texGenAttrib.h"
 #include "texGenAttrib.h"
 #include "transformState.h"
 #include "transformState.h"
@@ -324,7 +323,6 @@ init_libpgraph() {
   SwitchNode::init_type();
   SwitchNode::init_type();
   TexMatrixAttrib::init_type();
   TexMatrixAttrib::init_type();
   TexProjectorEffect::init_type();
   TexProjectorEffect::init_type();
-  TextureApplyAttrib::init_type();
   TextureAttrib::init_type();
   TextureAttrib::init_type();
   TexGenAttrib::init_type();
   TexGenAttrib::init_type();
   TransformState::init_type();
   TransformState::init_type();
@@ -380,7 +378,6 @@ init_libpgraph() {
   SwitchNode::register_with_read_factory();
   SwitchNode::register_with_read_factory();
   TexMatrixAttrib::register_with_read_factory();
   TexMatrixAttrib::register_with_read_factory();
   TexProjectorEffect::register_with_read_factory();
   TexProjectorEffect::register_with_read_factory();
-  TextureApplyAttrib::register_with_read_factory();
   TextureAttrib::register_with_read_factory();
   TextureAttrib::register_with_read_factory();
   TexGenAttrib::register_with_read_factory();
   TexGenAttrib::register_with_read_factory();
   TransformState::register_with_read_factory();
   TransformState::register_with_read_factory();

+ 12 - 6
panda/src/pgraph/lensNode.I

@@ -18,8 +18,8 @@
 
 
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: copy_lens
-//       Access: Public
+//     Function: LensNode::copy_lens
+//       Access: Published
 //  Description: Sets up the LensNode using a copy of the
 //  Description: Sets up the LensNode using a copy of the
 //               indicated Lens.  If the original Lens is
 //               indicated Lens.  If the original Lens is
 //               changed or destroyed, this LensNode is not
 //               changed or destroyed, this LensNode is not
@@ -28,11 +28,14 @@
 INLINE void LensNode::
 INLINE void LensNode::
 copy_lens(const Lens &lens) {
 copy_lens(const Lens &lens) {
   _lens = lens.make_copy();
   _lens = lens.make_copy();
+  if (_shown_frustum != (PandaNode *)NULL) {
+    show_frustum();
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: set_lens
-//       Access: Public
+//     Function: LensNode::set_lens
+//       Access: Published
 //  Description: Sets up the LensNode using this particular Lens
 //  Description: Sets up the LensNode using this particular Lens
 //               pointer.  If the lens is subsequently modified, the
 //               pointer.  If the lens is subsequently modified, the
 //               LensNode properties immediately reflect the change.
 //               LensNode properties immediately reflect the change.
@@ -40,11 +43,14 @@ copy_lens(const Lens &lens) {
 INLINE void LensNode::
 INLINE void LensNode::
 set_lens(Lens *lens) {
 set_lens(Lens *lens) {
   _lens = lens;
   _lens = lens;
+  if (_shown_frustum != (PandaNode *)NULL) {
+    show_frustum();
+  }
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: get_lens
-//       Access: Public
+//     Function: LensNode::get_lens
+//       Access: Published
 //  Description: Returns a pointer to the particular Lens
 //  Description: Returns a pointer to the particular Lens
 //               associated with this LensNode, or NULL if there is
 //               associated with this LensNode, or NULL if there is
 //               not yet a Lens associated.
 //               not yet a Lens associated.

+ 40 - 4
panda/src/pgraph/lensNode.cxx

@@ -22,12 +22,13 @@
 #include "bamReader.h"
 #include "bamReader.h"
 #include "datagram.h"
 #include "datagram.h"
 #include "datagramIterator.h"
 #include "datagramIterator.h"
+#include "geomNode.h"
 
 
 TypeHandle LensNode::_type_handle;
 TypeHandle LensNode::_type_handle;
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LensNode::Constructor
 //     Function: LensNode::Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 LensNode::
 LensNode::
@@ -50,7 +51,7 @@ LensNode(const LensNode &copy) :
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LensNode::xform
 //     Function: LensNode::xform
-//       Access: Public, Virtual
+//       Access: Published, Virtual
 //  Description: Transforms the contents of this PandaNode by the
 //  Description: Transforms the contents of this PandaNode by the
 //               indicated matrix, if it means anything to do so.  For
 //               indicated matrix, if it means anything to do so.  For
 //               most kinds of PandaNodes, this does nothing.
 //               most kinds of PandaNodes, this does nothing.
@@ -63,7 +64,7 @@ xform(const LMatrix4f &mat) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LensNode::make_copy
 //     Function: LensNode::make_copy
-//       Access: Public, Virtual
+//       Access: Published, Virtual
 //  Description: Returns a newly-allocated Node that is a shallow copy
 //  Description: Returns a newly-allocated Node that is a shallow copy
 //               of this one.  It will be a different Node pointer,
 //               of this one.  It will be a different Node pointer,
 //               but its internal data may or may not be shared with
 //               but its internal data may or may not be shared with
@@ -76,7 +77,7 @@ make_copy() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LensNode::is_in_view
 //     Function: LensNode::is_in_view
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the given point is within the bounds
 //  Description: Returns true if the given point is within the bounds
 //               of the lens of the LensNode (i.e. if the camera can
 //               of the lens of the LensNode (i.e. if the camera can
 //               see the point).
 //               see the point).
@@ -92,6 +93,41 @@ is_in_view(const LPoint3f &pos) {
   return (ret != 0);
   return (ret != 0);
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: LensNode::show_frustum
+//       Access: Published
+//  Description: Enables the drawing of the lens's frustum to aid in
+//               visualization.  This actually creates a GeomNode
+//               which is parented to the LensNode.
+////////////////////////////////////////////////////////////////////
+void LensNode::
+show_frustum() {
+  if (_shown_frustum != (PandaNode *)NULL) {
+    hide_frustum();
+  }
+  PT(GeomNode) geom_node = new GeomNode("frustum");
+  _shown_frustum = geom_node;
+  add_child(_shown_frustum);
+
+  if (_lens != (Lens *)NULL) {
+    geom_node->add_geom(_lens->make_geometry());
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: LensNode::hide_frustum
+//       Access: Published
+//  Description: Disables the drawing of the lens's frustum to aid in
+//               visualization.
+////////////////////////////////////////////////////////////////////
+void LensNode::
+hide_frustum() {
+  if (_shown_frustum != (PandaNode *)NULL) {
+    remove_child(_shown_frustum);
+    _shown_frustum = (PandaNode *)NULL;
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: LensNode::output
 //     Function: LensNode::output
 //       Access: Public, Virtual
 //       Access: Public, Virtual

+ 4 - 0
panda/src/pgraph/lensNode.h

@@ -52,8 +52,12 @@ PUBLISHED:
 
 
   bool is_in_view(const LPoint3f &pos);
   bool is_in_view(const LPoint3f &pos);
 
 
+  void show_frustum();
+  void hide_frustum();
+
 protected:
 protected:
   PT(Lens) _lens;
   PT(Lens) _lens;
+  PT(PandaNode) _shown_frustum;
 
 
 public:
 public:
   static void register_with_read_factory();
   static void register_with_read_factory();

+ 0 - 1
panda/src/pgraph/pgraph_composite4.cxx

@@ -14,7 +14,6 @@
 #include "switchNode.cxx"
 #include "switchNode.cxx"
 #include "texMatrixAttrib.cxx"
 #include "texMatrixAttrib.cxx"
 #include "texProjectorEffect.cxx"
 #include "texProjectorEffect.cxx"
-#include "textureApplyAttrib.cxx"
 #include "textureAttrib.cxx"
 #include "textureAttrib.cxx"
 #include "texGenAttrib.cxx"
 #include "texGenAttrib.cxx"
 #include "textureCollection.cxx"
 #include "textureCollection.cxx"

+ 48 - 74
panda/src/pgraph/spotlight.cxx

@@ -142,87 +142,61 @@ write(ostream &out, int indent_level) const {
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
-//     Function: Spotlight::bind
-//       Access: Public, Virtual
-//  Description:
-////////////////////////////////////////////////////////////////////
-void Spotlight::
-bind(GraphicsStateGuardianBase *gsg, const NodePath &light, int light_id) {
-  gsg->bind_light(this, light, light_id);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: Spotlight::make_image
-//       Access: Public
-//  Description: Generates an image into the indicated texture of a
-//               circle with a soft edge that corresponds to the
-//               falloff of the spotlight.  This is intended to be
-//               used to implement projected texture spotlights; the
-//               image can be applied to geometry with UV's computed
-//               appropriate to simulate the texture's region of
-//               influence.
+//     Function: Spotlight::make_spot
+//       Access: Published, Static
+//  Description: Returns a newly-generated Texture that renders a
+//               circular spot image as might be cast from the
+//               spotlight.  This may be projected onto target
+//               geometry (for instance, via
+//               NodePath::project_texture()) instead of actually
+//               enabling the light itself, as a cheesy way to make a
+//               high-resolution spot appear on the geometry.
 //
 //
-//               Returns true if the image is successfully generated,
-//               false otherwise.
-////////////////////////////////////////////////////////////////////
-bool Spotlight::
-make_image(Texture *texture, float radius) {
-  if (texture == NULL) {
-    pgraph_cat.error()
-      << "Spotlight::make_image() - NULL texture" << endl;
-    return false;
+//               pixel_width specifies the height and width of the new
+//               texture in pixels, full_radius is a value in the
+//               range 0..1 that indicates the relative size of the
+//               fully bright center spot, and fg and bg are the
+//               colors of the interior and exterior of the spot,
+//               respectively.
+////////////////////////////////////////////////////////////////////
+PT(Texture) Spotlight::
+make_spot(int pixel_width, float full_radius, Colorf &fg, Colorf &bg) {
+  int num_channels;
+  if (fg[0] == fg[1] && fg[1] == fg[2] &&
+      bg[0] == bg[1] && bg[1] == bg[2]) {
+    // grayscale
+    num_channels = 1;
+  } else {
+    // color
+    num_channels = 3;
   }
   }
-  int size = min(texture->get_x_size(), texture->get_y_size());
-  if (size == 0) {
-    size = 64;
+  if (fg[3] != 1.0f || bg[3] != 1.0f) {
+    // with alpha.
+    ++num_channels;
   }
   }
+  PNMImage image(pixel_width, pixel_width, num_channels);
+  image.render_spot(LCAST(double, fg), LCAST(double, bg), full_radius, 1.0);
 
 
-  PNMImage image(size, size, 1);
-
-  const Colorf &c4 = get_color();
-  const RGBColord color(c4[0], c4[1], c4[2]);
-
-  int half_width = (size - 2) / 2;
-  float dXY = 1 / (float)half_width;
-  float Y = dXY + dXY;
-  float X, YY, dist_from_center, intensity;
-  int tx, ty, tx2, ty2;
-
-  for (int y = 0; y < half_width; y++, Y += dXY) {
-    X = dXY * y + dXY;
-    YY = Y * Y;
-    ty = y + half_width;
-
-    for (int x = y; x < half_width; x++, X += dXY) {
-      dist_from_center = (float)sqrt(X * X + YY);
-      float D = dist_from_center;
-      if (D <= radius)
-        intensity = 1.0f;
-          else if (D < 1.0f)
-        intensity = pow(cos((D-radius) /
-                (1.0f-radius) * (MathNumbers::pi_f*0.5f)), get_exponent());
-      else
-        intensity = 0;
+  PT(Texture) tex = new Texture("spot");
+  tex->load(image);
+  tex->set_border_color(bg);
+  tex->set_wrap_u(Texture::WM_border_color);
+  tex->set_wrap_v(Texture::WM_border_color);
 
 
-      tx = x + half_width;
+  tex->set_minfilter(Texture::FT_linear);
+  tex->set_magfilter(Texture::FT_linear);
 
 
-      image.set_xel(tx, ty, color * intensity);
-      image.set_xel(tx, size - ty - 1, color * intensity);
-      image.set_xel(size - tx - 1, ty, color * intensity);
-      image.set_xel(size - tx - 1, size - ty - 1, color * intensity);
-
-      tx2 = ty; ty2 = tx;
-
-      image.set_xel(tx2, ty2, color * intensity);
-      image.set_xel(tx2, size - ty2 - 1, color * intensity);
-      image.set_xel(size - tx2 - 1, ty2, color * intensity);
-      image.set_xel(size - tx2 - 1, size - ty2 - 1, color * intensity);
-    }
-  }
-
-  texture->load(image);
+  return tex;
+}
 
 
-  return true;
+////////////////////////////////////////////////////////////////////
+//     Function: Spotlight::bind
+//       Access: Public, Virtual
+//  Description:
+////////////////////////////////////////////////////////////////////
+void Spotlight::
+bind(GraphicsStateGuardianBase *gsg, const NodePath &light, int light_id) {
+  gsg->bind_light(this, light, light_id);
 }
 }
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////

+ 3 - 2
panda/src/pgraph/spotlight.h

@@ -60,13 +60,14 @@ PUBLISHED:
   
   
   INLINE const LVecBase3f &get_attenuation() const;
   INLINE const LVecBase3f &get_attenuation() const;
   INLINE void set_attenuation(const LVecBase3f &attenuation);
   INLINE void set_attenuation(const LVecBase3f &attenuation);
+
+  static PT(Texture) make_spot(int pixel_width, float full_radius,
+                               Colorf &fg, Colorf &bg);
   
   
 public:
 public:
   virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
   virtual void bind(GraphicsStateGuardianBase *gsg, const NodePath &light,
                     int light_id);
                     int light_id);
 
 
-  bool make_image(Texture *texture, float radius);
-
 protected:
 protected:
   virtual void fill_viz_geom(GeomNode *viz_geom);
   virtual void fill_viz_geom(GeomNode *viz_geom);
 
 

+ 0 - 40
panda/src/pgraph/textureApplyAttrib.I

@@ -1,40 +0,0 @@
-// Filename: textureApplyAttrib.I
-// Created by:  drose (04Mar02)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::Constructor
-//       Access: Private
-//  Description: Use TextureApplyAttrib::make() to construct a new
-//               TextureApplyAttrib object.
-////////////////////////////////////////////////////////////////////
-INLINE TextureApplyAttrib::
-TextureApplyAttrib(TextureApplyAttrib::Mode mode) :
-  _mode(mode)
-{
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::get_mode
-//       Access: Published
-//  Description: Returns the culling mode.
-////////////////////////////////////////////////////////////////////
-INLINE TextureApplyAttrib::Mode TextureApplyAttrib::
-get_mode() const {
-  return _mode;
-}

+ 0 - 179
panda/src/pgraph/textureApplyAttrib.cxx

@@ -1,179 +0,0 @@
-// Filename: textureApplyAttrib.cxx
-// Created by:  drose (04Mar02)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#include "textureApplyAttrib.h"
-#include "graphicsStateGuardianBase.h"
-#include "dcast.h"
-#include "bamReader.h"
-#include "bamWriter.h"
-#include "datagram.h"
-#include "datagramIterator.h"
-
-TypeHandle TextureApplyAttrib::_type_handle;
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::make
-//       Access: Published, Static
-//  Description: Constructs a new TextureApplyAttrib object.
-////////////////////////////////////////////////////////////////////
-CPT(RenderAttrib) TextureApplyAttrib::
-make(TextureApplyAttrib::Mode mode) {
-  TextureApplyAttrib *attrib = new TextureApplyAttrib(mode);
-  return return_new(attrib);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::issue
-//       Access: Public, Virtual
-//  Description: Calls the appropriate method on the indicated GSG
-//               to issue the graphics commands appropriate to the
-//               given attribute.  This is normally called
-//               (indirectly) only from
-//               GraphicsStateGuardian::set_state() or modify_state().
-////////////////////////////////////////////////////////////////////
-void TextureApplyAttrib::
-issue(GraphicsStateGuardianBase *gsg) const {
-  gsg->issue_texture_apply(this);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::output
-//       Access: Public, Virtual
-//  Description: 
-////////////////////////////////////////////////////////////////////
-void TextureApplyAttrib::
-output(ostream &out) const {
-  out << get_type() << ":";
-  switch (get_mode()) {
-  case M_modulate:
-    out << "modulate";
-    break;
-
-  case M_decal:
-    out << "decal";
-    break;
-
-  case M_blend:
-    out << "blend";
-    break;
-
-  case M_replace:
-    out << "replace";
-    break;
-
-  case M_add:
-    out << "add";
-    break;
-  }
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::compare_to_impl
-//       Access: Protected, Virtual
-//  Description: Intended to be overridden by derived TextureApplyAttrib
-//               types to return a unique number indicating whether
-//               this TextureApplyAttrib is equivalent to the other one.
-//
-//               This should return 0 if the two TextureApplyAttrib objects
-//               are equivalent, a number less than zero if this one
-//               should be sorted before the other one, and a number
-//               greater than zero otherwise.
-//
-//               This will only be called with two TextureApplyAttrib
-//               objects whose get_type() functions return the same.
-////////////////////////////////////////////////////////////////////
-int TextureApplyAttrib::
-compare_to_impl(const RenderAttrib *other) const {
-  const TextureApplyAttrib *ta;
-  DCAST_INTO_R(ta, other, 0);
-  return (int)_mode - (int)ta->_mode;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::make_default_impl
-//       Access: Protected, Virtual
-//  Description: Intended to be overridden by derived TextureApplyAttrib
-//               types to specify what the default property for a
-//               TextureApplyAttrib of this type should be.
-//
-//               This should return a newly-allocated TextureApplyAttrib of
-//               the same type that corresponds to whatever the
-//               standard default for this kind of TextureApplyAttrib is.
-////////////////////////////////////////////////////////////////////
-RenderAttrib *TextureApplyAttrib::
-make_default_impl() const {
-  return new TextureApplyAttrib;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::register_with_read_factory
-//       Access: Public, Static
-//  Description: Tells the BamReader how to create objects of type
-//               TextureApplyAttrib.
-////////////////////////////////////////////////////////////////////
-void TextureApplyAttrib::
-register_with_read_factory() {
-  BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::write_datagram
-//       Access: Public, Virtual
-//  Description: Writes the contents of this object to the datagram
-//               for shipping out to a Bam file.
-////////////////////////////////////////////////////////////////////
-void TextureApplyAttrib::
-write_datagram(BamWriter *manager, Datagram &dg) {
-  RenderAttrib::write_datagram(manager, dg);
-
-  dg.add_int8(_mode);
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::make_from_bam
-//       Access: Protected, Static
-//  Description: This function is called by the BamReader's factory
-//               when a new object of type TextureApplyAttrib is encountered
-//               in the Bam file.  It should create the TextureApplyAttrib
-//               and extract its information from the file.
-////////////////////////////////////////////////////////////////////
-TypedWritable *TextureApplyAttrib::
-make_from_bam(const FactoryParams &params) {
-  TextureApplyAttrib *attrib = new TextureApplyAttrib;
-  DatagramIterator scan;
-  BamReader *manager;
-
-  parse_params(params, scan, manager);
-  attrib->fillin(scan, manager);
-
-  return attrib;
-}
-
-////////////////////////////////////////////////////////////////////
-//     Function: TextureApplyAttrib::fillin
-//       Access: Protected
-//  Description: This internal function is called by make_from_bam to
-//               read in all of the relevant data from the BamFile for
-//               the new TextureApplyAttrib.
-////////////////////////////////////////////////////////////////////
-void TextureApplyAttrib::
-fillin(DatagramIterator &scan, BamReader *manager) {
-  RenderAttrib::fillin(scan, manager);
-
-  _mode = (Mode)scan.get_int8();
-}

+ 0 - 95
panda/src/pgraph/textureApplyAttrib.h

@@ -1,95 +0,0 @@
-// Filename: textureApplyAttrib.h
-// Created by:  drose (04Mar02)
-//
-////////////////////////////////////////////////////////////////////
-//
-// PANDA 3D SOFTWARE
-// Copyright (c) 2001 - 2004, Disney Enterprises, Inc.  All rights reserved
-//
-// All use of this software is subject to the terms of the Panda 3d
-// Software license.  You should have received a copy of this license
-// along with this source code; you will also find a current copy of
-// the license at http://etc.cmu.edu/panda3d/docs/license/ .
-//
-// To contact the maintainers of this program write to
-// [email protected] .
-//
-////////////////////////////////////////////////////////////////////
-
-#ifndef TEXTUREAPPLYATTRIB_H
-#define TEXTUREAPPLYATTRIB_H
-
-#include "pandabase.h"
-
-#include "renderAttrib.h"
-
-class FactoryParams;
-
-////////////////////////////////////////////////////////////////////
-//       Class : TextureApplyAttrib
-// Description : Specifies how textures are applied; specifically, how
-//               texture color modifies geometry color.
-//
-//               This class is now deprecated; it has been replaced
-//               with the TextureStage class to support
-//               multitexturing.
-////////////////////////////////////////////////////////////////////
-class EXPCL_PANDA TextureApplyAttrib : public RenderAttrib {
-PUBLISHED:
-  enum Mode {
-    M_modulate,
-    M_decal,
-    M_blend,
-    M_replace,
-    M_add
-  };
-
-private:
-  INLINE TextureApplyAttrib(Mode mode = M_modulate);
-
-PUBLISHED:
-  static CPT(RenderAttrib) make(Mode mode);
-
-  INLINE Mode get_mode() const;
-
-public:
-  virtual void issue(GraphicsStateGuardianBase *gsg) const;
-  virtual void output(ostream &out) const;
-
-protected:
-  virtual int compare_to_impl(const RenderAttrib *other) const;
-  virtual RenderAttrib *make_default_impl() const;
-
-private:
-  Mode _mode;
-
-public:
-  static void register_with_read_factory();
-  virtual void write_datagram(BamWriter *manager, Datagram &dg);
-
-protected:
-  static TypedWritable *make_from_bam(const FactoryParams &params);
-  void fillin(DatagramIterator &scan, BamReader *manager);
-  
-public:
-  static TypeHandle get_class_type() {
-    return _type_handle;
-  }
-  static void init_type() {
-    RenderAttrib::init_type();
-    register_type(_type_handle, "TextureApplyAttrib",
-                  RenderAttrib::get_class_type());
-  }
-  virtual TypeHandle get_type() const {
-    return get_class_type();
-  }
-  virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
-
-private:
-  static TypeHandle _type_handle;
-};
-
-#include "textureApplyAttrib.I"
-
-#endif
-

+ 106 - 57
panda/src/pnmimage/pnmImage.I

@@ -18,7 +18,7 @@
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::Constructor
 //     Function: PNMImage::Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImage::
 INLINE PNMImage::
@@ -29,7 +29,7 @@ PNMImage() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::Constructor
 //     Function: PNMImage::Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImage::
 INLINE PNMImage::
@@ -42,7 +42,7 @@ PNMImage(const Filename &filename, PNMFileType *type) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::Constructor
 //     Function: PNMImage::Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImage::
 INLINE PNMImage::
@@ -56,7 +56,7 @@ PNMImage(int x_size, int y_size, int num_channels, xelval maxval,
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::Copy Constructor
 //     Function: PNMImage::Copy Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImage::
 INLINE PNMImage::
@@ -71,7 +71,7 @@ PNMImage(const PNMImage &copy) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::Copy Assigment Operator
 //     Function: PNMImage::Copy Assigment Operator
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImage::
 INLINE void PNMImage::
@@ -81,7 +81,7 @@ operator = (const PNMImage &copy) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::Destructor
 //     Function: PNMImage::Destructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImage::
 INLINE PNMImage::
@@ -92,7 +92,7 @@ INLINE PNMImage::
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::clamp_val
 //     Function: PNMImage::clamp_val
-//       Access: Public
+//       Access: Published
 //  Description: A handy function to clamp values to
 //  Description: A handy function to clamp values to
 //               [0..get_maxval()].
 //               [0..get_maxval()].
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -103,7 +103,7 @@ clamp_val(int input_value) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::to_val
 //     Function: PNMImage::to_val
-//       Access: Public
+//       Access: Published
 //  Description: A handy function to scale values from [0..1] to
 //  Description: A handy function to scale values from [0..1] to
 //               [0..get_maxval()].
 //               [0..get_maxval()].
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -114,7 +114,7 @@ to_val(double input_value) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::from_val
 //     Function: PNMImage::from_val
-//       Access: Public
+//       Access: Published
 //  Description: A handy function to scale values from
 //  Description: A handy function to scale values from
 //               [0..get_maxval()] to [0..1].
 //               [0..get_maxval()] to [0..1].
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -125,7 +125,7 @@ from_val(xelval input_value) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::fill
 //     Function: PNMImage::fill
-//       Access: Public
+//       Access: Published
 //  Description: Sets the entire image (except the alpha channel) to
 //  Description: Sets the entire image (except the alpha channel) to
 //               the given color.
 //               the given color.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -138,7 +138,7 @@ fill(double red, double green, double blue) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::fill
 //     Function: PNMImage::fill
-//       Access: Public
+//       Access: Published
 //  Description: Sets the entire image (except the alpha channel) to
 //  Description: Sets the entire image (except the alpha channel) to
 //               the given grayscale level.
 //               the given grayscale level.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -149,7 +149,7 @@ fill(double gray) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::fill_val
 //     Function: PNMImage::fill_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the entire image (except the alpha channel) to
 //  Description: Sets the entire image (except the alpha channel) to
 //               the given grayscale level.
 //               the given grayscale level.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -160,7 +160,7 @@ fill_val(xelval gray) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::alpha_fill
 //     Function: PNMImage::alpha_fill
-//       Access: Public
+//       Access: Published
 //  Description: Sets the entire alpha channel to the given level.
 //  Description: Sets the entire alpha channel to the given level.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImage::
 INLINE void PNMImage::
@@ -170,7 +170,7 @@ alpha_fill(double alpha) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::is_valid
 //     Function: PNMImage::is_valid
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the image has been read in or
 //  Description: Returns true if the image has been read in or
 //               correctly initialized with a height and width.  If
 //               correctly initialized with a height and width.  If
 //               this returns false, virtually all member functions
 //               this returns false, virtually all member functions
@@ -183,7 +183,7 @@ is_valid() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_num_channels
 //     Function: PNMImage::set_num_channels
-//       Access: Public
+//       Access: Published
 //  Description: Changes the number of channels associated with the
 //  Description: Changes the number of channels associated with the
 //               image.  The new number of channels must be an integer
 //               image.  The new number of channels must be an integer
 //               in the range 1 through 4, inclusive.  This will
 //               in the range 1 through 4, inclusive.  This will
@@ -198,7 +198,7 @@ set_num_channels(int num_channels) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::add_alpha
 //     Function: PNMImage::add_alpha
-//       Access: Public
+//       Access: Published
 //  Description: Adds an alpha channel to the image, if it does not
 //  Description: Adds an alpha channel to the image, if it does not
 //               already have one.  The alpha channel is initialized
 //               already have one.  The alpha channel is initialized
 //               to zeros.
 //               to zeros.
@@ -210,7 +210,7 @@ add_alpha() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::remove_alpha
 //     Function: PNMImage::remove_alpha
-//       Access: Public
+//       Access: Published
 //  Description: Removes the image's alpha channel, if it exists.
 //  Description: Removes the image's alpha channel, if it exists.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImage::
 INLINE void PNMImage::
@@ -220,7 +220,7 @@ remove_alpha() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::make_grayscale
 //     Function: PNMImage::make_grayscale
-//       Access: Public
+//       Access: Published
 //  Description: Converts the image from RGB to grayscale.  Any alpha
 //  Description: Converts the image from RGB to grayscale.  Any alpha
 //               channel, if present, is left undisturbed.
 //               channel, if present, is left undisturbed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -231,7 +231,7 @@ make_grayscale() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::make_rgb
 //     Function: PNMImage::make_rgb
-//       Access: Public
+//       Access: Published
 //  Description: Converts the image from grayscale to RGB.  Any alpha
 //  Description: Converts the image from grayscale to RGB.  Any alpha
 //               channel, if present, is left undisturbed.
 //               channel, if present, is left undisturbed.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -242,7 +242,7 @@ make_rgb() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_xel_val
 //     Function: PNMImage::get_xel_val
-//       Access: Public
+//       Access: Published
 //  Description: Returns the RGB color at the indicated pixel.  Each
 //  Description: Returns the RGB color at the indicated pixel.  Each
 //               component is in the range 0..maxval.
 //               component is in the range 0..maxval.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -253,7 +253,7 @@ get_xel_val(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_xel_val
 //     Function: PNMImage::set_xel_val
-//       Access: Public
+//       Access: Published
 //  Description: Changes the RGB color at the indicated pixel.  Each
 //  Description: Changes the RGB color at the indicated pixel.  Each
 //               component is in the range 0..maxval.
 //               component is in the range 0..maxval.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -264,7 +264,7 @@ set_xel_val(int x, int y, const xel &value) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_xel_val
 //     Function: PNMImage::set_xel_val
-//       Access: Public
+//       Access: Published
 //  Description: Changes the RGB color at the indicated pixel.  Each
 //  Description: Changes the RGB color at the indicated pixel.  Each
 //               component is in the range 0..maxval.
 //               component is in the range 0..maxval.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -275,7 +275,7 @@ set_xel_val(int x, int y, xelval r, xelval g, xelval b) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_xel_val
 //     Function: PNMImage::set_xel_val
-//       Access: Public
+//       Access: Published
 //  Description: Changes all three color components at the indicated
 //  Description: Changes all three color components at the indicated
 //               pixel to the same value.  The value is in the range
 //               pixel to the same value.  The value is in the range
 //               0..maxval.
 //               0..maxval.
@@ -287,7 +287,7 @@ set_xel_val(int x, int y, xelval gray) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_red_val
 //     Function: PNMImage::get_red_val
-//       Access: Public
+//       Access: Published
 //  Description: Returns the red component color at the indicated
 //  Description: Returns the red component color at the indicated
 //               pixel.  The value returned is in the range 0..maxval.
 //               pixel.  The value returned is in the range 0..maxval.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -298,7 +298,7 @@ get_red_val(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_green_val
 //     Function: PNMImage::get_green_val
-//       Access: Public
+//       Access: Published
 //  Description: Returns the green component color at the indicated
 //  Description: Returns the green component color at the indicated
 //               pixel.  The value returned is in the range 0..maxval.
 //               pixel.  The value returned is in the range 0..maxval.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -309,7 +309,7 @@ get_green_val(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_blue_val
 //     Function: PNMImage::get_blue_val
-//       Access: Public
+//       Access: Published
 //  Description: Returns the blue component color at the indicated
 //  Description: Returns the blue component color at the indicated
 //               pixel.  The value returned is in the range 0..maxval.
 //               pixel.  The value returned is in the range 0..maxval.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -320,7 +320,7 @@ get_blue_val(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_gray_val
 //     Function: PNMImage::get_gray_val
-//       Access: Public
+//       Access: Published
 //  Description: Returns the gray component color at the indicated
 //  Description: Returns the gray component color at the indicated
 //               pixel.  This only has a meaningful value for
 //               pixel.  This only has a meaningful value for
 //               grayscale images; for other image types, this returns
 //               grayscale images; for other image types, this returns
@@ -335,7 +335,7 @@ get_gray_val(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_alpha_val
 //     Function: PNMImage::get_alpha_val
-//       Access: Public
+//       Access: Published
 //  Description: Returns the alpha component color at the indicated
 //  Description: Returns the alpha component color at the indicated
 //               pixel.  It is an error to call this unless
 //               pixel.  It is an error to call this unless
 //               has_alpha() is true.  The value returned is in the
 //               has_alpha() is true.  The value returned is in the
@@ -348,7 +348,7 @@ get_alpha_val(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_red_val
 //     Function: PNMImage::set_red_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the red component color only at the indicated
 //  Description: Sets the red component color only at the indicated
 //               pixel.  The value given should be in the range
 //               pixel.  The value given should be in the range
 //               0..maxval.
 //               0..maxval.
@@ -360,7 +360,7 @@ set_red_val(int x, int y, xelval r) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_green_val
 //     Function: PNMImage::set_green_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the green component color only at the indicated
 //  Description: Sets the green component color only at the indicated
 //               pixel.  The value given should be in the range
 //               pixel.  The value given should be in the range
 //               0..maxval.
 //               0..maxval.
@@ -372,7 +372,7 @@ set_green_val(int x, int y, xelval g) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_blue_val
 //     Function: PNMImage::set_blue_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the blue component color only at the indicated
 //  Description: Sets the blue component color only at the indicated
 //               pixel.  The value given should be in the range
 //               pixel.  The value given should be in the range
 //               0..maxval.
 //               0..maxval.
@@ -384,7 +384,7 @@ set_blue_val(int x, int y, xelval b) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_gray_val
 //     Function: PNMImage::set_gray_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the gray component color at the indicated
 //  Description: Sets the gray component color at the indicated
 //               pixel.  This is only meaningful for grayscale images;
 //               pixel.  This is only meaningful for grayscale images;
 //               for other image types, this simply sets the blue
 //               for other image types, this simply sets the blue
@@ -401,7 +401,7 @@ set_gray_val(int x, int y, xelval gray) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_alpha_val
 //     Function: PNMImage::set_alpha_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the alpha component color only at the indicated
 //  Description: Sets the alpha component color only at the indicated
 //               pixel.  It is an error to call this unless
 //               pixel.  It is an error to call this unless
 //               has_alpha() is true.  The value given should be in
 //               has_alpha() is true.  The value given should be in
@@ -414,7 +414,7 @@ set_alpha_val(int x, int y, xelval a) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_xel
 //     Function: PNMImage::get_xel
-//       Access: Public
+//       Access: Published
 //  Description: Returns the RGB color at the indicated pixel.  Each
 //  Description: Returns the RGB color at the indicated pixel.  Each
 //               component is a double in the range 0..1.
 //               component is a double in the range 0..1.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -427,7 +427,7 @@ get_xel(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_xel
 //     Function: PNMImage::set_xel
-//       Access: Public
+//       Access: Published
 //  Description: Changes the RGB color at the indicated pixel.  Each
 //  Description: Changes the RGB color at the indicated pixel.  Each
 //               component is a double in the range 0..1.
 //               component is a double in the range 0..1.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -438,7 +438,7 @@ set_xel(int x, int y, const RGBColord &value) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_xel
 //     Function: PNMImage::set_xel
-//       Access: Public
+//       Access: Published
 //  Description: Changes the RGB color at the indicated pixel.  Each
 //  Description: Changes the RGB color at the indicated pixel.  Each
 //               component is a double in the range 0..1.
 //               component is a double in the range 0..1.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -449,7 +449,7 @@ set_xel(int x, int y, double r, double g, double b) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_xel
 //     Function: PNMImage::set_xel
-//       Access: Public
+//       Access: Published
 //  Description: Changes all three color components at the indicated
 //  Description: Changes all three color components at the indicated
 //               pixel to the same value.  The value is a double in
 //               pixel to the same value.  The value is a double in
 //               the range 0..1.
 //               the range 0..1.
@@ -459,9 +459,58 @@ set_xel(int x, int y, double gray) {
   set_xel_val(x, y, to_val(gray), to_val(gray), to_val(gray));
   set_xel_val(x, y, to_val(gray), to_val(gray), to_val(gray));
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PNMImage::get_xel_a
+//       Access: Published
+//  Description: Returns the RGBA color at the indicated pixel.  Each
+//               component is a double in the range 0..1.
+////////////////////////////////////////////////////////////////////
+INLINE Colord PNMImage::
+get_xel_a(int x, int y) const {
+  if (has_alpha()) {
+    return Colord(from_val(get_red_val(x, y)),
+                  from_val(get_green_val(x, y)),
+                  from_val(get_blue_val(x, y)),
+                  from_val(get_alpha_val(x, y)));
+  } else {
+    return Colord(from_val(get_red_val(x, y)),
+                  from_val(get_green_val(x, y)),
+                  from_val(get_blue_val(x, y)),
+                  0.0);
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PNMImage::set_xel_a
+//       Access: Published
+//  Description: Changes the RGBA color at the indicated pixel.  Each
+//               component is a double in the range 0..1.
+////////////////////////////////////////////////////////////////////
+INLINE void PNMImage::
+set_xel_a(int x, int y, const Colord &value) {
+  set_xel_val(x, y, to_val(value[0]), to_val(value[1]), to_val(value[2]));
+  if (has_alpha()) {
+    set_alpha_val(x, y, to_val(value[3]));
+  }
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: PNMImage::set_xel_a
+//       Access: Published
+//  Description: Changes the RGBA color at the indicated pixel.  Each
+//               component is a double in the range 0..1.
+////////////////////////////////////////////////////////////////////
+INLINE void PNMImage::
+set_xel_a(int x, int y, double r, double g, double b, double a) {
+  set_xel_val(x, y, to_val(r), to_val(g), to_val(b));
+  if (has_alpha()) {
+    set_alpha_val(x, y, to_val(a));
+  }
+}
+
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_red
 //     Function: PNMImage::get_red
-//       Access: Public
+//       Access: Published
 //  Description: Returns the red component color at the indicated
 //  Description: Returns the red component color at the indicated
 //               pixel.  The value returned is a double in the range
 //               pixel.  The value returned is a double in the range
 //               0..1.
 //               0..1.
@@ -473,7 +522,7 @@ get_red(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_green
 //     Function: PNMImage::get_green
-//       Access: Public
+//       Access: Published
 //  Description: Returns the green component color at the indicated
 //  Description: Returns the green component color at the indicated
 //               pixel.  The value returned is a double in the range
 //               pixel.  The value returned is a double in the range
 //               0..1.
 //               0..1.
@@ -485,7 +534,7 @@ get_green(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_blue
 //     Function: PNMImage::get_blue
-//       Access: Public
+//       Access: Published
 //  Description: Returns the blue component color at the indicated
 //  Description: Returns the blue component color at the indicated
 //               pixel.  The value returned is a double in the range
 //               pixel.  The value returned is a double in the range
 //               0..1.
 //               0..1.
@@ -497,7 +546,7 @@ get_blue(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_gray
 //     Function: PNMImage::get_gray
-//       Access: Public
+//       Access: Published
 //  Description: Returns the gray component color at the indicated
 //  Description: Returns the gray component color at the indicated
 //               pixel.  This only has a meaningful value for
 //               pixel.  This only has a meaningful value for
 //               grayscale images; for other image types, this returns
 //               grayscale images; for other image types, this returns
@@ -512,7 +561,7 @@ get_gray(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_alpha
 //     Function: PNMImage::get_alpha
-//       Access: Public
+//       Access: Published
 //  Description: Returns the alpha component color at the indicated
 //  Description: Returns the alpha component color at the indicated
 //               pixel.  It is an error to call this unless
 //               pixel.  It is an error to call this unless
 //               has_alpha() is true.  The value returned is a double
 //               has_alpha() is true.  The value returned is a double
@@ -525,7 +574,7 @@ get_alpha(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_red
 //     Function: PNMImage::set_red
-//       Access: Public
+//       Access: Published
 //  Description: Sets the red component color only at the indicated
 //  Description: Sets the red component color only at the indicated
 //               pixel.  The value given should be a double in the
 //               pixel.  The value given should be a double in the
 //               range 0..1.
 //               range 0..1.
@@ -537,7 +586,7 @@ set_red(int x, int y, double r) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_green
 //     Function: PNMImage::set_green
-//       Access: Public
+//       Access: Published
 //  Description: Sets the green component color only at the indicated
 //  Description: Sets the green component color only at the indicated
 //               pixel.  The value given should be a double in the
 //               pixel.  The value given should be a double in the
 //               range 0..1.
 //               range 0..1.
@@ -549,7 +598,7 @@ set_green(int x, int y, double r) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_blue
 //     Function: PNMImage::set_blue
-//       Access: Public
+//       Access: Published
 //  Description: Sets the blue component color only at the indicated
 //  Description: Sets the blue component color only at the indicated
 //               pixel.  The value given should be a double in the
 //               pixel.  The value given should be a double in the
 //               range 0..1.
 //               range 0..1.
@@ -561,7 +610,7 @@ set_blue(int x, int y, double r) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_gray
 //     Function: PNMImage::set_gray
-//       Access: Public
+//       Access: Published
 //  Description: Sets the gray component color at the indicated
 //  Description: Sets the gray component color at the indicated
 //               pixel.  This is only meaningful for grayscale images;
 //               pixel.  This is only meaningful for grayscale images;
 //               for other image types, this simply sets the blue
 //               for other image types, this simply sets the blue
@@ -578,7 +627,7 @@ set_gray(int x, int y, double r) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_alpha
 //     Function: PNMImage::set_alpha
-//       Access: Public
+//       Access: Published
 //  Description: Sets the alpha component color only at the indicated
 //  Description: Sets the alpha component color only at the indicated
 //               pixel.  It is an error to call this unless
 //               pixel.  It is an error to call this unless
 //               has_alpha() is true.  The value given should be in
 //               has_alpha() is true.  The value given should be in
@@ -591,7 +640,7 @@ set_alpha(int x, int y, double r) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_channel
 //     Function: PNMImage::get_channel
-//       Access: Public
+//       Access: Published
 //  Description: Returns the nth component color at the indicated
 //  Description: Returns the nth component color at the indicated
 //               pixel.  The channel index should be in the range
 //               pixel.  The channel index should be in the range
 //               0..(get_num_channels()-1).  The channels are ordered B,
 //               0..(get_num_channels()-1).  The channels are ordered B,
@@ -607,7 +656,7 @@ get_channel(int x, int y, int channel) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_channel_val
 //     Function: PNMImage::set_channel_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the nth component color at the indicated
 //  Description: Sets the nth component color at the indicated
 //               pixel.  The channel index should be in the range
 //               pixel.  The channel index should be in the range
 //               0..(get_num_channels()-1).  The channels are ordered B,
 //               0..(get_num_channels()-1).  The channels are ordered B,
@@ -623,7 +672,7 @@ set_channel(int x, int y, int channel, double value) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_bright
 //     Function: PNMImage::get_bright
-//       Access: Public
+//       Access: Published
 //  Description: Returns the linear brightness of the given xel, as a
 //  Description: Returns the linear brightness of the given xel, as a
 //               double in the range 0..1.  This flavor of
 //               double in the range 0..1.  This flavor of
 //               get_bright() returns the correct grayscale brightness
 //               get_bright() returns the correct grayscale brightness
@@ -636,7 +685,7 @@ get_bright(int x, int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_bright
 //     Function: PNMImage::get_bright
-//       Access: Public
+//       Access: Published
 //  Description: This flavor of get_bright() works correctly only for
 //  Description: This flavor of get_bright() works correctly only for
 //               color images.  It returns a single brightness value
 //               color images.  It returns a single brightness value
 //               for the RGB color at the indicated pixel, based on
 //               for the RGB color at the indicated pixel, based on
@@ -651,7 +700,7 @@ get_bright(int x, int y, double rc, double gc, double bc) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_bright
 //     Function: PNMImage::get_bright
-//       Access: Public
+//       Access: Published
 //  Description: This flavor of get_bright() works correctly only for
 //  Description: This flavor of get_bright() works correctly only for
 //               four-channel images.  It returns a single brightness
 //               four-channel images.  It returns a single brightness
 //               value for the RGBA color at the indicated pixel,
 //               value for the RGBA color at the indicated pixel,
@@ -667,7 +716,7 @@ get_bright(int x, int y, double rc, double gc, double bc, double ac) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::blend
 //     Function: PNMImage::blend
-//       Access: Public
+//       Access: Published
 //  Description: Smoothly blends the indicated pixel value in with
 //  Description: Smoothly blends the indicated pixel value in with
 //               whatever was already in the image, based on the given
 //               whatever was already in the image, based on the given
 //               alpha value.  An alpha of 1.0 is fully opaque and
 //               alpha value.  An alpha of 1.0 is fully opaque and
@@ -681,7 +730,7 @@ blend(int x, int y, const RGBColord &val, double alpha) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::Array Operator
 //     Function: PNMImage::Array Operator
-//       Access: Public
+//       Access: Published
 //  Description: Allows the PNMImage to appear to be a 2-d array of
 //  Description: Allows the PNMImage to appear to be a 2-d array of
 //               xels.
 //               xels.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -692,7 +741,7 @@ operator [] (int y) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::Array Operator
 //     Function: PNMImage::Array Operator
-//       Access: Public
+//       Access: Published
 //  Description: Allows the PNMImage to appear to be a 2-d array of
 //  Description: Allows the PNMImage to appear to be a 2-d array of
 //               xels.
 //               xels.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -703,7 +752,7 @@ operator [] (int y) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::box_filter
 //     Function: PNMImage::box_filter
-//       Access: Public
+//       Access: Published
 //  Description: This flavor of box_filter() will apply the filter
 //  Description: This flavor of box_filter() will apply the filter
 //               over the entire image without resizing or copying;
 //               over the entire image without resizing or copying;
 //               the effect is that of a blur operation.
 //               the effect is that of a blur operation.
@@ -715,7 +764,7 @@ box_filter(double radius) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::gaussian_filter
 //     Function: PNMImage::gaussian_filter
-//       Access: Public
+//       Access: Published
 //  Description: This flavor of gaussian_filter() will apply the filter
 //  Description: This flavor of gaussian_filter() will apply the filter
 //               over the entire image without resizing or copying;
 //               over the entire image without resizing or copying;
 //               the effect is that of a blur operation.
 //               the effect is that of a blur operation.

+ 84 - 21
panda/src/pnmimage/pnmImage.cxx

@@ -23,7 +23,7 @@
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::clear
 //     Function: PNMImage::clear
-//       Access: Public
+//       Access: Published
 //  Description: Frees all memory allocated for the image, and clears
 //  Description: Frees all memory allocated for the image, and clears
 //               all its parameters (size, color, type, etc).
 //               all its parameters (size, color, type, etc).
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -46,7 +46,7 @@ clear() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::clear
 //     Function: PNMImage::clear
-//       Access: Public
+//       Access: Published
 //  Description: This flavor of clear() reinitializes the image to an
 //  Description: This flavor of clear() reinitializes the image to an
 //               empty (black) image with the given dimensions.
 //               empty (black) image with the given dimensions.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -75,7 +75,7 @@ clear(int x_size, int y_size, int num_channels,
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::copy_from
 //     Function: PNMImage::copy_from
-//       Access: Public
+//       Access: Published
 //  Description: Makes this image become a copy of the other image.
 //  Description: Makes this image become a copy of the other image.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PNMImage::
 void PNMImage::
@@ -94,7 +94,7 @@ copy_from(const PNMImage &copy) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::copy_header_from
 //     Function: PNMImage::copy_header_from
-//       Access: Public
+//       Access: Published
 //  Description: Copies just the header information into this image.
 //  Description: Copies just the header information into this image.
 //               This will blow away any image data stored in the
 //               This will blow away any image data stored in the
 //               image.  The new image data will be allocated, but
 //               image.  The new image data will be allocated, but
@@ -115,7 +115,7 @@ copy_header_from(const PNMImageHeader &header) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::fill_val
 //     Function: PNMImage::fill_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the entire image (except the alpha channel) to
 //  Description: Sets the entire image (except the alpha channel) to
 //               the given color.
 //               the given color.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -132,7 +132,7 @@ fill_val(xelval red, xelval green, xelval blue) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::alpha_fill_val
 //     Function: PNMImage::alpha_fill_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the entire alpha channel to the given level.
 //  Description: Sets the entire alpha channel to the given level.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PNMImage::
 void PNMImage::
@@ -152,7 +152,7 @@ alpha_fill_val(xelval alpha) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::read
 //     Function: PNMImage::read
-//       Access: Public
+//       Access: Published
 //  Description: Reads the indicated image filename.  If type is
 //  Description: Reads the indicated image filename.  If type is
 //               non-NULL, it is a suggestion for the type of file it
 //               non-NULL, it is a suggestion for the type of file it
 //               is.  Returns true if successful, false on error.
 //               is.  Returns true if successful, false on error.
@@ -170,7 +170,7 @@ read(const Filename &filename, PNMFileType *type) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::read
 //     Function: PNMImage::read
-//       Access: Public
+//       Access: Published
 //  Description: Reads the image data from the indicated stream.  
 //  Description: Reads the image data from the indicated stream.  
 //
 //
 //               The filename is advisory only, and may be used
 //               The filename is advisory only, and may be used
@@ -194,7 +194,7 @@ read(istream &data, const string &filename, PNMFileType *type) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::read
 //     Function: PNMImage::read
-//       Access: Public
+//       Access: Published
 //  Description: This flavor of read() uses an already-existing
 //  Description: This flavor of read() uses an already-existing
 //               PNMReader to read the image file.  You can get a
 //               PNMReader to read the image file.  You can get a
 //               reader via the PNMImageHeader::make_reader() methods.
 //               reader via the PNMImageHeader::make_reader() methods.
@@ -236,7 +236,7 @@ read(PNMReader *reader) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::write
 //     Function: PNMImage::write
-//       Access: Public
+//       Access: Published
 //  Description: Writes the image to the indicated filename.  If type
 //  Description: Writes the image to the indicated filename.  If type
 //               is non-NULL, it is a suggestion for the type of image
 //               is non-NULL, it is a suggestion for the type of image
 //               file to write.
 //               file to write.
@@ -257,7 +257,7 @@ write(const Filename &filename, PNMFileType *type) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::write
 //     Function: PNMImage::write
-//       Access: Public
+//       Access: Published
 //  Description: Writes the image to the indicated ostream.
 //  Description: Writes the image to the indicated ostream.
 //
 //
 //               The filename is advisory only, and may be used
 //               The filename is advisory only, and may be used
@@ -283,7 +283,7 @@ write(ostream &data, const string &filename, PNMFileType *type) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::write
 //     Function: PNMImage::write
-//       Access: Public
+//       Access: Published
 //  Description: This flavor of write() uses an already-existing
 //  Description: This flavor of write() uses an already-existing
 //               PNMWriter to write the image file.  You can get a
 //               PNMWriter to write the image file.  You can get a
 //               writer via the PNMImageHeader::make_writer() methods.
 //               writer via the PNMImageHeader::make_writer() methods.
@@ -313,7 +313,7 @@ write(PNMWriter *writer) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_color_type
 //     Function: PNMImage::set_color_type
-//       Access: Public
+//       Access: Published
 //  Description: Translates the image to or from grayscale, color, or
 //  Description: Translates the image to or from grayscale, color, or
 //               four-color mode.  Grayscale images are converted to
 //               four-color mode.  Grayscale images are converted to
 //               full-color images with R, G, B set to the original
 //               full-color images with R, G, B set to the original
@@ -364,7 +364,7 @@ set_color_type(PNMImage::ColorType color_type) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::make_grayscale
 //     Function: PNMImage::make_grayscale
-//       Access: Public
+//       Access: Published
 //  Description: Converts the image from RGB to grayscale.  Any alpha
 //  Description: Converts the image from RGB to grayscale.  Any alpha
 //               channel, if present, is left undisturbed.  The
 //               channel, if present, is left undisturbed.  The
 //               optional rc, gc, bc values represent the relative
 //               optional rc, gc, bc values represent the relative
@@ -389,7 +389,7 @@ make_grayscale(double rc, double gc, double bc) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_maxval
 //     Function: PNMImage::set_maxval
-//       Access: Public
+//       Access: Published
 //  Description: Rescales the image to the indicated maxval.
 //  Description: Rescales the image to the indicated maxval.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PNMImage::
 void PNMImage::
@@ -429,7 +429,7 @@ set_maxval(xelval maxval) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::get_channel_val
 //     Function: PNMImage::get_channel_val
-//       Access: Public
+//       Access: Published
 //  Description: Returns the nth component color at the indicated
 //  Description: Returns the nth component color at the indicated
 //               pixel.  The channel index should be in the range
 //               pixel.  The channel index should be in the range
 //               0..(get_num_channels()-1).  The channels are ordered B,
 //               0..(get_num_channels()-1).  The channels are ordered B,
@@ -464,7 +464,7 @@ get_channel_val(int x, int y, int channel) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::set_channel_val
 //     Function: PNMImage::set_channel_val
-//       Access: Public
+//       Access: Published
 //  Description: Sets the nth component color at the indicated
 //  Description: Sets the nth component color at the indicated
 //               pixel.  The channel index should be in the range
 //               pixel.  The channel index should be in the range
 //               0..(get_num_channels()-1).  The channels are ordered B,
 //               0..(get_num_channels()-1).  The channels are ordered B,
@@ -503,7 +503,7 @@ set_channel_val(int x, int y, int channel, xelval value) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::blend
 //     Function: PNMImage::blend
-//       Access: Public
+//       Access: Published
 //  Description: Smoothly blends the indicated pixel value in with
 //  Description: Smoothly blends the indicated pixel value in with
 //               whatever was already in the image, based on the given
 //               whatever was already in the image, based on the given
 //               alpha value.  An alpha of 1.0 is fully opaque and
 //               alpha value.  An alpha of 1.0 is fully opaque and
@@ -546,7 +546,7 @@ blend(int x, int y, double r, double g, double b, double alpha) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::copy_sub_image
 //     Function: PNMImage::copy_sub_image
-//       Access: Public
+//       Access: Published
 //  Description: Copies a rectangular area of another image into a
 //  Description: Copies a rectangular area of another image into a
 //               rectangular area of this image.  Both images must
 //               rectangular area of this image.  Both images must
 //               already have been initialized.  The upper-left corner
 //               already have been initialized.  The upper-left corner
@@ -598,7 +598,7 @@ copy_sub_image(const PNMImage &copy, int xto, int yto,
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::blend_sub_image
 //     Function: PNMImage::blend_sub_image
-//       Access: Public
+//       Access: Published
 //  Description: Behaves like copy_sub_image(), except the alpha
 //  Description: Behaves like copy_sub_image(), except the alpha
 //               channel of the copy is used to blend the copy into
 //               channel of the copy is used to blend the copy into
 //               the destination image, instead of overwriting pixels
 //               the destination image, instead of overwriting pixels
@@ -646,10 +646,73 @@ blend_sub_image(const PNMImage &copy, int xto, int yto,
   }
   }
 }
 }
 
 
+////////////////////////////////////////////////////////////////////
+//     Function: PNMImage::render_spot
+//       Access: Published
+//  Description: Renders a solid-color circle, with a fuzzy edge, into
+//               the center of the PNMImage.  If the PNMImage is
+//               non-square, this actually renders an ellipse.
+//
+//               The min_radius and max_radius are in the scale 0..1,
+//               where 1.0 means the full width of the image.  If
+//               min_radius == max_radius, there is no fuzzy edge;
+//               otherwise, the pixels between min_radius and
+//               max_radius are smoothly blended between fg and bg
+//               colors.
+////////////////////////////////////////////////////////////////////
+void PNMImage::
+render_spot(const Colord &fg, const Colord &bg,
+            double min_radius, double max_radius) {
+  double x_scale = 2.0 / _x_size;
+  double y_scale = 2.0 / _y_size;
+
+  // If the width is even, x_center1 == x_center0.  If the width is
+  // odd, x_center1 == x_center0 + 1.
+  int x_center0 = _x_size / 2;
+  int y_center0 = _y_size / 2;
+  int x_center1 = (_x_size + 1) / 2;
+  int y_center1 = (_y_size + 1) / 2;
+
+  double min_r2 = min_radius * min_radius;
+  double max_r2 = max_radius * max_radius;
+
+  for (int yi = 0; yi < y_center1; ++yi) {
+    double y = yi * y_scale;
+    for (int xi = 0; xi < x_center1; ++xi) {
+      double x = xi * x_scale;
+      double d2 = (x * x + y * y);
+      if (d2 <= min_r2) {
+        set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, fg);
+        set_xel_a(x_center0 + xi, y_center1 - 1 - yi, fg);
+        set_xel_a(x_center1 - 1 - xi, y_center0 + yi, fg);
+        set_xel_a(x_center0 + xi, y_center0 + yi, fg);
+
+      } else if (d2 >= max_r2) {
+        set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, bg);
+        set_xel_a(x_center0 + xi, y_center1 - 1 - yi, bg);
+        set_xel_a(x_center1 - 1 - xi, y_center0 + yi, bg);
+        set_xel_a(x_center0 + xi, y_center0 + yi, bg);
+
+      } else {
+        double d = sqrt(d2);
+        d = (d - min_radius) / (max_radius - min_radius);
+        d2 = d * d;
+        double t = (3.0 * d2) - (2.0 * d * d2);
+        Colord c = fg + t * (bg - fg);
+
+        set_xel_a(x_center1 - 1 - xi, y_center1 - 1 - yi, c);
+        set_xel_a(x_center0 + xi, y_center1 - 1 - yi, c);
+        set_xel_a(x_center1 - 1 - xi, y_center0 + yi, c);
+        set_xel_a(x_center0 + xi, y_center0 + yi, c);
+      }
+    }
+  }
+}
+
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImage::setup_rc
 //     Function: PNMImage::setup_rc
-//       Access: Public
+//       Access: Published
 //  Description: Sets the _default_rc,bc,gc values appropriately
 //  Description: Sets the _default_rc,bc,gc values appropriately
 //               according to the color type of the image, so that
 //               according to the color type of the image, so that
 //               get_bright() will return a meaningful value for both
 //               get_bright() will return a meaningful value for both

+ 7 - 0
panda/src/pnmimage/pnmImage.h

@@ -144,6 +144,10 @@ PUBLISHED:
   INLINE void set_xel(int x, int y, double r, double g, double b);
   INLINE void set_xel(int x, int y, double r, double g, double b);
   INLINE void set_xel(int x, int y, double gray);
   INLINE void set_xel(int x, int y, double gray);
 
 
+  INLINE Colord get_xel_a(int x, int y) const;
+  INLINE void set_xel_a(int x, int y, const Colord &value);
+  INLINE void set_xel_a(int x, int y, double r, double g, double b, double a);
+
   INLINE double get_red(int x, int y) const;
   INLINE double get_red(int x, int y) const;
   INLINE double get_green(int x, int y) const;
   INLINE double get_green(int x, int y) const;
   INLINE double get_blue(int x, int y) const;
   INLINE double get_blue(int x, int y) const;
@@ -183,6 +187,9 @@ PUBLISHED:
                        int xfrom = 0, int yfrom = 0,
                        int xfrom = 0, int yfrom = 0,
                        int x_size = -1, int y_size = -1);
                        int x_size = -1, int y_size = -1);
 
 
+  void render_spot(const Colord &fg, const Colord &bg,
+                   double min_radius, double max_radius);
+
   // The bodies for the non-inline *_filter() functions can be found
   // The bodies for the non-inline *_filter() functions can be found
   // in the file pnm-image-filter.cxx.
   // in the file pnm-image-filter.cxx.
 
 

+ 16 - 16
panda/src/pnmimage/pnmImageHeader.I

@@ -18,7 +18,7 @@
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::Constructor
 //     Function: PNMImageHeader::Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::
 INLINE PNMImageHeader::
@@ -32,7 +32,7 @@ PNMImageHeader() {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::Copy Constructor
 //     Function: PNMImageHeader::Copy Constructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::
 INLINE PNMImageHeader::
@@ -47,7 +47,7 @@ PNMImageHeader(const PNMImageHeader &copy) :
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::Copy Assignment Operator
 //     Function: PNMImageHeader::Copy Assignment Operator
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE void PNMImageHeader::
 INLINE void PNMImageHeader::
@@ -61,7 +61,7 @@ operator = (const PNMImageHeader &copy) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::Destructor
 //     Function: PNMImageHeader::Destructor
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE PNMImageHeader::
 INLINE PNMImageHeader::
@@ -70,7 +70,7 @@ INLINE PNMImageHeader::
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::get_color_type
 //     Function: PNMImageHeader::get_color_type
-//       Access: Public
+//       Access: Published
 //  Description: Returns the image type of the image, as an enumerated
 //  Description: Returns the image type of the image, as an enumerated
 //               value.  This is really just the number of channels
 //               value.  This is really just the number of channels
 //               cast to the enumerated type.
 //               cast to the enumerated type.
@@ -83,7 +83,7 @@ get_color_type() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::get_num_channels
 //     Function: PNMImageHeader::get_num_channels
-//       Access: Public
+//       Access: Published
 //  Description: Returns the number of channels in the image.
 //  Description: Returns the number of channels in the image.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 INLINE int PNMImageHeader::
 INLINE int PNMImageHeader::
@@ -94,7 +94,7 @@ get_num_channels() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::is_grayscale
 //     Function: PNMImageHeader::is_grayscale
-//       Access: Public, Static
+//       Access: Published, Static
 //  Description: This static variant of is_grayscale() returns true if
 //  Description: This static variant of is_grayscale() returns true if
 //               the indicated image type represents a grayscale
 //               the indicated image type represents a grayscale
 //               image, false otherwise.
 //               image, false otherwise.
@@ -106,7 +106,7 @@ is_grayscale(PNMImageHeader::ColorType color_type) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::is_grayscale
 //     Function: PNMImageHeader::is_grayscale
-//       Access: Public
+//       Access: Published
 //  Description: Returns false if the image is a full-color image, and
 //  Description: Returns false if the image is a full-color image, and
 //               has red, green, and blue components; true if it is a
 //               has red, green, and blue components; true if it is a
 //               grayscale image and has only a gray component.  (The
 //               grayscale image and has only a gray component.  (The
@@ -120,7 +120,7 @@ is_grayscale() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::has_alpha
 //     Function: PNMImageHeader::has_alpha
-//       Access: Public, Static
+//       Access: Published, Static
 //  Description: This static variant of has_alpha() returns true if
 //  Description: This static variant of has_alpha() returns true if
 //               the indicated image type includes an alpha channel,
 //               the indicated image type includes an alpha channel,
 //               false otherwise.
 //               false otherwise.
@@ -132,7 +132,7 @@ has_alpha(PNMImageHeader::ColorType color_type) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::has_alpha
 //     Function: PNMImageHeader::has_alpha
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the image includes an alpha channel,
 //  Description: Returns true if the image includes an alpha channel,
 //               false otherwise.  Unlike is_grayscale(), if this
 //               false otherwise.  Unlike is_grayscale(), if this
 //               returns false it is an error to call any of the
 //               returns false it is an error to call any of the
@@ -145,7 +145,7 @@ has_alpha() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::get_maxval
 //     Function: PNMImageHeader::get_maxval
-//       Access: Public
+//       Access: Published
 //  Description: Returns the maximum channel value allowable for any
 //  Description: Returns the maximum channel value allowable for any
 //               pixel in this image; for instance, 255 for a typical
 //               pixel in this image; for instance, 255 for a typical
 //               8-bit-per-channel image.  A pixel with this value is
 //               8-bit-per-channel image.  A pixel with this value is
@@ -158,7 +158,7 @@ get_maxval() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::get_x_size
 //     Function: PNMImageHeader::get_x_size
-//       Access: Public
+//       Access: Published
 //  Description: Returns the number of pixels in the X direction.
 //  Description: Returns the number of pixels in the X direction.
 //               This is one more than the largest allowable X
 //               This is one more than the largest allowable X
 //               coordinate.
 //               coordinate.
@@ -170,7 +170,7 @@ get_x_size() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::get_y_size
 //     Function: PNMImageHeader::get_y_size
-//       Access: Public
+//       Access: Published
 //  Description: Returns the number of pixels in the Y direction.
 //  Description: Returns the number of pixels in the Y direction.
 //               This is one more than the largest allowable Y
 //               This is one more than the largest allowable Y
 //               coordinate.
 //               coordinate.
@@ -182,7 +182,7 @@ get_y_size() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::has_type
 //     Function: PNMImageHeader::has_type
-//       Access: Public
+//       Access: Published
 //  Description: Returns true if the PNMImageHeader knows what type it
 //  Description: Returns true if the PNMImageHeader knows what type it
 //               is, false otherwise.
 //               is, false otherwise.
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
@@ -193,7 +193,7 @@ has_type() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::get_type
 //     Function: PNMImageHeader::get_type
-//       Access: Public
+//       Access: Published
 //  Description: If the file type is known (e.g. has_type() returns
 //  Description: If the file type is known (e.g. has_type() returns
 //               true), returns its PNMFileType pointer; otherwise,
 //               true), returns its PNMFileType pointer; otherwise,
 //               returns NULL.
 //               returns NULL.
@@ -205,7 +205,7 @@ get_type() const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::set_type
 //     Function: PNMImageHeader::set_type
-//       Access: Public
+//       Access: Published
 //  Description: Sets the file type of this PNMImage.  This will be
 //  Description: Sets the file type of this PNMImage.  This will be
 //               the default type used when an image is read, if the
 //               the default type used when an image is read, if the
 //               type cannot be determined by magic number or inferred
 //               type cannot be determined by magic number or inferred

+ 7 - 7
panda/src/pnmimage/pnmImageHeader.cxx

@@ -25,7 +25,7 @@
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::read_header
 //     Function: PNMImageHeader::read_header
-//       Access: Public
+//       Access: Published
 //  Description: Opens up the image file and tries to read its header
 //  Description: Opens up the image file and tries to read its header
 //               information to determine its size, number of
 //               information to determine its size, number of
 //               channels, etc.  If successful, updates the header
 //               channels, etc.  If successful, updates the header
@@ -46,7 +46,7 @@ read_header(const Filename &filename, PNMFileType *type) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::make_reader
 //     Function: PNMImageHeader::make_reader
-//       Access: Public
+//       Access: Published
 //  Description: Returns a newly-allocated PNMReader of the suitable
 //  Description: Returns a newly-allocated PNMReader of the suitable
 //               type for reading from the indicated image filename,
 //               type for reading from the indicated image filename,
 //               or NULL if the filename cannot be read for some
 //               or NULL if the filename cannot be read for some
@@ -94,7 +94,7 @@ make_reader(const Filename &filename, PNMFileType *type) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::make_reader
 //     Function: PNMImageHeader::make_reader
-//       Access: Public
+//       Access: Published
 //  Description: Returns a newly-allocated PNMReader of the suitable
 //  Description: Returns a newly-allocated PNMReader of the suitable
 //               type for reading from the already-opened image file,
 //               type for reading from the already-opened image file,
 //               or NULL if the file cannot be read for some reason.
 //               or NULL if the file cannot be read for some reason.
@@ -224,7 +224,7 @@ make_reader(istream *file, bool owns_file, const Filename &filename,
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::make_writer
 //     Function: PNMImageHeader::make_writer
-//       Access: Public
+//       Access: Published
 //  Description: Returns a newly-allocated PNMWriter of the suitable
 //  Description: Returns a newly-allocated PNMWriter of the suitable
 //               type for writing an image to the indicated filename,
 //               type for writing an image to the indicated filename,
 //               or NULL if the filename cannot be written for some
 //               or NULL if the filename cannot be written for some
@@ -278,7 +278,7 @@ make_writer(const Filename &filename, PNMFileType *type) const {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::make_writer
 //     Function: PNMImageHeader::make_writer
-//       Access: Public
+//       Access: Published
 //  Description: Returns a newly-allocated PNMWriter of the suitable
 //  Description: Returns a newly-allocated PNMWriter of the suitable
 //               type for writing to the already-opened image file, or
 //               type for writing to the already-opened image file, or
 //               NULL if the file cannot be written for some reason.
 //               NULL if the file cannot be written for some reason.
@@ -357,7 +357,7 @@ make_writer(ostream *file, bool owns_file, const Filename &filename,
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::read_magic_number
 //     Function: PNMImageHeader::read_magic_number
-//       Access: Public, Static
+//       Access: Published, Static
 //  Description: Ensures that the first n bytes of the file are read
 //  Description: Ensures that the first n bytes of the file are read
 //               into magic_number.  If magic_number is initially
 //               into magic_number.  If magic_number is initially
 //               nonempty, assumes these represent the first few bytes
 //               nonempty, assumes these represent the first few bytes
@@ -380,7 +380,7 @@ read_magic_number(istream *file, string &magic_number, int num_bytes) {
 
 
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 //     Function: PNMImageHeader::output
 //     Function: PNMImageHeader::output
-//       Access: Public
+//       Access: Published
 //  Description:
 //  Description:
 ////////////////////////////////////////////////////////////////////
 ////////////////////////////////////////////////////////////////////
 void PNMImageHeader::
 void PNMImageHeader::

+ 7 - 1
panda/src/wgldisplay/wglGraphicsStateGuardian.cxx

@@ -86,7 +86,13 @@ framebuffer_bind_to_texture(GraphicsOutput *win, Texture *tex) {
 
 
   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   TextureContext *tc = tex->prepare_now(get_prepared_objects(), this);
   nassertr(tc != (TextureContext *)NULL, false);
   nassertr(tc != (TextureContext *)NULL, false);
-  bind_texture(tc);
+  CLP(TextureContext) *gtc = DCAST(CLP(TextureContext), tc);
+  GLenum target = get_texture_target(tex->get_texture_type());
+  if (target == GL_NONE) {
+    // Invalid texture, can't bind it.
+    return false;
+  }
+  GLP(BindTexture)(target, gtc->_index);
 
 
   if (get_properties().is_single_buffered()) {
   if (get_properties().is_single_buffered()) {
     _wglBindTexImageARB(buffer->_pbuffer, WGL_FRONT_LEFT_ARB);
     _wglBindTexImageARB(buffer->_pbuffer, WGL_FRONT_LEFT_ARB);