Browse Source

fix dx resize crash some more; first pass at dx cube map support

David Rose 20 years ago
parent
commit
af49897d5e

+ 32 - 0
panda/src/display/graphicsStateGuardian.I

@@ -273,6 +273,27 @@ get_supports_texture_dot3() const {
   return _supports_texture_dot3;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_supports_3d_texture
+//       Access: Published
+//  Description: Returns true if this GSG can render 3-d (volumetric)
+//               textures.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+get_supports_3d_texture() const {
+  return _supports_3d_texture;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_supports_cube_map
+//       Access: Published
+//  Description: Returns true if this GSG can render cube map textures.
+////////////////////////////////////////////////////////////////////
+INLINE bool GraphicsStateGuardian::
+get_supports_cube_map() const {
+  return _supports_cube_map;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_max_lights
 //       Access: Published
@@ -690,6 +711,17 @@ get_cs_transform() const {
   return _cs_transform;
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: GraphicsStateGuardian::get_inv_cs_transform
+//       Access: Public
+//  Description: Returns the inverse of the transform returned by
+//               get_cs_transform().
+////////////////////////////////////////////////////////////////////
+INLINE const TransformState *GraphicsStateGuardian::
+get_inv_cs_transform() const {
+  return _inv_cs_transform;
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: GraphicsStateGuardian::get_light
 //       Access: Protected

+ 8 - 0
panda/src/display/graphicsStateGuardian.cxx

@@ -126,6 +126,9 @@ GraphicsStateGuardian(const FrameBufferProperties &properties,
   _supports_texture_saved_result = false;
   _supports_texture_dot3 = false;
 
+  _supports_3d_texture = false;
+  _supports_cube_map = false;
+
   // Assume no limits on number of lights or clip planes.
   _max_lights = -1;
   _max_clip_planes = -1;
@@ -946,12 +949,17 @@ set_coordinate_system(CoordinateSystem cs) {
   if (_internal_coordinate_system == CS_default ||
       _internal_coordinate_system == _coordinate_system) {
     _cs_transform = TransformState::make_identity();
+    _inv_cs_transform = TransformState::make_identity();
 
   } else {
     _cs_transform = 
       TransformState::make_mat
       (LMatrix4f::convert_mat(_coordinate_system,
                               _internal_coordinate_system));
+    _inv_cs_transform = 
+      TransformState::make_mat
+      (LMatrix4f::convert_mat(_internal_coordinate_system,
+                              _coordinate_system));
   }
   _internal_transform = _cs_transform->compose(_external_transform);
 }

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

@@ -98,6 +98,9 @@ PUBLISHED:
   INLINE bool get_supports_texture_saved_result() const;
   INLINE bool get_supports_texture_dot3() const;
 
+  INLINE bool get_supports_3d_texture() const;
+  INLINE bool get_supports_cube_map() const;
+
   INLINE int get_max_lights() const;
   INLINE int get_max_clip_planes() const;
 
@@ -205,6 +208,7 @@ public:
   virtual CoordinateSystem get_internal_coordinate_system() const;
 
   INLINE const TransformState *get_cs_transform() const;
+  INLINE const TransformState *get_inv_cs_transform() const;
 
   virtual void issue_transform(const TransformState *transform);
   virtual void issue_color_scale(const ColorScaleAttrib *attrib);
@@ -317,6 +321,7 @@ protected:
   CoordinateSystem _coordinate_system;
   CoordinateSystem _internal_coordinate_system;
   CPT(TransformState) _cs_transform;
+  CPT(TransformState) _inv_cs_transform;
 
   Colorf _scene_graph_color;
   bool _has_scene_graph_color;
@@ -370,6 +375,9 @@ protected:
   bool _supports_texture_saved_result;
   bool _supports_texture_dot3;
 
+  bool _supports_3d_texture;
+  bool _supports_cube_map;
+
   int _max_lights;
   int _max_clip_planes;
 

+ 0 - 1
panda/src/doc/eggSyntax.txt

@@ -295,7 +295,6 @@ appear before they are referenced.
       WORLD_NORMAL
       EYE_NORMAL
       WORLD_POSITION
-      OBJECT_POSITION
       EYE_POSITION
       POINT_SPRITE
 

+ 1 - 1
panda/src/dxgsg8/dxGeomMunger8.cxx

@@ -116,7 +116,7 @@ munge_format_impl(const GeomVertexFormat *orig,
     int num_stages = _texture->get_num_on_stages();
     for (int i = 0; i < num_stages; ++i) {
       TextureStage *stage = _texture->get_on_stage(i);
-      
+
       const InternalName *name = stage->get_texcoord_name();
       if (used_stages.insert(name).second) {
         // This is the first time we've encountered this texcoord name.

+ 97 - 31
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -146,7 +146,7 @@ DXGraphicsStateGuardian8::
 TextureContext *DXGraphicsStateGuardian8::
 prepare_texture(Texture *tex) {
   DXTextureContext8 *dtc = new DXTextureContext8(tex);
-  if (dtc->create_texture(*_screen) == (IDirect3DTexture8 *)NULL) {
+  if (!dtc->create_texture(*_screen)) {
     delete dtc;
     return NULL;
   }
@@ -191,7 +191,7 @@ apply_texture(int i, TextureContext *tc) {
           << "Texture " << *dtc->_texture << " has changed mipmap state.\n";
       }
 
-      if (dtc->create_texture(*_screen) == (IDirect3DTexture8 *)NULL) {
+      if (!dtc->create_texture(*_screen)) {
         // Oops, we can't re-create the texture for some reason.
         dxgsg8_cat.error()
           << "Unable to re-create texture " << *dtc->_texture << endl;
@@ -1320,8 +1320,11 @@ framebuffer_copy_to_texture(Texture *tex, int z, const DisplayRegion *dr, const
   }
   DXTextureContext8 *dtc = DCAST(DXTextureContext8, tc);
 
+  nassertv(tex->get_texture_type() == Texture::TT_2d_texture);
+  nassertv(dtc->get_d3d_2d_texture() != NULL);
+
   IDirect3DSurface8 *tex_level_0, *render_target;
-  hr = dtc->get_d3d_texture()->GetSurfaceLevel(0, &tex_level_0);
+  hr = dtc->get_d3d_2d_texture()->GetSurfaceLevel(0, &tex_level_0);
   if (FAILED(hr)) {
     dxgsg8_cat.error() << "GetSurfaceLev failed in copy_texture" << D3DERRORSTRING(hr);
     return;
@@ -1519,6 +1522,9 @@ reset() {
   _supports_texture_saved_result = ((d3d_caps.PrimitiveMiscCaps & D3DPMISCCAPS_TSSARGTEMP) != 0);
   _supports_texture_dot3 = true;
 
+  _supports_3d_texture = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) != 0);
+  _supports_cube_map = ((d3d_caps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) != 0);
+
   ZeroMemory(&_lmodel_ambient, sizeof(Colorf));
   _d3d_device->SetRenderState(D3DRS_AMBIENT, 0x0);
 
@@ -2225,26 +2231,22 @@ do_issue_texture() {
     apply_texture(i, tc);
     set_texture_blend_mode(i, stage);
 
-    bool has_tex_mat = false;
-    LMatrix4f tex_mat;
-    
+    bool texcoords_3d = false;
+
+    CPT(TransformState) tex_mat = TransformState::make_identity();
     if (_current_tex_mat->has_stage(stage)) {
-      // We have to reorder the elements of the matrix for some reason.
-      const LMatrix4f &m = _current_tex_mat->get_mat(stage);
-      tex_mat.set(m(0, 0), m(0, 1), m(0, 3), 0.0f,
-                  m(1, 0), m(1, 1), m(1, 3), 0.0f,
-                  m(3, 0), m(3, 1), m(3, 3), 0.0f,
-                  0.0f, 0.0f, 0.0f, 1.0f);
-      has_tex_mat = true;
+      tex_mat = _current_tex_mat->get_transform(stage);
     }
     
     // Issue the texgen mode.
     TexGenAttrib::Mode mode = _current_tex_gen->get_mode(stage);
     bool any_point_sprite = false;
+
     switch (mode) {
     case TexGenAttrib::M_off:
     case TexGenAttrib::M_light_vector:
       _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, texcoord_index);
+      texcoords_3d = false;
       break;
       
     case TexGenAttrib::M_eye_sphere_map:
@@ -2254,20 +2256,75 @@ do_issue_texture() {
         // This texture matrix, applied on top of the texcoord
         // computed by D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR,
         // approximates the effect produced by OpenGL's GL_SPHERE_MAP.
-        static const LMatrix4f sphere_map
-          (0.33f, 0.0f, 0.0f, 0.0f,
-           0.0f, 0.33f, 0.0f, 0.0f,
-           0.0f, 0.0f, 1.0f, 0.0f,
-           0.5f, 0.5f, 0.0f, 1.0f);
-
-        if (has_tex_mat) {
-          tex_mat = sphere_map * tex_mat;
-        } else {
-          tex_mat = sphere_map;
-          has_tex_mat = true;
-        }
+        static CPT(TransformState) sphere_map =
+          TransformState::make_mat(LMatrix4f(0.33f, 0.0f, 0.0f, 0.0f,
+                                             0.0f, 0.33f, 0.0f, 0.0f,
+                                             0.0f, 0.0f, 1.0f, 0.0f,
+                                             0.5f, 0.5f, 0.0f, 1.0f));
+        tex_mat = tex_mat->compose(sphere_map);
+        texcoords_3d = true;
+      }
+      break;
+
+    case TexGenAttrib::M_world_cube_map:
+      // To achieve world reflection vector, we must transform camera
+      // coordinates to world coordinates; i.e. apply the camera
+      // transform.  In the case of a vector, we should not apply the
+      // pos component of the transform.
+      {
+        _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, 
+                                          texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
+        texcoords_3d = true;
+        CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
+        tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3f::zero()));
+      }
+      break;
+
+    case TexGenAttrib::M_eye_cube_map:
+      _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, 
+                                        texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
+      texcoords_3d = true;
+      break;
+
+    case TexGenAttrib::M_world_normal:
+      // To achieve world normal, we must transform camera coordinates
+      // to world coordinates; i.e. apply the camera transform.  In
+      // the case of a normal, we should not apply the pos component
+      // of the transform.
+      {
+        _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, 
+                                          texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
+        texcoords_3d = true;
+        CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
+        tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3f::zero()));
+      }
+      break;
+
+    case TexGenAttrib::M_eye_normal:
+      _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, 
+                                        texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
+      texcoords_3d = true;
+      break;
+
+    case TexGenAttrib::M_world_position:
+      // To achieve world position, we must transform camera
+      // coordinates to world coordinates; i.e. apply the
+      // inverse root_transform.
+      {
+        _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, 
+                                          texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
+        texcoords_3d = true;
+        CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
+        tex_mat = tex_mat->compose(camera_transform);
       }
       break;
+
+    case TexGenAttrib::M_eye_position:
+      _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, 
+                                        texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
+      texcoords_3d = true;
+      tex_mat = tex_mat->compose(_inv_cs_transform);
+      break;
       
     case TexGenAttrib::M_point_sprite:
       _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, texcoord_index);
@@ -2277,8 +2334,17 @@ do_issue_texture() {
     
     _d3d_device->SetRenderState(D3DRS_POINTSPRITEENABLE, any_point_sprite);
 
-    if (has_tex_mat) {
-      _d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)tex_mat.get_data());
+    if (!tex_mat->is_identity()) {
+      LMatrix4f m = tex_mat->get_mat();
+      if (!texcoords_3d) {
+        // For 2-d texture coordinates, we have to reorder the matrix.
+        m.set(m(0, 0), m(0, 1), m(0, 3), 0.0f,
+              m(1, 0), m(1, 1), m(1, 3), 0.0f,
+              m(3, 0), m(3, 1), m(3, 3), 0.0f,
+              0.0f, 0.0f, 0.0f, 1.0f);
+      }
+
+      _d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)m.get_data());
       _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS,
                                         D3DTTFF_COUNT2);
     } else {
@@ -2964,10 +3030,10 @@ reset_d3d_device(D3DPRESENT_PARAMETERS *presentation_params,
   assert(IS_VALID_PTR(_screen->_d3d8));
   assert(IS_VALID_PTR(_d3d_device));
 
-  // It is not clear whether we need to call this or not.  Calling
-  // this forces all of the textures and vbuffers to be regenerated,
-  // but it doesn't appear to be necessary.
-  //release_all();
+  // Calling this forces all of the textures and vbuffers to be
+  // regenerated.  It appears to be necessary on some cards but not
+  // on others.
+  release_all();
 
   // for windowed mode make sure our format matches the desktop fmt,
   // in case the desktop mode has been changed

+ 35 - 2
panda/src/dxgsg8/dxTextureContext8.I

@@ -32,9 +32,42 @@ has_mipmaps() const {
 //     Function: DXTextureContext8::get_d3d_texture
 //       Access: Public
 //  Description: Returns the Direct3D object that represents the
-//               texture.
+//               texture, whatever kind of texture it is.
 ////////////////////////////////////////////////////////////////////
-INLINE IDirect3DTexture8 *DXTextureContext8::
+INLINE IDirect3DBaseTexture8 *DXTextureContext8::
 get_d3d_texture() const {
   return _d3d_texture;
 }
+
+////////////////////////////////////////////////////////////////////
+//     Function: DXTextureContext8::get_d3d_2d_texture
+//       Access: Public
+//  Description: Returns the Direct3D object that represents the
+//               texture, in the case of a 1-d or 2-d texture.
+////////////////////////////////////////////////////////////////////
+INLINE IDirect3DTexture8 *DXTextureContext8::
+get_d3d_2d_texture() const {
+  return _d3d_2d_texture;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DXTextureContext8::get_d3d_volume_texture
+//       Access: Public
+//  Description: Returns the Direct3D object that represents the
+//               texture, in the case of a 3-d texture.
+////////////////////////////////////////////////////////////////////
+INLINE IDirect3DVolumeTexture8 *DXTextureContext8::
+get_d3d_volume_texture() const {
+  return _d3d_volume_texture;
+}
+
+////////////////////////////////////////////////////////////////////
+//     Function: DXTextureContext8::get_d3d_cube_texture
+//       Access: Public
+//  Description: Returns the Direct3D object that represents the
+//               texture, in the case of a cube map texture.
+////////////////////////////////////////////////////////////////////
+INLINE IDirect3DCubeTexture8 *DXTextureContext8::
+get_d3d_cube_texture() const {
+  return _d3d_cube_texture;
+}

+ 435 - 124
panda/src/dxgsg8/dxTextureContext8.cxx

@@ -43,8 +43,10 @@ DXTextureContext8(Texture *tex) :
   }
 
   _d3d_texture = NULL;
+  _d3d_2d_texture = NULL;
+  _d3d_volume_texture = NULL;
+  _d3d_cube_texture = NULL;
   _has_mipmaps = false;
-  _tex = tex;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -56,11 +58,10 @@ DXTextureContext8::
 ~DXTextureContext8() {
   if (dxgsg8_cat.is_spam()) {
     dxgsg8_cat.spam()
-      << "Deleting texture context for " << _tex->get_name() << "\n";
+      << "Deleting texture context for " << _texture->get_name() << "\n";
   }
   delete_texture();
   TextureContext::~TextureContext();
-  _tex = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -70,16 +71,17 @@ DXTextureContext8::
 //               for the specified device.  This code gets the
 //               attributes of the texture from the bitmap, creates
 //               the texture, and then copies the bitmap into the
-//               texture.
+//               texture.  The return value is true if the texture is
+//               successfully created, false otherwise.
 ////////////////////////////////////////////////////////////////////
-IDirect3DTexture8 *DXTextureContext8::
+bool DXTextureContext8::
 create_texture(DXScreenData &scrn) {
   HRESULT hr;
   int num_alpha_bits;     //  number of alpha bits in texture pixfmt
   D3DFORMAT target_pixel_format = D3DFMT_UNKNOWN;
   bool needs_luminance = false;
 
-  nassertr(IS_VALID_PTR(_texture), NULL);
+  nassertr(IS_VALID_PTR(_texture), false);
 
   delete_texture();
 
@@ -93,6 +95,7 @@ create_texture(DXScreenData &scrn) {
 
   DWORD orig_width = (DWORD)_texture->get_x_size();
   DWORD orig_height = (DWORD)_texture->get_y_size();
+  DWORD orig_depth = (DWORD)_texture->get_z_size();
 
   if ((_texture->get_format() == Texture::F_luminance_alpha)||
       (_texture->get_format() == Texture::F_luminance_alphamask) ||
@@ -103,7 +106,7 @@ create_texture(DXScreenData &scrn) {
   if (num_alpha_bits > 0) {
     if (num_color_channels == 3) {
       dxgsg8_cat.error()
-        << "texture " << _tex->get_name() 
+        << "texture " << _texture->get_name() 
         << " has no inherent alpha channel, but alpha format is requested!\n";
     }
   }
@@ -121,7 +124,7 @@ create_texture(DXScreenData &scrn) {
     }
     break;
   case 2:
-    assert(needs_luminance && (num_alpha_bits > 0));
+    nassertr(needs_luminance && (num_alpha_bits > 0), false);
     _d3d_format = D3DFMT_A8L8;
     break;
   case 3:
@@ -133,43 +136,120 @@ create_texture(DXScreenData &scrn) {
   }
 
   // make sure we handled all the possible cases
-  assert(_d3d_format != D3DFMT_UNKNOWN);
+  nassertr(_d3d_format != D3DFMT_UNKNOWN, false);
 
   DWORD target_width = orig_width;
   DWORD target_height = orig_height;
+  DWORD target_depth = orig_depth;
 
-  if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_POW2) {
-    if (!ISPOW2(target_width)) {
-      target_width = down_to_power_2(target_width);
+  DWORD filter_caps;
+
+  switch (_texture->get_texture_type()) {
+  case Texture::TT_1d_texture:
+  case Texture::TT_2d_texture:
+    filter_caps = scrn._d3dcaps.TextureFilterCaps;
+
+    if (target_width > scrn._d3dcaps.MaxTextureWidth) {
+      target_width = scrn._d3dcaps.MaxTextureWidth;
     }
-    if (!ISPOW2(target_height)) {
-      target_height = down_to_power_2(target_height);
+    if (target_height > scrn._d3dcaps.MaxTextureHeight) {
+      target_height = scrn._d3dcaps.MaxTextureHeight;
     }
-  }
 
-  if (target_width > scrn._d3dcaps.MaxTextureWidth) {
-    target_width = scrn._d3dcaps.MaxTextureWidth;
-  }
-  if (target_height > scrn._d3dcaps.MaxTextureHeight) {
-    target_height = scrn._d3dcaps.MaxTextureHeight;
+    if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_POW2) {
+      if (!ISPOW2(target_width)) {
+        target_width = down_to_power_2(target_width);
+      }
+      if (!ISPOW2(target_height)) {
+        target_height = down_to_power_2(target_height);
+      }
+    }
+    break;
+
+  case Texture::TT_3d_texture:
+    if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP) == 0) {
+      dxgsg8_cat.warning()
+        << "3-d textures are not supported by this graphics driver.\n";
+      return false;
+    }
+
+    filter_caps = scrn._d3dcaps.VolumeTextureFilterCaps;
+
+    if (target_width > scrn._d3dcaps.MaxVolumeExtent) {
+      target_width = scrn._d3dcaps.MaxVolumeExtent;
+    }
+    if (target_height > scrn._d3dcaps.MaxVolumeExtent) {
+      target_height = scrn._d3dcaps.MaxVolumeExtent;
+    }
+    if (target_depth > scrn._d3dcaps.MaxVolumeExtent) {
+      target_depth = scrn._d3dcaps.MaxVolumeExtent;
+    }
+
+    if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_VOLUMEMAP_POW2) {
+      if (!ISPOW2(target_width)) {
+        target_width = down_to_power_2(target_width);
+      }
+      if (!ISPOW2(target_height)) {
+        target_height = down_to_power_2(target_height);
+      }
+      if (!ISPOW2(target_depth)) {
+        target_depth = down_to_power_2(target_depth);
+      }
+    }
+    break;
+
+  case Texture::TT_cube_map:
+    if ((scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP) == 0) {
+      dxgsg8_cat.warning()
+        << "Cube map textures are not supported by this graphics driver.\n";
+      return false;
+    }
+
+    filter_caps = scrn._d3dcaps.CubeTextureFilterCaps;
+
+    if (target_width > scrn._d3dcaps.MaxTextureWidth) {
+      target_width = scrn._d3dcaps.MaxTextureWidth;
+    }
+
+    if (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_CUBEMAP_POW2) {
+      if (!ISPOW2(target_width)) {
+        target_width = down_to_power_2(target_width);
+      }
+    }
+
+    target_height = target_width;
+    break;
   }
 
   // checks for SQUARE reqmt (nvidia riva128 needs this)
-  if ((target_width != target_height) && (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY)) {
-    // assume pow2 textures.   sum exponents, divide by 2 rounding down to get sq size
+  if ((target_width != target_height) && 
+      (scrn._d3dcaps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) != 0) {
+    // assume pow2 textures.  sum exponents, divide by 2 rounding down
+    // to get sq size
     int i, width_exp, height_exp;
-    for (i = target_width, width_exp = 0; i > 1; width_exp++, i >>= 1);
-    for (i = target_height, height_exp = 0; i > 1; height_exp++, i >>= 1);
+    for (i = target_width, width_exp = 0; i > 1; width_exp++, i >>= 1) {
+    }
+    for (i = target_height, height_exp = 0; i > 1; height_exp++, i >>= 1) {
+    }
     target_height = target_width = 1<<((width_exp+height_exp)>>1);
   }
 
   bool shrink_original = false;
 
-  if (orig_width != target_width || orig_height != target_height) {
-    dxgsg8_cat.info()
-      << "Reducing size of " << _tex->get_name()
-      << " from " << orig_width << "x" << orig_height
-      << " to " << target_width << "x" << target_height << "\n";
+  if (orig_width != target_width || orig_height != target_height ||
+      orig_depth != target_depth) {
+    if (_texture->get_texture_type() == Texture::TT_3d_texture) {
+      dxgsg8_cat.info()
+        << "Reducing size of " << _texture->get_name()
+        << " from " << orig_width << "x" << orig_height << "x" << orig_depth
+        << " to " << target_width << "x" << target_height
+        << "x" << target_depth << "\n";
+    } else {
+      dxgsg8_cat.info()
+        << "Reducing size of " << _texture->get_name()
+        << " from " << orig_width << "x" << orig_height
+        << " to " << target_width << "x" << target_height << "\n";
+    }
 
     shrink_original = true;
   }
@@ -218,7 +298,7 @@ create_texture(DXScreenData &scrn) {
     }
 
     if (num_alpha_bits>0) {
-      assert(num_color_channels == 4);
+      nassertr(num_color_channels == 4, false);
 
       // no 32-bit fmt, look for 16 bit w/alpha  (1-15)
 
@@ -262,7 +342,7 @@ create_texture(DXScreenData &scrn) {
     break;
 
   case 24:
-    assert(num_color_channels == 3);
+    nassertr(num_color_channels == 3, false);
 
     if (!dx_force_16bpptextures) {
       CHECK_FOR_FMT(R8G8B8, Conv24to24);
@@ -281,8 +361,8 @@ create_texture(DXScreenData &scrn) {
 
   case 16:
     if (needs_luminance) {
-      assert(num_alpha_bits>0);
-      assert(num_color_channels == 2);
+      nassertr(num_alpha_bits > 0, false);
+      nassertr(num_color_channels == 2, false);
 
       CHECK_FOR_FMT(A8L8, ConvLum16to16);
 
@@ -301,7 +381,7 @@ create_texture(DXScreenData &scrn) {
       CHECK_FOR_FMT(A4R4G4B4, ConvLum16to16_4444);
       CHECK_FOR_FMT(A1R5G5B5, ConvLum16to16_1555);
     } else {
-      assert((num_color_channels == 3)||(num_color_channels == 4));
+      nassertr((num_color_channels == 3)||(num_color_channels == 4), false);
       // look for compatible 16bit fmts, if none then give up
       // (dont worry about other bitdepths for 16 bit)
       switch(num_alpha_bits) {
@@ -310,7 +390,7 @@ create_texture(DXScreenData &scrn) {
           CHECK_FOR_FMT(R5G6B5, Conv24to16_0565);
           CHECK_FOR_FMT(X1R5G5B5, Conv24to16_X555);
         } else {
-          assert(num_color_channels == 4);
+          nassertr(num_color_channels == 4, false);
           // it could be 4 if user asks us to throw away the alpha channel
           CHECK_FOR_FMT(R5G6B5, Conv32to16_0565);
           CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555);
@@ -321,23 +401,24 @@ create_texture(DXScreenData &scrn) {
         // explicitly want 1-5-5-5 fmt, as opposed to F_rgbm, which
         // could use 32bpp ARGB.  fail if this particular fmt not
         // avail.
-        assert(num_color_channels == 4);
+        nassertr(num_color_channels == 4, false);
         CHECK_FOR_FMT(X1R5G5B5, Conv32to16_X555);
         break;
       case 4:
         // app specifically requests 4-4-4-4 F_rgba4 case, as opposed
         // to F_rgba, which could use 32bpp ARGB
-        assert(num_color_channels == 4);
+        nassertr(num_color_channels == 4, false);
         CHECK_FOR_FMT(A4R4G4B4, Conv32to16_4444);
         break;
-      default: assert(0);  // problem in get_bits_per_pixel()?
+      default: 
+        nassertr(false, false);  // problem in get_bits_per_pixel()?
       }
     }
   case 8:
     if (needs_luminance) {
       // dont bother handling those other 8bit lum fmts like 4-4,
       // since 16 8-8 is usually supported too
-      assert(num_color_channels == 1);
+      nassertr(num_color_channels == 1, false);
 
       // look for native lum fmt first
       CHECK_FOR_FMT(L8, ConvLum8to8);
@@ -375,9 +456,11 @@ create_texture(DXScreenData &scrn) {
 
   // if we've gotten here, haven't found a match
   dxgsg8_cat.error()
-    << error_message << ": " << _tex->get_name() << endl
-    << "NumColorChannels: " <<num_color_channels << "; NumAlphaBits: " << num_alpha_bits
-    << "; targetbpp: " <<target_bpp << "; _supported_tex_formats_mask: 0x" << (void*)scrn._supported_tex_formats_mask
+    << error_message << ": " << _texture->get_name() << endl
+    << "NumColorChannels: " << num_color_channels << "; NumAlphaBits: " 
+    << num_alpha_bits << "; targetbpp: " <<target_bpp
+    << "; _supported_tex_formats_mask: 0x"
+    << (void*)scrn._supported_tex_formats_mask
     << "; NeedLuminance: " << needs_luminance << endl;
   goto error_exit;
 
@@ -421,7 +504,7 @@ create_texture(DXScreenData &scrn) {
 
   Texture::FilterType ft;
 
-  ft = _tex->get_magfilter();
+  ft = _texture->get_magfilter();
   if ((ft != Texture::FT_linear) && ft != Texture::FT_nearest) {
     // mipmap settings make no sense for magfilter
     if (ft == Texture::FT_nearest_mipmap_nearest) {
@@ -431,13 +514,14 @@ create_texture(DXScreenData &scrn) {
     }
   }
 
-  if ((ft == Texture::FT_linear) && !(scrn._d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFLINEAR)) {
+  if (ft == Texture::FT_linear && 
+      (filter_caps & D3DPTFILTERCAPS_MAGFLINEAR) == 0) {
     ft = Texture::FT_nearest;
   }
-  _tex->set_magfilter(ft);
+  _texture->set_magfilter(ft);
 
   // figure out if we are mipmapping this texture
-  ft = _tex->get_minfilter();
+  ft = _texture->get_minfilter();
   _has_mipmaps = false;
 
   if (!dx_ignore_mipmaps) {  // set if no HW mipmap capable
@@ -453,11 +537,13 @@ create_texture(DXScreenData &scrn) {
       _has_mipmaps = true;
       if (dxgsg8_cat.is_spam()) {
         if (ft != Texture::FT_linear_mipmap_linear) {
-          dxgsg8_cat.spam() << "Forcing trilinear mipmapping on DX texture [" << _tex->get_name() << "]\n";
+          dxgsg8_cat.spam()
+            << "Forcing trilinear mipmapping on DX texture ["
+            << _texture->get_name() << "]\n";
         }
       }
       ft = Texture::FT_linear_mipmap_linear;
-      _tex->set_minfilter(ft);
+      _texture->set_minfilter(ft);
     }
 
   } else if ((ft == Texture::FT_nearest_mipmap_nearest) ||   // cvt to no-mipmap filter types
@@ -469,15 +555,15 @@ create_texture(DXScreenData &scrn) {
     ft = Texture::FT_linear;
   }
 
-  assert((scrn._d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFPOINT) != 0);
+  nassertr((filter_caps & D3DPTFILTERCAPS_MINFPOINT) != 0, false);
 
 #define TRILINEAR_MIPMAP_TEXFILTERCAPS (D3DPTFILTERCAPS_MIPFLINEAR | D3DPTFILTERCAPS_MINFLINEAR)
 
   // do any other filter type degradations necessary
   switch(ft) {
   case Texture::FT_linear_mipmap_linear:
-    if ((scrn._d3dcaps.TextureFilterCaps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) {
-      if (scrn._d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR) {
+    if ((filter_caps & TRILINEAR_MIPMAP_TEXFILTERCAPS) != TRILINEAR_MIPMAP_TEXFILTERCAPS) {
+      if (filter_caps & D3DPTFILTERCAPS_MINFLINEAR) {
         ft = Texture::FT_linear_mipmap_nearest;
       } else {
         // if you cant do linear in a level, you probably cant do
@@ -489,43 +575,43 @@ create_texture(DXScreenData &scrn) {
 
   case Texture::FT_nearest_mipmap_linear:
     // if we dont have bilinear, do nearest_nearest
-    if (!((scrn._d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MIPFPOINT) &&
-          (scrn._d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR))) {
+    if (!((filter_caps & D3DPTFILTERCAPS_MIPFPOINT) &&
+          (filter_caps & D3DPTFILTERCAPS_MINFLINEAR))) {
       ft = Texture::FT_nearest_mipmap_nearest;
     }
     break;
 
   case Texture::FT_linear_mipmap_nearest:
     // if we dont have mip linear, do nearest_nearest
-    if (!(scrn._d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MIPFLINEAR)) {
+    if (!(filter_caps & D3DPTFILTERCAPS_MIPFLINEAR)) {
       ft = Texture::FT_nearest_mipmap_nearest;
     }
     break;
 
   case Texture::FT_linear:
-    if (!(scrn._d3dcaps.TextureFilterCaps & D3DPTFILTERCAPS_MINFLINEAR)) {
+    if (!(filter_caps & D3DPTFILTERCAPS_MINFLINEAR)) {
       ft = Texture::FT_nearest;
     }
     break;
   }
 
-  _tex->set_minfilter(ft);
+  _texture->set_minfilter(ft);
 
   uint aniso_degree;
 
   aniso_degree = 1;
   if (scrn._d3dcaps.RasterCaps & D3DPRASTERCAPS_ANISOTROPY) {
-    aniso_degree = _tex->get_anisotropic_degree();
+    aniso_degree = _texture->get_anisotropic_degree();
     if ((aniso_degree>scrn._d3dcaps.MaxAnisotropy) || 
         dx_force_anisotropic_filtering) {
       aniso_degree = scrn._d3dcaps.MaxAnisotropy;
     }
   }
-  _tex->set_anisotropic_degree(aniso_degree);
+  _texture->set_anisotropic_degree(aniso_degree);
 
 #ifdef _DEBUG
   dxgsg8_cat.spam()
-    << "create_texture: setting aniso degree for " << _tex->get_name()
+    << "create_texture: setting aniso degree for " << _texture->get_name()
     << " to: " << aniso_degree << endl;
 #endif
 
@@ -537,15 +623,37 @@ create_texture(DXScreenData &scrn) {
 
     if (dxgsg8_cat.is_debug()) {
       dxgsg8_cat.debug()
-        << "create_texture: generating mipmaps for " << _tex->get_name()
+        << "create_texture: generating mipmaps for " << _texture->get_name()
         << endl;
     }
   } else {
     mip_level_count = 1;
   }
 
-  hr = scrn._d3d_device->CreateTexture(target_width, target_height, mip_level_count, 0x0,
-                                       target_pixel_format, D3DPOOL_MANAGED, &_d3d_texture);
+  switch (_texture->get_texture_type()) {
+  case Texture::TT_1d_texture:
+  case Texture::TT_2d_texture:
+    hr = scrn._d3d_device->CreateTexture
+      (target_width, target_height, mip_level_count, 0x0,
+       target_pixel_format, D3DPOOL_MANAGED, &_d3d_2d_texture);
+    _d3d_texture = _d3d_2d_texture;
+    break;
+
+  case Texture::TT_3d_texture:
+    hr = scrn._d3d_device->CreateVolumeTexture
+      (target_width, target_height, target_depth, mip_level_count, 0x0,
+       target_pixel_format, D3DPOOL_MANAGED, &_d3d_volume_texture);
+    _d3d_texture = _d3d_volume_texture;
+    break;
+
+  case Texture::TT_cube_map:
+    hr = scrn._d3d_device->CreateCubeTexture
+      (target_width, mip_level_count, 0x0,
+       target_pixel_format, D3DPOOL_MANAGED, &_d3d_cube_texture);
+    _d3d_texture = _d3d_cube_texture;
+    break;
+  }
+
   if (FAILED(hr)) {
     dxgsg8_cat.error()
       << "D3D create_texture failed!" << D3DERRORSTRING(hr);
@@ -554,7 +662,7 @@ create_texture(DXScreenData &scrn) {
 
   if (dxgsg8_cat.is_debug()) {
     dxgsg8_cat.debug()
-      << "create_texture: " << _tex->get_name()
+      << "create_texture: " << _texture->get_name()
       << " converting panda equivalent of " << D3DFormatStr(_d3d_format)
       << " => " << D3DFormatStr(target_pixel_format) << endl;
   }
@@ -566,13 +674,15 @@ create_texture(DXScreenData &scrn) {
 
   // PRINT_REFCNT(dxgsg8, scrn._d3d8);
 
-  // Return the newly created texture
-  return _d3d_texture;
+  return true;
 
  error_exit:
 
   RELEASE(_d3d_texture, dxgsg8, "texture", RELEASE_ONCE);
-  return NULL;
+  _d3d_2d_texture = NULL;
+  _d3d_volume_texture = NULL;
+  _d3d_cube_texture = NULL;
+  return false;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -587,11 +697,10 @@ delete_texture() {
     return;
   }
 
-  if (dxgsg8_cat.is_spam()) {
-    dxgsg8_cat.spam() << "Deleting DX texture for " << _tex->get_name() << "\n";
-  }
-
   RELEASE(_d3d_texture, dxgsg8, "texture", RELEASE_ONCE);
+  _d3d_2d_texture = NULL;
+  _d3d_volume_texture = NULL;
+  _d3d_cube_texture = NULL;
 }
 
 ////////////////////////////////////////////////////////////////////
@@ -616,7 +725,9 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface, Textur
   BYTE *buf = result->modify_ram_image().p();
 
   if (IsBadWritePtr(d3d_surface, sizeof(DWORD))) {
-    dxgsg8_cat.error() << "d3d_surface_to_texture failed: bad pD3DSurf ptr value (" << ((void*)d3d_surface) << ")\n";
+    dxgsg8_cat.error()
+      << "d3d_surface_to_texture failed: bad pD3DSurf ptr value ("
+      << ((void*)d3d_surface) << ")\n";
     exit(1);
   }
 
@@ -632,18 +743,20 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface, Textur
   copy_width = RECT_XSIZE(source_rect);
   copy_height = RECT_YSIZE(source_rect);
 
-  //make sure there's enough space in the texture, its size must match
-  //(especially xsize) or scanlines will be too long
+  // make sure there's enough space in the texture, its size must
+  // match (especially xsize) or scanlines will be too long
 
   if (!((copy_width == result->get_x_size()) && (copy_height <= (DWORD)result->get_y_size()))) {
-    dxgsg8_cat.error() << "d3d_surface_to_texture, Texture size too small to hold display surface!\n";
+    dxgsg8_cat.error()
+      << "d3d_surface_to_texture, Texture size too small to hold display surface!\n";
     nassertr(false, E_FAIL);
     return E_FAIL;
   }
 
   hr = d3d_surface->LockRect(&locked_rect, (CONST RECT*)NULL, (D3DLOCK_READONLY | D3DLOCK_NO_DIRTY_UPDATE /* | D3DLOCK_NOSYSLOCK */));
   if (FAILED(hr)) {
-    dxgsg8_cat.error() << "d3d_surface_to_texture LockRect() failed!" << D3DERRORSTRING(hr);
+    dxgsg8_cat.error()
+      << "d3d_surface_to_texture LockRect() failed!" << D3DERRORSTRING(hr);
     return hr;
   }
 
@@ -816,7 +929,8 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface, Textur
   }
 
   default:
-    dxgsg8_cat.error() << "d3d_surface_to_texture: unsupported D3DFORMAT!\n";
+    dxgsg8_cat.error()
+      << "d3d_surface_to_texture: unsupported D3DFORMAT!\n";
   }
 
   d3d_surface->UnlockRect();
@@ -830,8 +944,12 @@ d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface, Textur
 ////////////////////////////////////////////////////////////////////
 HRESULT DXTextureContext8::
 fill_d3d_texture_pixels() {
+  if (_texture->get_texture_type() == Texture::TT_3d_texture) {
+    return fill_d3d_volume_texture_pixels();
+  }
+
   HRESULT hr = E_FAIL;
-  assert(IS_VALID_PTR(_texture));
+  nassertr(IS_VALID_PTR(_texture), E_FAIL);
 
   CPTA_uchar image = _texture->get_ram_image();
   if (image.is_null()) {
@@ -843,80 +961,266 @@ fill_d3d_texture_pixels() {
 
   PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
 
-  assert(IS_VALID_PTR(_d3d_texture));
+  nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
 
   DWORD orig_width  = (DWORD) _texture->get_x_size();
   DWORD orig_height = (DWORD) _texture->get_y_size();
+  DWORD orig_depth = (DWORD) _texture->get_z_size();
   DWORD num_color_channels = _texture->get_num_components();
   D3DFORMAT source_format = _d3d_format;
-  BYTE *pixels = (BYTE*)image.p();
+  BYTE *image_pixels = (BYTE*)image.p();
   int component_width = _texture->get_component_width();
 
-  assert(IS_VALID_PTR(pixels));
+  nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
 
-  IDirect3DSurface8 *mip_level_0;
-  hr = _d3d_texture->GetSurfaceLevel(0, &mip_level_0);
-  if (FAILED(hr)) {
-    dxgsg8_cat.error() << "FillDDSurfaceTexturePixels failed for " << _tex->get_name() << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
-    return E_FAIL;
+  IDirect3DSurface8 *mip_level_0 = NULL;
+  bool using_temp_buffer = false;
+  BYTE *pixels = NULL;
+
+  for (unsigned int di = 0; di < orig_depth; di++) {
+    pixels = image_pixels + di * _texture->get_expected_ram_page_size();
+    mip_level_0 = NULL;
+
+    if (_texture->get_texture_type() == Texture::TT_cube_map) {
+      nassertr(IS_VALID_PTR(_d3d_cube_texture), E_FAIL);
+      hr = _d3d_cube_texture->GetCubeMapSurface((D3DCUBEMAP_FACES)di, 0, &mip_level_0);
+    } else {      
+      nassertr(IS_VALID_PTR(_d3d_2d_texture), E_FAIL);
+      hr = _d3d_2d_texture->GetSurfaceLevel(0, &mip_level_0);
+    }
+
+    if (FAILED(hr)) {
+      dxgsg8_cat.error()
+        << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+      << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
+      return E_FAIL;
+    }
+
+    RECT source_size;
+    source_size.left = source_size.top = 0;
+    source_size.right = orig_width;
+    source_size.bottom = orig_height;
+    
+    UINT source_row_byte_length = orig_width * num_color_channels;
+    
+    DWORD level_0_filter, mip_filter_flags;
+    using_temp_buffer = false;
+    
+    // need filtering if size changes, (also if bitdepth reduced (need
+    // dithering)??)
+    level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
+    
+    // D3DXLoadSurfaceFromMemory will load black luminance and we want
+    // full white, so convert to explicit luminance-alpha format
+    if (_d3d_format == D3DFMT_A8) {
+      // alloc buffer for explicit D3DFMT_A8L8
+      USHORT *temp_buffer = new USHORT[orig_width * orig_height];
+      if (!IS_VALID_PTR(temp_buffer)) {
+        dxgsg8_cat.error()
+          << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
+        goto exit_FillDDSurf;
+      }
+      using_temp_buffer = true;
+      
+      USHORT *out_pixels = temp_buffer;
+      BYTE *source_pixels = pixels + component_width - 1;
+      for (UINT y = 0; y < orig_height; y++) {
+        for (UINT x = 0;
+             x < orig_width;
+             x++, source_pixels += component_width, out_pixels++) {
+          // add full white, which is our interpretation of alpha-only
+          // (similar to default adding full opaque alpha 0xFF to
+          // RGB-only textures)
+          *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
+        }
+      }
+      
+      source_format = D3DFMT_A8L8;
+      source_row_byte_length = orig_width * sizeof(USHORT);
+      pixels = (BYTE*)temp_buffer;
+      
+    } else if (component_width != 1) {
+      // Convert from 16-bit per channel (or larger) format down to
+      // 8-bit per channel.  This throws away precision in the
+      // original image, but dx8 doesn't support high-precision images
+      // anyway.
+      
+      int num_components = _texture->get_num_components();
+      int num_pixels = orig_width * orig_height * num_components;
+      BYTE *temp_buffer = new BYTE[num_pixels];
+      if (!IS_VALID_PTR(temp_buffer)) {
+        dxgsg8_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
+        goto exit_FillDDSurf;
+      }
+      using_temp_buffer = true;
+      
+      BYTE *source_pixels = pixels + component_width - 1;
+      for (int i = 0; i < num_pixels; i++) {
+        temp_buffer[i] = *source_pixels;
+        source_pixels += component_width;
+      }
+      pixels = (BYTE*)temp_buffer;
+    }
+    
+    
+    // filtering may be done here if texture if targetsize != origsize
+#ifdef DO_PSTATS
+    GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * orig_height);
+#endif
+    hr = D3DXLoadSurfaceFromMemory
+      (mip_level_0, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)pixels,
+       source_format, source_row_byte_length, (PALETTEENTRY*)NULL, 
+       &source_size, level_0_filter, (D3DCOLOR)0x0);
+    if (FAILED(hr)) {
+      dxgsg8_cat.error()
+        << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+        << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
+      goto exit_FillDDSurf;
+    }
+    
+    if (_has_mipmaps) {
+      if (!dx_use_triangle_mipgen_filter) {
+        mip_filter_flags = D3DX_FILTER_BOX;
+      } else {
+        mip_filter_flags = D3DX_FILTER_TRIANGLE;
+      }
+      
+      //    mip_filter_flags| = D3DX_FILTER_DITHER;
+      
+      hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0, 
+                             mip_filter_flags);
+      if (FAILED(hr)) {
+        dxgsg8_cat.error()
+          << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+          << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
+        goto exit_FillDDSurf;
+      }
+    }
+    if (using_temp_buffer) {
+      SAFE_DELETE_ARRAY(pixels);
+    }
+    RELEASE(mip_level_0, dxgsg8, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE);
+  }
+  return hr;
+    
+ exit_FillDDSurf:
+  if (using_temp_buffer) {
+    SAFE_DELETE_ARRAY(pixels);
   }
+  RELEASE(mip_level_0, dxgsg8, "FillDDSurf MipLev0 texture ptr", RELEASE_ONCE);
+  return hr;
+}
 
-  RECT source_size;
-  source_size.left = source_size.top = 0;
-  source_size.right = orig_width;
-  source_size.bottom = orig_height;
+////////////////////////////////////////////////////////////////////
+//     Function: DXTextureContext8::fill_d3d_volume_texture_pixels
+//       Access: Private
+//  Description: 
+////////////////////////////////////////////////////////////////////
+HRESULT DXTextureContext8::
+fill_d3d_volume_texture_pixels() {
+  HRESULT hr = E_FAIL;
+  nassertr(IS_VALID_PTR(_texture), E_FAIL);
 
-  UINT source_row_byte_length = orig_width * num_color_channels;
+  CPTA_uchar image = _texture->get_ram_image();
+  if (image.is_null()) {
+    // The texture doesn't have an image to load.  That's ok; it
+    // might be a texture we've rendered to by frame buffer
+    // operations or something.
+    return S_OK;
+  }
 
-  DWORD level_0_filter, mip_filter_flags;
+  PStatTimer timer(GraphicsStateGuardian::_load_texture_pcollector);
+
+  nassertr(IS_VALID_PTR(_d3d_texture), E_FAIL);
+  nassertr(_texture->get_texture_type() == Texture::TT_3d_texture, E_FAIL);
+
+  DWORD orig_width  = (DWORD) _texture->get_x_size();
+  DWORD orig_height = (DWORD) _texture->get_y_size();
+  DWORD orig_depth = (DWORD) _texture->get_z_size();
+  DWORD num_color_channels = _texture->get_num_components();
+  D3DFORMAT source_format = _d3d_format;
+  BYTE *image_pixels = (BYTE*)image.p();
+  int component_width = _texture->get_component_width();
+
+  nassertr(IS_VALID_PTR(image_pixels), E_FAIL);
+
+  IDirect3DVolume8 *mip_level_0 = NULL;
   bool using_temp_buffer = false;
+  BYTE *pixels = image_pixels;
 
-  // need filtering if size changes, (also if bitdepth reduced (need dithering)??)
-  level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
+  nassertr(IS_VALID_PTR(_d3d_volume_texture), E_FAIL);
+  hr = _d3d_volume_texture->GetVolumeLevel(0, &mip_level_0);
+
+  if (FAILED(hr)) {
+    dxgsg8_cat.error()
+      << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+      << ", GetSurfaceLevel failed" << D3DERRORSTRING(hr);
+    return E_FAIL;
+  }
 
-  // D3DXLoadSurfaceFromMemory will load black luminance and we want full white,
-  // so convert to explicit luminance-alpha format
+  D3DBOX source_size;
+  source_size.Left = source_size.Top = source_size.Front = 0;
+  source_size.Right = orig_width;
+  source_size.Bottom = orig_height;
+  source_size.Back = orig_depth;
+    
+  UINT source_row_byte_length = orig_width * num_color_channels;
+  UINT source_page_byte_length = orig_height * source_row_byte_length;
+    
+  DWORD level_0_filter, mip_filter_flags;
+  using_temp_buffer = false;
+    
+  // need filtering if size changes, (also if bitdepth reduced (need
+  // dithering)??)
+  level_0_filter = D3DX_FILTER_LINEAR ; //| D3DX_FILTER_DITHER;  //dithering looks ugly on i810 for 4444 textures
+    
+  // D3DXLoadSurfaceFromMemory will load black luminance and we want
+  // full white, so convert to explicit luminance-alpha format
   if (_d3d_format == D3DFMT_A8) {
     // alloc buffer for explicit D3DFMT_A8L8
-    USHORT *temp_buffer = new USHORT[orig_width*orig_height];
+    USHORT *temp_buffer = new USHORT[orig_width * orig_height * orig_depth];
     if (!IS_VALID_PTR(temp_buffer)) {
-      dxgsg8_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
+      dxgsg8_cat.error()
+        << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
       goto exit_FillDDSurf;
     }
     using_temp_buffer = true;
-
+    
     USHORT *out_pixels = temp_buffer;
     BYTE *source_pixels = pixels + component_width - 1;
-    for (UINT y = 0; y < orig_height; y++) {
-      for (UINT x = 0;
-           x < orig_width;
-           x++, source_pixels += component_width, out_pixels++) {
-        // add full white, which is our interpretation of alpha-only
-        // (similar to default adding full opaque alpha 0xFF to
-        // RGB-only textures)
-        *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
+    for (UINT z = 0; z < orig_depth; z++) {
+      for (UINT y = 0; y < orig_height; y++) {
+        for (UINT x = 0;
+             x < orig_width;
+             x++, source_pixels += component_width, out_pixels++) {
+          // add full white, which is our interpretation of alpha-only
+          // (similar to default adding full opaque alpha 0xFF to
+          // RGB-only textures)
+          *out_pixels = ((*source_pixels) << 8 ) | 0xFF;
+        }
       }
     }
-
+      
     source_format = D3DFMT_A8L8;
-    source_row_byte_length = orig_width*sizeof(USHORT);
+    source_row_byte_length = orig_width * sizeof(USHORT);
+    source_page_byte_length = orig_height * source_row_byte_length;
     pixels = (BYTE*)temp_buffer;
-
+      
   } else if (component_width != 1) {
     // Convert from 16-bit per channel (or larger) format down to
     // 8-bit per channel.  This throws away precision in the
     // original image, but dx8 doesn't support high-precision images
     // anyway.
-
+    
     int num_components = _texture->get_num_components();
-    int num_pixels = orig_width * orig_height * num_components;
+    int num_pixels = orig_width * orig_height * orig_depth * num_components;
     BYTE *temp_buffer = new BYTE[num_pixels];
     if (!IS_VALID_PTR(temp_buffer)) {
       dxgsg8_cat.error() << "FillDDSurfaceTexturePixels couldnt alloc mem for temp pixbuf!\n";
       goto exit_FillDDSurf;
     }
     using_temp_buffer = true;
-
+    
     BYTE *source_pixels = pixels + component_width - 1;
     for (int i = 0; i < num_pixels; i++) {
       temp_buffer[i] = *source_pixels;
@@ -924,36 +1228,43 @@ fill_d3d_texture_pixels() {
     }
     pixels = (BYTE*)temp_buffer;
   }
-
-
+    
+    
   // filtering may be done here if texture if targetsize != origsize
 #ifdef DO_PSTATS
-  GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_row_byte_length * orig_height);
+  GraphicsStateGuardian::_data_transferred_pcollector.add_level(source_page_byte_length * orig_depth);
 #endif
-  hr = D3DXLoadSurfaceFromMemory(mip_level_0, (PALETTEENTRY*)NULL, (RECT*)NULL, (LPCVOID)pixels, source_format,
-                                 source_row_byte_length, (PALETTEENTRY*)NULL, &source_size, level_0_filter, (D3DCOLOR)0x0);
+  hr = D3DXLoadVolumeFromMemory
+    (mip_level_0, (PALETTEENTRY*)NULL, (D3DBOX*)NULL, (LPCVOID)pixels,
+     source_format, source_row_byte_length, source_page_byte_length,
+     (PALETTEENTRY*)NULL, 
+     &source_size, level_0_filter, (D3DCOLOR)0x0);
   if (FAILED(hr)) {
-    dxgsg8_cat.error() << "FillDDSurfaceTexturePixels failed for " << _tex->get_name() << ", D3DXLoadSurfFromMem failed" << D3DERRORSTRING(hr);
+    dxgsg8_cat.error()
+      << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+      << ", D3DXLoadVolumeFromMem failed" << D3DERRORSTRING(hr);
     goto exit_FillDDSurf;
   }
-
+  
   if (_has_mipmaps) {
     if (!dx_use_triangle_mipgen_filter) {
       mip_filter_flags = D3DX_FILTER_BOX;
     } else {
       mip_filter_flags = D3DX_FILTER_TRIANGLE;
     }
-
+    
     //    mip_filter_flags| = D3DX_FILTER_DITHER;
-
-    hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0, mip_filter_flags);
+    
+    hr = D3DXFilterTexture(_d3d_texture, (PALETTEENTRY*)NULL, 0, 
+                           mip_filter_flags);
     if (FAILED(hr)) {
       dxgsg8_cat.error()
-        << "FillDDSurfaceTexturePixels failed for " << _tex->get_name() << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
+        << "FillDDSurfaceTexturePixels failed for " << _texture->get_name()
+        << ", D3DXFilterTex failed" << D3DERRORSTRING(hr);
       goto exit_FillDDSurf;
     }
   }
-
+    
  exit_FillDDSurf:
   if (using_temp_buffer) {
     SAFE_DELETE_ARRAY(pixels);

+ 10 - 4
panda/src/dxgsg8/dxTextureContext8.h

@@ -32,23 +32,29 @@ public:
   DXTextureContext8(Texture *tex);
   virtual ~DXTextureContext8();
 
-  IDirect3DTexture8 *create_texture(DXScreenData &scrn);
+  bool create_texture(DXScreenData &scrn);
   void delete_texture();
 
   INLINE bool has_mipmaps() const;
-  INLINE IDirect3DTexture8 *get_d3d_texture() const;
+  INLINE IDirect3DBaseTexture8 *get_d3d_texture() const;
+  INLINE IDirect3DTexture8 *get_d3d_2d_texture() const;
+  INLINE IDirect3DVolumeTexture8 *get_d3d_volume_texture() const;
+  INLINE IDirect3DCubeTexture8 *get_d3d_cube_texture() const;
 
   static HRESULT d3d_surface_to_texture(RECT &source_rect, IDirect3DSurface8 *d3d_surface, Texture *result);
 
 private:
   HRESULT fill_d3d_texture_pixels();
+  HRESULT fill_d3d_volume_texture_pixels();
   static int down_to_power_2(int value);
   unsigned int get_bits_per_pixel(Texture::Format format, int *alphbits);
 
 private:
-  Texture *_tex;            // ptr to parent, primarily for access to namestr
   D3DFORMAT _d3d_format;    // the 'D3DFORMAT' the Panda TextureBuffer fmt corresponds to
-  IDirect3DTexture8  *_d3d_texture;
+  IDirect3DBaseTexture8 *_d3d_texture;
+  IDirect3DTexture8 *_d3d_2d_texture;
+  IDirect3DVolumeTexture8 *_d3d_volume_texture;
+  IDirect3DCubeTexture8 *_d3d_cube_texture;
 
   bool _has_mipmaps;
 

+ 1 - 1
panda/src/dxgsg8/wdxGraphicsWindow8.cxx

@@ -1114,7 +1114,7 @@ search_for_device(wdxGraphicsPipe8 *dxpipe, DXDeviceInfo *device_info) {
 ////////////////////////////////////////////////////////////////////
 bool wdxGraphicsWindow8::
 reset_device_resize_window(UINT new_xsize, UINT new_ysize) {
-  assert((new_xsize > 0) && (new_ysize > 0));
+  nassertr((new_xsize > 0) && (new_ysize > 0), false);
   bool retval = true;
 
   DXScreenData *screen = NULL;

+ 0 - 6
panda/src/egg/eggTexture.cxx

@@ -836,9 +836,6 @@ string_tex_gen(const string &string) {
   } else if (cmp_nocase_uh(string, "world_position") == 0) {
     return TG_world_position;
 
-  } else if (cmp_nocase_uh(string, "object_position") == 0) {
-    return TG_object_position;
-
   } else if (cmp_nocase_uh(string, "eye_position") == 0) {
     return TG_eye_position;
 
@@ -1161,9 +1158,6 @@ operator << (ostream &out, EggTexture::TexGen tex_gen) {
   case EggTexture::TG_world_position:
     return out << "world_position";
 
-  case EggTexture::TG_object_position:
-    return out << "object_position";
-
   case EggTexture::TG_eye_position:
     return out << "eye_position";
 

+ 0 - 1
panda/src/egg/eggTexture.h

@@ -140,7 +140,6 @@ PUBLISHED:
     TG_eye_normal,
 
     TG_world_position,
-    TG_object_position,
     TG_eye_position,
 
     TG_point_sprite,

+ 0 - 3
panda/src/egg2pg/eggRenderState.cxx

@@ -515,9 +515,6 @@ get_tex_gen(const EggTexture *egg_tex) {
   case EggTexture::TG_world_position:
     return TexGenAttrib::M_world_position;
 
-  case EggTexture::TG_object_position:
-    return TexGenAttrib::M_object_position;
-
   case EggTexture::TG_eye_position:
     return TexGenAttrib::M_eye_position;
 

+ 0 - 17
panda/src/glstuff/glGraphicsStateGuardian_src.cxx

@@ -4300,23 +4300,6 @@ finish_modify_state() {
         }
         break;
 
-      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 TexGenAttrib::M_eye_position:
         // To represent eye position correctly, we need to temporarily
         // load the coordinate-system transform.

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

@@ -330,12 +330,9 @@ public:
   bool _supports_draw_range_elements;
   PFNGLDRAWRANGEELEMENTSPROC _glDrawRangeElements;
 
-  bool _supports_3d_texture;
   PFNGLTEXIMAGE3DPROC _glTexImage3D;
   PFNGLTEXSUBIMAGE3DPROC _glTexSubImage3D;
 
-  bool _supports_cube_map;
-
   bool _supports_bgr;
   bool _supports_rescale_normal;
 

+ 17 - 8
panda/src/gobj/texture.cxx

@@ -1008,7 +1008,11 @@ release(PreparedGraphicsObjects *prepared_objects) {
   ci = _contexts.find(prepared_objects);
   if (ci != _contexts.end()) {
     TextureContext *tc = (*ci).second;
-    prepared_objects->release_texture(tc);
+    if (tc != (TextureContext *)NULL) {
+      prepared_objects->release_texture(tc);
+    } else {
+      _contexts.erase(ci);
+    }
     return true;
   }
 
@@ -1036,12 +1040,14 @@ release_all() {
   for (ci = temp.begin(); ci != temp.end(); ++ci) {
     PreparedGraphicsObjects *prepared_objects = (*ci).first;
     TextureContext *tc = (*ci).second;
-    prepared_objects->release_texture(tc);
+    if (tc != (TextureContext *)NULL) {
+      prepared_objects->release_texture(tc);
+    }
   }
 
-  // Now that we've called release_texture() on every known context,
-  // the _contexts list should have completely emptied itself.
-  nassertr(_contexts.empty(), num_freed);
+  // There might still be some outstanding contexts in the map, if
+  // there were any NULL pointers there.  Eliminate them.
+  _contexts.clear();
 
   return num_freed;
 }
@@ -1163,9 +1169,9 @@ prepare_now(PreparedGraphicsObjects *prepared_objects,
   }
 
   TextureContext *tc = prepared_objects->prepare_texture_now(this, gsg);
-  if (tc != (TextureContext *)NULL) {
-    _contexts[prepared_objects] = tc;
+  _contexts[prepared_objects] = tc;
 
+  if (tc != (TextureContext *)NULL) {
     // Now that we have a new TextureContext with zero dirty flags, our
     // intersection of all dirty flags must be zero.  This doesn't mean
     // that some other contexts aren't still dirty, but at least one
@@ -1213,7 +1219,10 @@ mark_dirty(int flags_to_set) {
   // Otherwise, iterate through the contexts and mark them all dirty.
   Contexts::iterator ci;
   for (ci = _contexts.begin(); ci != _contexts.end(); ++ci) {
-    (*ci).second->mark_dirty(flags_to_set);
+    TextureContext *tc = (*ci).second;
+    if (tc != (TextureContext *)NULL) {
+      tc->mark_dirty(flags_to_set);
+    }
   }
 
   _all_dirty_flags |= flags_to_set;

+ 4 - 6
panda/src/pgraph/renderAttrib.h

@@ -99,8 +99,7 @@ PUBLISHED:
     M_off,
 
     // In the types below, "eye" means the coordinate space of the
-    // observing camera, "object" means the local coordinate space of
-    // the object, and "world" means world coordinates, e.g. the
+    // observing camera, and "world" means world coordinates, e.g. the
     // coordinate space of the root of the graph.
 
     // Sphere maps are classic static reflection maps.  They are
@@ -114,9 +113,8 @@ PUBLISHED:
     // texture images.  They can also be generated dynamically for
     // real-time reflections (see GraphicsOutput::make_cube_map()).
     // Typically, a statically-generated cube map will be in eye
-    // space, while a dynamically-generated map will be in world space
-    // or object space (depending on where the camera rig that
-    // generates the map is parented).
+    // space, while a dynamically-generated map will be in world
+    // space.
 
     // Cube mapping is not supported on all hardware.
     M_world_cube_map,
@@ -131,7 +129,7 @@ PUBLISHED:
     // coordinates.  This is particularly useful for implementing
     // projective texturing (see NodePath::project_texture()).
     M_world_position,
-    M_object_position,
+    M_unused,  // formerly M_object_position, now deprecated.
     M_eye_position,
 
     // With M_point_sprite, texture coordinates will be generated for

+ 3 - 3
panda/src/pgraph/texGenAttrib.cxx

@@ -283,9 +283,6 @@ output(ostream &out) const {
     case M_world_position:
       out << "world_position";
       break;
-    case M_object_position:
-      out << "object_position";
-      break;
     case M_eye_position:
       out << "eye_position";
       break;
@@ -298,6 +295,9 @@ output(ostream &out) const {
       out << "light_vector: \"" << mode_def._source_name << "\", "
           << mode_def._light;
       break;
+
+    case M_unused:
+      break;
     }
     out << ")";
   }