dxGeomMunger8.cxx

00001 // Filename: dxGeomMunger8.cxx
00002 // Created by:  drose (11Mar05)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "dxGeomMunger8.h"
00016 #include "geomVertexReader.h"
00017 #include "geomVertexWriter.h"
00018 #include "config_dxgsg8.h"
00019 
00020 GeomMunger *DXGeomMunger8::_deleted_chain = NULL;
00021 TypeHandle DXGeomMunger8::_type_handle;
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: DXGeomMunger8::Destructor
00025 //       Access: Public, Virtual
00026 //  Description: 
00027 ////////////////////////////////////////////////////////////////////
00028 DXGeomMunger8::
00029 ~DXGeomMunger8() {
00030   if (_reffed_filtered_texture) {
00031     unref_delete(_filtered_texture);
00032     _reffed_filtered_texture = false;
00033   }
00034 }
00035 
00036 ////////////////////////////////////////////////////////////////////
00037 //     Function: DXGeomMunger8::wp_callback
00038 //       Access: Public, Virtual
00039 //  Description: This callback is set to be made whenever the
00040 //               associated _texture or _tex_gen attributes are
00041 //               destructed, in which case the GeomMunger is invalid
00042 //               and should no longer be used.
00043 ////////////////////////////////////////////////////////////////////
00044 void DXGeomMunger8::
00045 wp_callback(void *) {
00046   unregister_myself();
00047 
00048   if (_reffed_filtered_texture) {
00049     unref_delete(_filtered_texture);
00050     _reffed_filtered_texture = false;
00051   }
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: DXGeomMunger8::munge_format_impl
00056 //       Access: Protected, Virtual
00057 //  Description: Given a source GeomVertexFormat, converts it if
00058 //               necessary to the appropriate format for rendering.
00059 ////////////////////////////////////////////////////////////////////
00060 CPT(GeomVertexFormat) DXGeomMunger8::
00061 munge_format_impl(const GeomVertexFormat *orig,
00062                   const GeomVertexAnimationSpec &animation) {
00063   if (dxgsg8_cat.is_debug()) {
00064     if (animation.get_animation_type() != AT_none) {
00065       dxgsg8_cat.debug()
00066         << "preparing animation type " << animation << " for " << *orig
00067         << "\n";
00068     }
00069   }
00070   // We have to build a completely new format that includes only the
00071   // appropriate components, in the appropriate order, in just one
00072   // array.
00073   PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig);
00074   new_format->set_animation(animation);
00075   PT(GeomVertexArrayFormat) new_array_format = new GeomVertexArrayFormat;
00076 
00077   const GeomVertexColumn *vertex_type = orig->get_vertex_column();
00078   const GeomVertexColumn *normal_type = orig->get_normal_column(); 
00079   const GeomVertexColumn *color_type = orig->get_color_column();
00080 
00081   if (vertex_type != (const GeomVertexColumn *)NULL) {
00082     new_array_format->add_column
00083       (InternalName::get_vertex(), 3, NT_float32,
00084        vertex_type->get_contents());
00085     new_format->remove_column(vertex_type->get_name());
00086 
00087   } else {
00088     // If we don't have a vertex type, not much we can do.
00089     return orig;
00090   }
00091 
00092   if (animation.get_animation_type() == AT_hardware &&
00093       animation.get_num_transforms() > 0) {
00094     if (animation.get_num_transforms() > 1) {
00095       // If we want hardware animation, we need to reserve space for the
00096       // blend weights.
00097       new_array_format->add_column
00098         (InternalName::get_transform_weight(), animation.get_num_transforms() - 1,
00099          NT_float32, C_other);
00100     }
00101       
00102     if (animation.get_indexed_transforms()) {
00103       // Also, if we'll be indexing into the transform table, reserve
00104       // space for the index.
00105       new_array_format->add_column
00106         (InternalName::get_transform_index(), 1,
00107          NT_packed_dcba, C_index);
00108     }                                    
00109 
00110     // Make sure the old weights and indices are removed, just in
00111     // case.
00112     new_format->remove_column(InternalName::get_transform_weight());
00113     new_format->remove_column(InternalName::get_transform_index());
00114 
00115     // And we don't need the transform_blend table any more.
00116     new_format->remove_column(InternalName::get_transform_blend());
00117   }
00118 
00119   if (normal_type != (const GeomVertexColumn *)NULL) {
00120     new_array_format->add_column
00121       (InternalName::get_normal(), 3, NT_float32, C_vector);
00122     new_format->remove_column(normal_type->get_name());
00123   }
00124 
00125   if (color_type != (const GeomVertexColumn *)NULL) {
00126     new_array_format->add_column
00127       (InternalName::get_color(), 1, NT_packed_dabc, C_color);
00128     new_format->remove_column(color_type->get_name());
00129   }
00130 
00131   // To support multitexture, we will need to add all of the relevant
00132   // texcoord types, and in the order specified by the TextureAttrib.
00133 
00134   // Now set up each of the active texture coordinate stages--or at
00135   // least those for which we're not generating texture coordinates
00136   // automatically.
00137 
00138   if (_filtered_texture != (TextureAttrib *)NULL) {
00139     int num_stages = _filtered_texture->get_num_on_ff_stages();
00140     vector_int ff_tc_index(num_stages, 0);
00141 
00142     // Be sure we add the texture coordinates in the right order, as
00143     // specified by the attrib.  To ensure this, we first walk through
00144     // the stages of the attrib and get the index numbers in the
00145     // appropriate order.
00146     int si, tc_index;
00147     int max_tc_index = -1;
00148     for (si = 0; si < num_stages; ++si) {
00149       int tc_index = _filtered_texture->get_ff_tc_index(si);
00150       nassertr(tc_index < num_stages, orig);
00151       ff_tc_index[tc_index] = si;
00152       max_tc_index = max(tc_index, max_tc_index);
00153     }
00154 
00155     // Now walk through the texture coordinates in the order they will
00156     // appear on the final geometry.  For each one, get the texture
00157     // coordinate name from the associated stage.
00158     for (tc_index = 0; tc_index <= max_tc_index; ++tc_index) {
00159       si = ff_tc_index[tc_index];
00160       TextureStage *stage = _filtered_texture->get_on_ff_stage(si);
00161       InternalName *name = stage->get_texcoord_name();
00162 
00163       const GeomVertexColumn *texcoord_type = orig->get_column(name);
00164 
00165       if (texcoord_type != (const GeomVertexColumn *)NULL) {
00166         new_array_format->add_column
00167           (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
00168       } else {
00169         // We have to add something as a placeholder, even if the
00170         // texture coordinates aren't defined.
00171         new_array_format->add_column(name, 2, NT_float32, C_texcoord);
00172       }
00173       new_format->remove_column(name);
00174     }
00175   }
00176 
00177   // Make sure the FVF-style array we just built up is first in the
00178   // list.
00179   new_format->insert_array(0, new_array_format);
00180 
00181   return GeomVertexFormat::register_format(new_format);
00182 }
00183 
00184 ////////////////////////////////////////////////////////////////////
00185 //     Function: DXGeomMunger8::premunge_format_impl
00186 //       Access: Protected, Virtual
00187 //  Description: Given a source GeomVertexFormat, converts it if
00188 //               necessary to the appropriate format for rendering.
00189 ////////////////////////////////////////////////////////////////////
00190 CPT(GeomVertexFormat) DXGeomMunger8::
00191 premunge_format_impl(const GeomVertexFormat *orig) {
00192   // We have to build a completely new format that includes only the
00193   // appropriate components, in the appropriate order, in just one
00194   // array.
00195   PT(GeomVertexFormat) new_format = new GeomVertexFormat(*orig);
00196   PT(GeomVertexArrayFormat) new_array_format = new GeomVertexArrayFormat;
00197 
00198   const GeomVertexColumn *vertex_type = orig->get_vertex_column();
00199   const GeomVertexColumn *normal_type = orig->get_normal_column(); 
00200   const GeomVertexColumn *color_type = orig->get_color_column();
00201 
00202   if (vertex_type != (const GeomVertexColumn *)NULL) {
00203     new_array_format->add_column
00204       (InternalName::get_vertex(), 3, NT_float32,
00205        vertex_type->get_contents());
00206     new_format->remove_column(vertex_type->get_name());
00207 
00208   } else {
00209     // If we don't have a vertex type, not much we can do.
00210     return orig;
00211   }
00212 
00213   if (normal_type != (const GeomVertexColumn *)NULL) {
00214     new_array_format->add_column
00215       (InternalName::get_normal(), 3, NT_float32, C_vector);
00216     new_format->remove_column(normal_type->get_name());
00217   }
00218 
00219   if (color_type != (const GeomVertexColumn *)NULL) {
00220     new_array_format->add_column
00221       (InternalName::get_color(), 1, NT_packed_dabc, C_color);
00222     new_format->remove_column(color_type->get_name());
00223   }
00224 
00225   // To support multitexture, we will need to add all of the relevant
00226   // texcoord types, and in the order specified by the TextureAttrib.
00227 
00228   // Now set up each of the active texture coordinate stages--or at
00229   // least those for which we're not generating texture coordinates
00230   // automatically.
00231 
00232   if (_filtered_texture != (TextureAttrib *)NULL) {
00233     int num_stages = _filtered_texture->get_num_on_ff_stages();
00234     vector_int ff_tc_index(num_stages, 0);
00235 
00236     // Be sure we add the texture coordinates in the right order, as
00237     // specified by the attrib.  To ensure this, we first walk through
00238     // the stages of the attrib and get the index numbers in the
00239     // appropriate order.
00240     int si, tc_index;
00241     int max_tc_index = -1;
00242     for (si = 0; si < num_stages; ++si) {
00243       int tc_index = _filtered_texture->get_ff_tc_index(si);
00244       nassertr(tc_index < num_stages, orig);
00245       ff_tc_index[tc_index] = si;
00246       max_tc_index = max(tc_index, max_tc_index);
00247     }
00248 
00249     // Now walk through the texture coordinates in the order they will
00250     // appear on the final geometry.  For each one, get the texture
00251     // coordinate name from the associated stage.
00252     for (tc_index = 0; tc_index <= max_tc_index; ++tc_index) {
00253       si = ff_tc_index[tc_index];
00254       TextureStage *stage = _filtered_texture->get_on_ff_stage(si);
00255       InternalName *name = stage->get_texcoord_name();
00256 
00257       const GeomVertexColumn *texcoord_type = orig->get_column(name);
00258 
00259       if (texcoord_type != (const GeomVertexColumn *)NULL) {
00260         new_array_format->add_column
00261           (name, texcoord_type->get_num_values(), NT_float32, C_texcoord);
00262       } else {
00263         // We have to add something as a placeholder, even if the
00264         // texture coordinates aren't defined.
00265         new_array_format->add_column(name, 2, NT_float32, C_texcoord);
00266       }
00267       new_format->remove_column(name);
00268     }
00269   }
00270 
00271   // Make sure the FVF-style array we just built up is first in the
00272   // list.
00273   new_format->insert_array(0, new_array_format);
00274 
00275   return GeomVertexFormat::register_format(new_format);
00276 }
00277 
00278 ////////////////////////////////////////////////////////////////////
00279 //     Function: DXGeomMunger8::compare_to_impl
00280 //       Access: Protected, Virtual
00281 //  Description: Called to compare two GeomMungers who are known to be
00282 //               of the same type, for an apples-to-apples comparison.
00283 //               This will never be called on two pointers of a
00284 //               different type.
00285 ////////////////////////////////////////////////////////////////////
00286 int DXGeomMunger8::
00287 compare_to_impl(const GeomMunger *other) const {
00288   const DXGeomMunger8 *om = DCAST(DXGeomMunger8, other);
00289   if (_filtered_texture != om->_filtered_texture) {
00290     return _filtered_texture < om->_filtered_texture ? -1 : 1;
00291   }
00292   if (_tex_gen != om->_tex_gen) {
00293     return _tex_gen < om->_tex_gen ? -1 : 1;
00294   }
00295 
00296   return StandardMunger::compare_to_impl(other);
00297 }
00298 
00299 ////////////////////////////////////////////////////////////////////
00300 //     Function: DXGeomMunger8::geom_compare_to_impl
00301 //       Access: Protected, Virtual
00302 //  Description: Called to compare two GeomMungers who are known to be
00303 //               of the same type, for an apples-to-apples comparison.
00304 //               This will never be called on two pointers of a
00305 //               different type.
00306 ////////////////////////////////////////////////////////////////////
00307 int DXGeomMunger8::
00308 geom_compare_to_impl(const GeomMunger *other) const {
00309   // Unlike GLGeomMunger, we do consider _filtered_texture and
00310   // _tex_gen important for this purpose, since they control the
00311   // number and order of texture coordinates we might put into the
00312   // FVF.
00313   const DXGeomMunger8 *om = DCAST(DXGeomMunger8, other);
00314   if (_filtered_texture != om->_filtered_texture) {
00315     return _filtered_texture < om->_filtered_texture ? -1 : 1;
00316   }
00317   if (_tex_gen != om->_tex_gen) {
00318     return _tex_gen < om->_tex_gen ? -1 : 1;
00319   }
00320 
00321   return StandardMunger::geom_compare_to_impl(other);
00322 }