Browse Source

fix dx8/dx9 texture coordinate issue

David Rose 18 years ago
parent
commit
d52bd0616b

+ 60 - 44
panda/src/dxgsg8/dxGeomMunger8.cxx

@@ -133,37 +133,45 @@ munge_format_impl(const GeomVertexFormat *orig,
   }
 
   // To support multitexture, we will need to add all of the relevant
-  // texcoord types, and in the correct order.
+  // texcoord types, and in the order specified by the TextureAttrib.
 
   // Now set up each of the active texture coordinate stages--or at
   // least those for which we're not generating texture coordinates
   // automatically.
 
-  // Now copy all of the texture coordinates in, in order by stage
-  // index.  But we have to reuse previous columns.
   if (_filtered_texture != (TextureAttrib *)NULL) {
-    typedef pset<const InternalName *> UsedStages;
-    UsedStages used_stages;
-
-    int num_stages = _filtered_texture->get_num_on_stages();
-    for (int i = 0; i < num_stages; ++i) {
-      TextureStage *stage = _filtered_texture->get_on_stage(i);
+    int num_stages = _filtered_texture->get_num_on_ff_stages();
+    vector_int ff_tc_index(num_stages, 0);
+
+    // Be sure we add the texture coordinates in the right order, as
+    // specified by the attrib.  To ensure this, we first walk through
+    // the stages of the attrib and get the index numbers in the
+    // appropriate order.
+    int si, tc_index;
+    for (si = 0; si < num_stages; ++si) {
+      int tc_index = _filtered_texture->get_ff_tc_index(si);
+      ff_tc_index[tc_index] = si;
+    }
 
+    // Now walk through the texture coordinates in the order they will
+    // appear on the final geometry.  For each one, get the texture
+    // coordinate name from the associated stage.
+    for (tc_index = 0; tc_index < num_stages; ++tc_index) {
+      si = ff_tc_index[tc_index];
+      TextureStage *stage = _filtered_texture->get_on_ff_stage(si);
       InternalName *name = stage->get_texcoord_name();
-      if (used_stages.insert(name).second) {
-        // This is the first time we've encountered this texcoord name.
-        const GeomVertexColumn *texcoord_type = orig->get_column(name);
-        
-        if (texcoord_type != (const GeomVertexColumn *)NULL) {
-          new_array_format->add_column
-            (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
-        } else {
-          // We have to add something as a placeholder, even if the
-          // texture coordinates aren't defined.
-          new_array_format->add_column(name, 2, NT_float32, C_texcoord);
-        }
-        new_format->remove_column(name);
+
+      const GeomVertexColumn *texcoord_type = orig->get_column(name);
+
+      if (texcoord_type != (const GeomVertexColumn *)NULL) {
+        new_array_format->add_column
+          (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
+      } else {
+        // We have to add something as a placeholder, even if the
+        // texture coordinates aren't defined.
+        new_array_format->add_column(name, 2, NT_float32, C_texcoord);
       }
+      new_format->remove_column(name);
     }
   }
 
@@ -216,37 +224,45 @@ premunge_format_impl(const GeomVertexFormat *orig) {
   }
 
   // To support multitexture, we will need to add all of the relevant
-  // texcoord types, and in the correct order.
+  // texcoord types, and in the order specified by the TextureAttrib.
 
   // Now set up each of the active texture coordinate stages--or at
   // least those for which we're not generating texture coordinates
   // automatically.
 
-  // Now copy all of the texture coordinates in, in order by stage
-  // index.  But we have to reuse previous columns.
   if (_filtered_texture != (TextureAttrib *)NULL) {
-    typedef pset<const InternalName *> UsedStages;
-    UsedStages used_stages;
-
-    int num_stages = _filtered_texture->get_num_on_stages();
-    for (int i = 0; i < num_stages; ++i) {
-      TextureStage *stage = _filtered_texture->get_on_stage(i);
+    int num_stages = _filtered_texture->get_num_on_ff_stages();
+    vector_int ff_tc_index(num_stages, 0);
+
+    // Be sure we add the texture coordinates in the right order, as
+    // specified by the attrib.  To ensure this, we first walk through
+    // the stages of the attrib and get the index numbers in the
+    // appropriate order.
+    int si, tc_index;
+    for (si = 0; si < num_stages; ++si) {
+      int tc_index = _filtered_texture->get_ff_tc_index(si);
+      ff_tc_index[tc_index] = si;
+    }
 
+    // Now walk through the texture coordinates in the order they will
+    // appear on the final geometry.  For each one, get the texture
+    // coordinate name from the associated stage.
+    for (tc_index = 0; tc_index < num_stages; ++tc_index) {
+      si = ff_tc_index[tc_index];
+      TextureStage *stage = _filtered_texture->get_on_ff_stage(si);
       InternalName *name = stage->get_texcoord_name();
-      if (used_stages.insert(name).second) {
-        // This is the first time we've encountered this texcoord name.
-        const GeomVertexColumn *texcoord_type = orig->get_column(name);
-        
-        if (texcoord_type != (const GeomVertexColumn *)NULL) {
-          new_array_format->add_column
-            (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
-        } else {
-          // We have to add something as a placeholder, even if the
-          // texture coordinates aren't defined.
-          new_array_format->add_column(name, 2, NT_float32, C_texcoord);
-        }
-        new_format->remove_column(name);
+
+      const GeomVertexColumn *texcoord_type = orig->get_column(name);
+
+      if (texcoord_type != (const GeomVertexColumn *)NULL) {
+        new_array_format->add_column
+          (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
+      } else {
+        // We have to add something as a placeholder, even if the
+        // texture coordinates aren't defined.
+        new_array_format->add_column(name, 2, NT_float32, C_texcoord);
       }
+      new_format->remove_column(name);
     }
   }
 

+ 26 - 37
panda/src/dxgsg8/dxGraphicsStateGuardian8.cxx

@@ -2609,32 +2609,21 @@ do_issue_texture() {
 
   // We have to match up the texcoord stage index to the order written
   // out by the DXGeomMunger.  This means the texcoord names are
-  // written in the order they are referenced by the TextureAttrib,
-  // except that if a name is repeated its index number is reused from
-  // the first time.
-  typedef pmap<const InternalName *, int> UsedTexcoordIndex;
-  UsedTexcoordIndex used_texcoord_index;
+  // written in the order indicated by the TextureAttrib.
+
+  int si;
+  for (si = 0; si < num_stages; si++) {
+    TextureStage *stage = _effective_texture->get_on_ff_stage(si);
+    int texcoord_index = _effective_texture->get_ff_tc_index(si);
 
-  int i;
-  for (i = 0; i < num_stages; i++) {
-    TextureStage *stage = _effective_texture->get_on_ff_stage(i);
     Texture *texture = _effective_texture->get_on_texture(stage);
     nassertv(texture != (Texture *)NULL);
 
-    const InternalName *name = stage->get_texcoord_name();
-
-    // This pair of lines will get the next consecutive texcoord index
-    // number if this is the first time we have referenced this
-    // particular texcoord name; otherwise, it will return the same
-    // index number it returned before.
-    UsedTexcoordIndex::iterator ti = used_texcoord_index.insert(UsedTexcoordIndex::value_type(name, (int)used_texcoord_index.size())).first;
-    int texcoord_index = (*ti).second;
-
     // We always reissue every stage in DX, just in case the texcoord
     // index or texgen mode or some other property has changed.
     TextureContext *tc = texture->prepare_now(_prepared_objects, this);
-    apply_texture(i, tc);
-    set_texture_blend_mode(i, stage);
+    apply_texture(si, tc);
+    set_texture_blend_mode(si, stage);
 
     int texcoord_dimensions = 2;
 
@@ -2650,12 +2639,12 @@ do_issue_texture() {
     switch (mode) {
     case TexGenAttrib::M_off:
     case TexGenAttrib::M_light_vector:
-      _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, texcoord_index);
+      _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
       break;
 
     case TexGenAttrib::M_eye_sphere_map:
       {
-        _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX,
+        _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX,
                                           texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
         // This texture matrix, applied on top of the texcoord
         // computed by D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR,
@@ -2676,7 +2665,7 @@ do_issue_texture() {
       // transform.  In the case of a vector, we should not apply the
       // pos component of the transform.
       {
-        _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX,
+        _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX,
                                           texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
         texcoord_dimensions = 3;
         CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
@@ -2685,7 +2674,7 @@ do_issue_texture() {
       break;
 
     case TexGenAttrib::M_eye_cube_map:
-      _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX,
+      _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX,
                                         texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
       tex_mat = tex_mat->compose(_inv_cs_transform);
       texcoord_dimensions = 3;
@@ -2697,7 +2686,7 @@ do_issue_texture() {
       // the case of a normal, we should not apply the pos component
       // of the transform.
       {
-        _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX,
+        _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX,
                                           texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
         texcoord_dimensions = 3;
         CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
@@ -2706,7 +2695,7 @@ do_issue_texture() {
       break;
 
     case TexGenAttrib::M_eye_normal:
-      _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX,
+      _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX,
                                         texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
       texcoord_dimensions = 3;
       tex_mat = tex_mat->compose(_inv_cs_transform);
@@ -2717,7 +2706,7 @@ do_issue_texture() {
       // coordinates to world coordinates; i.e. apply the
       // camera transform.
       {
-        _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX,
+        _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX,
                                           texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
         texcoord_dimensions = 3;
         CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
@@ -2726,14 +2715,14 @@ do_issue_texture() {
       break;
 
     case TexGenAttrib::M_eye_position:
-      _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX,
+      _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX,
                                         texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
       texcoord_dimensions = 3;
       tex_mat = tex_mat->compose(_inv_cs_transform);
       break;
 
     case TexGenAttrib::M_point_sprite:
-      _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, texcoord_index);
+      _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
       any_point_sprite = true;
       break;
 
@@ -2749,7 +2738,7 @@ do_issue_texture() {
       // that there are 3-d texture coordinates, because of the
       // 3-component texture coordinate in get_constant_value().
       {
-        _d3d_device->SetTextureStageState(i, D3DTSS_TEXCOORDINDEX, 
+        _d3d_device->SetTextureStageState(si, D3DTSS_TEXCOORDINDEX, 
                                           texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
         texcoord_dimensions = 3;
 
@@ -2772,35 +2761,35 @@ do_issue_texture() {
               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,
+        _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)m.get_data());
+        _d3d_device->SetTextureStageState(si, D3DTSS_TEXTURETRANSFORMFLAGS,
                                           D3DTTFF_COUNT2);
       } else {
         LMatrix4f m = tex_mat->get_mat();
-        _d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)m.get_data());
+        _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)m.get_data());
         DWORD transform_flags = texcoord_dimensions;
         if (m.get_col(3) != LVecBase4f(0.0f, 0.0f, 0.0f, 1.0f)) {
           // If we have a projected texture matrix, we also need to
           // set D3DTTFF_COUNT4.
           transform_flags = D3DTTFF_COUNT4 | D3DTTFF_PROJECTED;
         }
-        _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS,
+        _d3d_device->SetTextureStageState(si, D3DTSS_TEXTURETRANSFORMFLAGS,
                                           transform_flags);
       }
 
     } else {
-      _d3d_device->SetTextureStageState(i, D3DTSS_TEXTURETRANSFORMFLAGS,
+      _d3d_device->SetTextureStageState(si, D3DTSS_TEXTURETRANSFORMFLAGS,
                                         D3DTTFF_DISABLE);
       // For some reason, "disabling" texture coordinate transforms
       // doesn't seem to be sufficient.  We'll load an identity matrix
       // to underscore the point.
-      _d3d_device->SetTransform(get_tex_mat_sym(i), &_d3d_ident_mat);
+      _d3d_device->SetTransform(get_tex_mat_sym(si), &_d3d_ident_mat);
     }
   }
 
   // Disable the texture stages that are no longer used.
-  for (i = num_stages; i < _num_active_texture_stages; i++) {
-    _d3d_device->SetTextureStageState(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
+  for (si = num_stages; si < _num_active_texture_stages; si++) {
+    _d3d_device->SetTextureStageState(si, D3DTSS_COLOROP, D3DTOP_DISABLE);
   }
 
   // Save the count of texture stages for next time.

+ 60 - 44
panda/src/dxgsg9/dxGeomMunger9.cxx

@@ -133,37 +133,45 @@ munge_format_impl(const GeomVertexFormat *orig,
   }
 
   // To support multitexture, we will need to add all of the relevant
-  // texcoord types, and in the correct order.
+  // texcoord types, and in the order specified by the TextureAttrib.
 
   // Now set up each of the active texture coordinate stages--or at
   // least those for which we're not generating texture coordinates
   // automatically.
 
-  // Now copy all of the texture coordinates in, in order by stage
-  // index.  But we have to reuse previous columns.
   if (_filtered_texture != (TextureAttrib *)NULL) {
-    typedef pset<const InternalName *> UsedStages;
-    UsedStages used_stages;
-
-    int num_stages = _filtered_texture->get_num_on_stages();
-    for (int i = 0; i < num_stages; ++i) {
-      TextureStage *stage = _filtered_texture->get_on_stage(i);
+    int num_stages = _filtered_texture->get_num_on_ff_stages();
+    vector_int ff_tc_index(num_stages, 0);
+
+    // Be sure we add the texture coordinates in the right order, as
+    // specified by the attrib.  To ensure this, we first walk through
+    // the stages of the attrib and get the index numbers in the
+    // appropriate order.
+    int si, tc_index;
+    for (si = 0; si < num_stages; ++si) {
+      int tc_index = _filtered_texture->get_ff_tc_index(si);
+      ff_tc_index[tc_index] = si;
+    }
 
+    // Now walk through the texture coordinates in the order they will
+    // appear on the final geometry.  For each one, get the texture
+    // coordinate name from the associated stage.
+    for (tc_index = 0; tc_index < num_stages; ++tc_index) {
+      si = ff_tc_index[tc_index];
+      TextureStage *stage = _filtered_texture->get_on_ff_stage(si);
       InternalName *name = stage->get_texcoord_name();
-      if (used_stages.insert(name).second) {
-        // This is the first time we've encountered this texcoord name.
-        const GeomVertexColumn *texcoord_type = orig->get_column(name);
-
-        if (texcoord_type != (const GeomVertexColumn *)NULL) {
-          new_array_format->add_column
-            (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
-        } else {
-          // We have to add something as a placeholder, even if the
-          // texture coordinates aren't defined.
-          new_array_format->add_column(name, 2, NT_float32, C_texcoord);
-        }
-        new_format->remove_column(name);
+
+      const GeomVertexColumn *texcoord_type = orig->get_column(name);
+
+      if (texcoord_type != (const GeomVertexColumn *)NULL) {
+        new_array_format->add_column
+          (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
+      } else {
+        // We have to add something as a placeholder, even if the
+        // texture coordinates aren't defined.
+        new_array_format->add_column(name, 2, NT_float32, C_texcoord);
       }
+      new_format->remove_column(name);
     }
   }
 
@@ -216,37 +224,45 @@ premunge_format_impl(const GeomVertexFormat *orig) {
   }
 
   // To support multitexture, we will need to add all of the relevant
-  // texcoord types, and in the correct order.
+  // texcoord types, and in the order specified by the TextureAttrib.
 
   // Now set up each of the active texture coordinate stages--or at
   // least those for which we're not generating texture coordinates
   // automatically.
 
-  // Now copy all of the texture coordinates in, in order by stage
-  // index.  But we have to reuse previous columns.
   if (_filtered_texture != (TextureAttrib *)NULL) {
-    typedef pset<const InternalName *> UsedStages;
-    UsedStages used_stages;
-
-    int num_stages = _filtered_texture->get_num_on_stages();
-    for (int i = 0; i < num_stages; ++i) {
-      TextureStage *stage = _filtered_texture->get_on_stage(i);
+    int num_stages = _filtered_texture->get_num_on_ff_stages();
+    vector_int ff_tc_index(num_stages, 0);
+
+    // Be sure we add the texture coordinates in the right order, as
+    // specified by the attrib.  To ensure this, we first walk through
+    // the stages of the attrib and get the index numbers in the
+    // appropriate order.
+    int si, tc_index;
+    for (si = 0; si < num_stages; ++si) {
+      int tc_index = _filtered_texture->get_ff_tc_index(si);
+      ff_tc_index[tc_index] = si;
+    }
 
+    // Now walk through the texture coordinates in the order they will
+    // appear on the final geometry.  For each one, get the texture
+    // coordinate name from the associated stage.
+    for (tc_index = 0; tc_index < num_stages; ++tc_index) {
+      si = ff_tc_index[tc_index];
+      TextureStage *stage = _filtered_texture->get_on_ff_stage(si);
       InternalName *name = stage->get_texcoord_name();
-      if (used_stages.insert(name).second) {
-        // This is the first time we've encountered this texcoord name.
-        const GeomVertexColumn *texcoord_type = orig->get_column(name);
-
-        if (texcoord_type != (const GeomVertexColumn *)NULL) {
-          new_array_format->add_column
-            (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
-        } else {
-          // We have to add something as a placeholder, even if the
-          // texture coordinates aren't defined.
-          new_array_format->add_column(name, 2, NT_float32, C_texcoord);
-        }
-        new_format->remove_column(name);
+
+      const GeomVertexColumn *texcoord_type = orig->get_column(name);
+
+      if (texcoord_type != (const GeomVertexColumn *)NULL) {
+        new_array_format->add_column
+          (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
+      } else {
+        // We have to add something as a placeholder, even if the
+        // texture coordinates aren't defined.
+        new_array_format->add_column(name, 2, NT_float32, C_texcoord);
       }
+      new_format->remove_column(name);
     }
   }
 

+ 37 - 48
panda/src/dxgsg9/dxGraphicsStateGuardian9.cxx

@@ -3882,32 +3882,21 @@ update_standard_texture_bindings() {
 
   // We have to match up the texcoord stage index to the order written
   // out by the DXGeomMunger.  This means the texcoord names are
-  // written in the order they are referenced by the TextureAttrib,
-  // except that if a name is repeated its index number is reused from
-  // the first time.
-  typedef pmap<const InternalName *, int> UsedTexcoordIndex;
-  UsedTexcoordIndex used_texcoord_index;
+  // written in the order indicated by the TextureAttrib.
+
+  int si;
+  for (si = 0; si < num_stages; si++) {
+    TextureStage *stage = _effective_texture->get_on_ff_stage(si);
+    int texcoord_index = _effective_texture->get_ff_tc_index(si);
 
-  int i;
-  for (i = 0; i < num_stages; i++) {
-    TextureStage *stage = _effective_texture->get_on_ff_stage(i);
     Texture *texture = _effective_texture->get_on_texture(stage);
     nassertv(texture != (Texture *)NULL);
 
-    const InternalName *name = stage->get_texcoord_name();
-
-    // This pair of lines will get the next consecutive texcoord index
-    // number if this is the first time we have referenced this
-    // particular texcoord name; otherwise, it will return the same
-    // index number it returned before.
-    UsedTexcoordIndex::iterator ti = used_texcoord_index.insert(UsedTexcoordIndex::value_type(name, (int)used_texcoord_index.size())).first;
-    int texcoord_index = (*ti).second;
-
     // We always reissue every stage in DX, just in case the texcoord
     // index or texgen mode or some other property has changed.
     TextureContext *tc = texture->prepare_now(_prepared_objects, this);
-    apply_texture(i, tc);
-    set_texture_blend_mode(i, stage);
+    apply_texture(si, tc);
+    set_texture_blend_mode(si, stage);
 
     int texcoord_dimensions = 2;
 
@@ -3923,13 +3912,13 @@ update_standard_texture_bindings() {
     switch (mode) {
     case TexGenAttrib::M_off:
     case TexGenAttrib::M_light_vector:
-      set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX, texcoord_index);
+      set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
       break;
 
     case TexGenAttrib::M_eye_sphere_map:
       {
-        set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX,
-                                          texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
+        set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
+                                texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
         // This texture matrix, applied on top of the texcoord
         // computed by D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR,
         // approximates the effect produced by OpenGL's GL_SPHERE_MAP.
@@ -3949,8 +3938,8 @@ update_standard_texture_bindings() {
       // transform.  In the case of a vector, we should not apply the
       // pos component of the transform.
       {
-        set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX,
-                                          texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
+        set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
+                                texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
         texcoord_dimensions = 3;
         CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
         tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3f::zero()));
@@ -3958,8 +3947,8 @@ update_standard_texture_bindings() {
       break;
 
     case TexGenAttrib::M_eye_cube_map:
-      set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX,
-                                        texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
+      set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
+                              texcoord_index | D3DTSS_TCI_CAMERASPACEREFLECTIONVECTOR);
       tex_mat = tex_mat->compose(_inv_cs_transform);
       texcoord_dimensions = 3;
       break;
@@ -3970,8 +3959,8 @@ update_standard_texture_bindings() {
       // the case of a normal, we should not apply the pos component
       // of the transform.
       {
-        set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX,
-                                          texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
+        set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
+                                texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
         texcoord_dimensions = 3;
         CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
         tex_mat = tex_mat->compose(camera_transform->set_pos(LVecBase3f::zero()));
@@ -3979,8 +3968,8 @@ update_standard_texture_bindings() {
       break;
 
     case TexGenAttrib::M_eye_normal:
-      set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX,
-                                        texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
+      set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
+                              texcoord_index | D3DTSS_TCI_CAMERASPACENORMAL);
       texcoord_dimensions = 3;
       tex_mat = tex_mat->compose(_inv_cs_transform);
       break;
@@ -3990,8 +3979,8 @@ update_standard_texture_bindings() {
       // coordinates to world coordinates; i.e. apply the
       // camera transform.
       {
-        set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX,
-                                          texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
+        set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
+                                texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
         texcoord_dimensions = 3;
         CPT(TransformState) camera_transform = _scene_setup->get_camera_transform()->compose(_inv_cs_transform);
         tex_mat = tex_mat->compose(camera_transform);
@@ -3999,14 +3988,14 @@ update_standard_texture_bindings() {
       break;
 
     case TexGenAttrib::M_eye_position:
-      set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX,
-                                        texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
+      set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
+                              texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
       texcoord_dimensions = 3;
       tex_mat = tex_mat->compose(_inv_cs_transform);
       break;
 
     case TexGenAttrib::M_point_sprite:
-      set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX, texcoord_index);
+      set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX, texcoord_index);
       any_point_sprite = true;
       break;
 
@@ -4022,7 +4011,7 @@ update_standard_texture_bindings() {
       // that there are 3-d texture coordinates, because of the
       // 3-component texture coordinate in get_constant_value().
       {
-        set_texture_stage_state(i, D3DTSS_TEXCOORDINDEX,
+        set_texture_stage_state(si, D3DTSS_TEXCOORDINDEX,
                                 texcoord_index | D3DTSS_TCI_CAMERASPACEPOSITION);
         texcoord_dimensions = 3;
 
@@ -4045,36 +4034,36 @@ update_standard_texture_bindings() {
               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());
-        set_texture_stage_state(i, D3DTSS_TEXTURETRANSFORMFLAGS,
-                                          D3DTTFF_COUNT2);
+        _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)m.get_data());
+        set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
+                                D3DTTFF_COUNT2);
       } else {
         LMatrix4f m = tex_mat->get_mat();
-        _d3d_device->SetTransform(get_tex_mat_sym(i), (D3DMATRIX *)m.get_data());
+        _d3d_device->SetTransform(get_tex_mat_sym(si), (D3DMATRIX *)m.get_data());
         DWORD transform_flags = texcoord_dimensions;
         if (m.get_col(3) != LVecBase4f(0.0f, 0.0f, 0.0f, 1.0f)) {
           // If we have a projected texture matrix, we also need to
           // set D3DTTFF_COUNT4.
           transform_flags = D3DTTFF_COUNT4 | D3DTTFF_PROJECTED;
         }
-        set_texture_stage_state(i, D3DTSS_TEXTURETRANSFORMFLAGS,
-                                          transform_flags);
+        set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
+                                transform_flags);
       }
 
     } else {
-      set_texture_stage_state(i, D3DTSS_TEXTURETRANSFORMFLAGS,
-                                        D3DTTFF_DISABLE);
+      set_texture_stage_state(si, D3DTSS_TEXTURETRANSFORMFLAGS,
+                              D3DTTFF_DISABLE);
       // For some reason, "disabling" texture coordinate transforms
       // doesn't seem to be sufficient.  We'll load an identity matrix
       // to underscore the point.
-      _d3d_device->SetTransform(get_tex_mat_sym(i), &_d3d_ident_mat);
+      _d3d_device->SetTransform(get_tex_mat_sym(si), &_d3d_ident_mat);
     }
   }
 
   // Disable the texture stages that are no longer used.
-  for (i = num_stages; i < _num_active_texture_stages; i++) {
-    set_texture_stage_state(i, D3DTSS_COLOROP, D3DTOP_DISABLE);
-    _d3d_device->SetTexture(i, NULL);
+  for (si = num_stages; si < _num_active_texture_stages; si++) {
+    set_texture_stage_state(si, D3DTSS_COLOROP, D3DTOP_DISABLE);
+    _d3d_device->SetTexture(si, NULL);
   }
 
   // Save the count of texture stages for next time.

+ 16 - 0
panda/src/pgraph/textureAttrib.I

@@ -131,6 +131,22 @@ get_on_ff_stage(int n) const {
   return _on_ff_stages[n];
 }
 
+////////////////////////////////////////////////////////////////////
+//     Function: TextureAttrib::get_ff_tc_index
+//       Access: Published
+//  Description: For each TextureStage listed in get_on_ff_stage(),
+//               this returns a unique index number for the texture
+//               coordinate name used by that TextureStage.  It is
+//               guaranteed to remain the same index number for each
+//               texcoord name, even if the texture render order
+//               changes.
+////////////////////////////////////////////////////////////////////
+INLINE int TextureAttrib::
+get_ff_tc_index(int n) const {
+  nassertr(n >= 0 && n < (int)_ff_tc_index.size(), 0);
+  return _ff_tc_index[n];
+}
+
 ////////////////////////////////////////////////////////////////////
 //     Function: TextureAttrib::has_on_stage
 //       Access: Published

+ 41 - 3
panda/src/pgraph/textureAttrib.cxx

@@ -19,6 +19,7 @@
 #include "textureAttrib.h"
 #include "attribSlots.h"
 #include "graphicsStateGuardianBase.h"
+#include "internalName.h"
 #include "bamReader.h"
 #include "bamWriter.h"
 #include "datagram.h"
@@ -846,15 +847,52 @@ fillin(DatagramIterator &scan, BamReader *manager) {
 ////////////////////////////////////////////////////////////////////
 void TextureAttrib::
 sort_on_stages() {
+  // First, we have to build up the tc_index mapping.  We need a
+  // unique number for each different texcoord name for the various
+  // TextureStages.
+
+  // It's important that this assignment not be based on the whims of
+  // render order--it mustn't change arbitrarily--so we must first
+  // sort the on_stages list into pointer order for this purpose.
+  sort(_on_stages.begin(), _on_stages.end());
+
+  typedef pmap<const InternalName *, int> UsedTexcoordIndex;
+  UsedTexcoordIndex used_texcoord_index;
+
+  typedef pmap<const TextureStage *, int> TexcoordMap;
+  TexcoordMap tc_map;
+
+  OnStages::const_iterator osi;
+  for (osi = _on_stages.begin(); osi != _on_stages.end(); ++osi) {
+    TextureStage *stage = (*osi);
+    if (stage->is_fixed_function()) {
+      const InternalName *name = stage->get_texcoord_name();
+
+      // This pair of lines will get the next consecutive texcoord index
+      // number if this is the first time we have referenced this
+      // particular texcoord name; otherwise, it will return the same
+      // index number it returned before.
+      UsedTexcoordIndex::iterator ti = used_texcoord_index.insert(UsedTexcoordIndex::value_type(name, (int)used_texcoord_index.size())).first;
+      int texcoord_index = (*ti).second;
+
+      tc_map[stage] = texcoord_index;
+    }
+  }
+
+  // Now we can sort the on_stages map into render order.
   sort(_on_stages.begin(), _on_stages.end(), IndirectLess<TextureStage>());
 
   _sort_seq = TextureStage::get_sort_seq();
 
   _on_ff_stages.clear();
-  OnStages::const_iterator osi;
+  _ff_tc_index.clear();
+
   for (osi = _on_stages.begin(); osi != _on_stages.end(); ++osi) {
-    if ((*osi)->is_fixed_function()) {
-      _on_ff_stages.push_back(*osi);
+    TextureStage *stage = (*osi);
+    if (stage->is_fixed_function()) {
+      _on_ff_stages.push_back(stage);
+      int texcoord_index = tc_map[stage];
+      _ff_tc_index.push_back(texcoord_index);
     }
   }
   

+ 3 - 0
panda/src/pgraph/textureAttrib.h

@@ -28,6 +28,7 @@
 #include "indirectLess.h"
 #include "geom.h"
 #include "ordered_vector.h"
+#include "vector_int.h"
 
 ////////////////////////////////////////////////////////////////////
 //       Class : TextureAttrib
@@ -60,6 +61,7 @@ PUBLISHED:
   INLINE TextureStage *get_on_stage(int n) const;
   INLINE int get_num_on_ff_stages() const;
   INLINE TextureStage *get_on_ff_stage(int n) const;
+  INLINE int get_ff_tc_index(int n) const;
   INLINE bool has_on_stage(TextureStage *stage) const;
   INLINE Texture *get_on_texture(TextureStage *stage) const;
 
@@ -103,6 +105,7 @@ private:
   typedef Geom::ActiveTextureStages OnStages;
   OnStages _on_stages;
   OnStages _on_ff_stages;
+  vector_int _ff_tc_index;
   
   typedef ov_set<TextureStage *> OffStages;
   OffStages _off_stages;