Panda3D

geomTransformer.cxx

00001 // Filename: geomTransformer.cxx
00002 // Created by:  drose (14Mar02)
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 "geomTransformer.h"
00016 #include "sceneGraphReducer.h"
00017 #include "geomNode.h"
00018 #include "geom.h"
00019 #include "geomVertexRewriter.h"
00020 #include "renderState.h"
00021 #include "transformTable.h"
00022 #include "transformBlendTable.h"
00023 #include "sliderTable.h"
00024 #include "pStatCollector.h"
00025 #include "pStatTimer.h"
00026 #include "vector_int.h"
00027 #include "userVertexTransform.h"
00028 #include "geomMunger.h"
00029 #include "texture.h"
00030 #include "texturePeeker.h"
00031 #include "config_pgraph.h"
00032 
00033 PStatCollector GeomTransformer::_apply_vertex_collector("*:Flatten:apply:vertex");
00034 PStatCollector GeomTransformer::_apply_texcoord_collector("*:Flatten:apply:texcoord");
00035 PStatCollector GeomTransformer::_apply_set_color_collector("*:Flatten:apply:set color");
00036 PStatCollector GeomTransformer::_apply_scale_color_collector("*:Flatten:apply:scale color");
00037 PStatCollector GeomTransformer::_apply_texture_color_collector("*:Flatten:apply:texture color");
00038 PStatCollector GeomTransformer::_apply_set_format_collector("*:Flatten:apply:set format");
00039 
00040 TypeHandle GeomTransformer::NewCollectedData::_type_handle;
00041 
00042 ////////////////////////////////////////////////////////////////////
00043 //     Function: GeomTransformer::Constructor
00044 //       Access: Public
00045 //  Description:
00046 ////////////////////////////////////////////////////////////////////
00047 GeomTransformer::
00048 GeomTransformer() :
00049   // The default value here comes from the Config file.
00050   _max_collect_vertices(max_collect_vertices)
00051 {
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: GeomTransformer::Copy Constructor
00056 //       Access: Public
00057 //  Description:
00058 ////////////////////////////////////////////////////////////////////
00059 GeomTransformer::
00060 GeomTransformer(const GeomTransformer &copy) :
00061   _max_collect_vertices(copy._max_collect_vertices)
00062 {
00063 }
00064 
00065 ////////////////////////////////////////////////////////////////////
00066 //     Function: GeomTransformer::Destructor
00067 //       Access: Public
00068 //  Description:
00069 ////////////////////////////////////////////////////////////////////
00070 GeomTransformer::
00071 ~GeomTransformer() {
00072   finish_collect(false);
00073 }
00074 
00075 ////////////////////////////////////////////////////////////////////
00076 //     Function: GeomTransformer::register_vertices
00077 //       Access: Public
00078 //  Description: Records the association of the Geom with its
00079 //               GeomVertexData, for the purpose of later removing
00080 //               unused vertices.
00081 ////////////////////////////////////////////////////////////////////
00082 void GeomTransformer::
00083 register_vertices(Geom *geom, bool might_have_unused) {
00084   VertexDataAssoc &assoc = _vdata_assoc[geom->get_vertex_data()];
00085   assoc._geoms.push_back(geom);
00086   if (might_have_unused) {
00087     assoc._might_have_unused = true;
00088   }
00089 }
00090 
00091 ////////////////////////////////////////////////////////////////////
00092 //     Function: GeomTransformer::register_vertices
00093 //       Access: Public
00094 //  Description: Records the association of the Geom with its
00095 //               GeomVertexData, for the purpose of later removing
00096 //               unused vertices.
00097 ////////////////////////////////////////////////////////////////////
00098 void GeomTransformer::
00099 register_vertices(GeomNode *node, bool might_have_unused) {
00100   Thread *current_thread = Thread::get_current_thread();
00101   OPEN_ITERATE_CURRENT_AND_UPSTREAM(node->_cycler, current_thread) {
00102     GeomNode::CDStageWriter cdata(node->_cycler, pipeline_stage, current_thread);
00103     GeomNode::GeomList::iterator gi;
00104     PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
00105     for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00106       GeomNode::GeomEntry &entry = (*gi);
00107       PT(Geom) geom = entry._geom.get_write_pointer();
00108       register_vertices(geom, might_have_unused);
00109     }
00110   }
00111   CLOSE_ITERATE_CURRENT_AND_UPSTREAM(node->_cycler);
00112 }
00113 
00114 ////////////////////////////////////////////////////////////////////
00115 //     Function: GeomTransformer::transform_vertices
00116 //       Access: Public
00117 //  Description: Transforms the vertices and the normals in the
00118 //               indicated Geom by the indicated matrix.  Returns true
00119 //               if the Geom was changed, false otherwise.
00120 ////////////////////////////////////////////////////////////////////
00121 bool GeomTransformer::
00122 transform_vertices(Geom *geom, const LMatrix4 &mat) {
00123   PStatTimer timer(_apply_vertex_collector);
00124 
00125   nassertr(geom != (Geom *)NULL, false);
00126   SourceVertices sv;
00127   sv._mat = mat;
00128   sv._vertex_data = geom->get_vertex_data();
00129   
00130   NewVertexData &new_data = _vertices[sv];
00131   if (new_data._vdata.is_null()) {
00132     // We have not yet converted these vertices.  Do so now.
00133     PT(GeomVertexData) new_vdata = new GeomVertexData(*sv._vertex_data);
00134     new_vdata->transform_vertices(mat);
00135     new_data._vdata = new_vdata;
00136   }
00137   
00138   geom->set_vertex_data(new_data._vdata);
00139   if (sv._vertex_data->get_ref_count() > 1) {
00140     _vdata_assoc[new_data._vdata]._might_have_unused = true;
00141     _vdata_assoc[sv._vertex_data]._might_have_unused = true;
00142   }
00143 
00144   return true;
00145 }
00146 
00147 
00148 ////////////////////////////////////////////////////////////////////
00149 //     Function: GeomTransformer::transform_vertices
00150 //       Access: Public
00151 //  Description: Transforms the vertices and the normals in all of the
00152 //               Geoms within the indicated GeomNode by the indicated
00153 //               matrix.  Does not destructively change Geoms;
00154 //               instead, a copy will be made of each Geom to be
00155 //               changed, in case multiple GeomNodes reference the
00156 //               same Geom. Returns true if the GeomNode was changed,
00157 //               false otherwise.
00158 ////////////////////////////////////////////////////////////////////
00159 bool GeomTransformer::
00160 transform_vertices(GeomNode *node, const LMatrix4 &mat) {
00161   bool any_changed = false;
00162 
00163   Thread *current_thread = Thread::get_current_thread();
00164   OPEN_ITERATE_CURRENT_AND_UPSTREAM(node->_cycler, current_thread) {
00165     GeomNode::CDStageWriter cdata(node->_cycler, pipeline_stage, current_thread);
00166     GeomNode::GeomList::iterator gi;
00167     PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
00168     for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00169       GeomNode::GeomEntry &entry = (*gi);
00170       PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy();
00171       if (transform_vertices(new_geom, mat)) {
00172         entry._geom = new_geom;
00173         any_changed = true;
00174       }
00175     }
00176   }
00177   CLOSE_ITERATE_CURRENT_AND_UPSTREAM(node->_cycler);
00178 
00179   if (any_changed) {
00180     node->mark_internal_bounds_stale();
00181   }
00182 
00183   return any_changed;
00184 }
00185 
00186 
00187 ////////////////////////////////////////////////////////////////////
00188 //     Function: GeomTransformer::transform_texcoords
00189 //       Access: Public
00190 //  Description: Transforms the texture coordinates in the indicated
00191 //               Geom by the indicated matrix.  Returns true if the
00192 //               Geom was changed, false otherwise.
00193 ////////////////////////////////////////////////////////////////////
00194 bool GeomTransformer::
00195 transform_texcoords(Geom *geom, const InternalName *from_name, 
00196                     InternalName *to_name, const LMatrix4 &mat) {
00197   PStatTimer timer(_apply_texcoord_collector);
00198 
00199   nassertr(geom != (Geom *)NULL, false);
00200 
00201   SourceTexCoords st;
00202   st._mat = mat;
00203   st._from = from_name;
00204   st._to = to_name;
00205   st._vertex_data = geom->get_vertex_data();
00206   
00207   NewVertexData &new_data = _texcoords[st];
00208   if (new_data._vdata.is_null()) {
00209     if (!st._vertex_data->has_column(from_name)) {
00210       // No from_name column; no change.
00211       return false;
00212     }
00213 
00214     PT(GeomVertexData) new_vdata;
00215     
00216     // We have not yet converted these texcoords.  Do so now.
00217     if (st._vertex_data->has_column(to_name)) {
00218       new_vdata = new GeomVertexData(*st._vertex_data);
00219     } else {
00220       const GeomVertexColumn *old_column = 
00221         st._vertex_data->get_format()->get_column(from_name);
00222       new_vdata = st._vertex_data->replace_column
00223         (to_name, old_column->get_num_components(),
00224          old_column->get_numeric_type(),
00225          old_column->get_contents());
00226     }
00227     
00228     CPT(GeomVertexFormat) format = new_vdata->get_format();
00229     
00230     GeomVertexWriter tdata(new_vdata, to_name);
00231     GeomVertexReader fdata(new_vdata, from_name);
00232     
00233     while (!fdata.is_at_end()) {
00234       const LPoint4 &coord = fdata.get_data4();
00235       tdata.set_data4(coord * mat);
00236     }
00237     new_data._vdata = new_vdata;
00238   }
00239   
00240   geom->set_vertex_data(new_data._vdata);
00241   if (st._vertex_data->get_ref_count() > 1) {
00242     _vdata_assoc[new_data._vdata]._might_have_unused = true;
00243     _vdata_assoc[st._vertex_data]._might_have_unused = true;
00244   }
00245 
00246   return true;
00247 }
00248 
00249 
00250 ////////////////////////////////////////////////////////////////////
00251 //     Function: GeomTransformer::transform_texcoords
00252 //       Access: Public
00253 //  Description: Transforms the texture coordinates in all of the
00254 //               Geoms within the indicated GeomNode by the indicated
00255 //               matrix.  Does not destructively change Geoms;
00256 //               instead, a copy will be made of each Geom to be
00257 //               changed, in case multiple GeomNodes reference the
00258 //               same Geom. Returns true if the GeomNode was changed,
00259 //               false otherwise.
00260 ////////////////////////////////////////////////////////////////////
00261 bool GeomTransformer::
00262 transform_texcoords(GeomNode *node, const InternalName *from_name,
00263                     InternalName *to_name, const LMatrix4 &mat) {
00264   bool any_changed = false;
00265 
00266   GeomNode::CDWriter cdata(node->_cycler);
00267   GeomNode::GeomList::iterator gi;
00268   PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
00269   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00270     GeomNode::GeomEntry &entry = (*gi);
00271     PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy();
00272     if (transform_texcoords(new_geom, from_name, to_name, mat)) {
00273       entry._geom = new_geom;
00274       any_changed = true;
00275     }
00276   }
00277 
00278   return any_changed;
00279 }
00280 
00281 
00282 ////////////////////////////////////////////////////////////////////
00283 //     Function: GeomTransformer::set_color
00284 //       Access: Public
00285 //  Description: Overrides the color indicated within the Geom with
00286 //               the given replacement color.  Returns true if the
00287 //               Geom was changed, false otherwise.
00288 ////////////////////////////////////////////////////////////////////
00289 bool GeomTransformer::
00290 set_color(Geom *geom, const LColor &color) {
00291   PStatTimer timer(_apply_set_color_collector);
00292 
00293   SourceColors sc;
00294   sc._color = color;
00295   sc._vertex_data = geom->get_vertex_data();
00296   
00297   NewVertexData &new_data = _fcolors[sc];
00298   if (new_data._vdata.is_null()) {
00299     // We have not yet converted these colors.  Do so now.
00300     if (sc._vertex_data->has_column(InternalName::get_color())) {
00301       new_data._vdata = sc._vertex_data->set_color(color);
00302     } else {
00303       new_data._vdata = sc._vertex_data->set_color
00304         (color, 1, Geom::NT_packed_dabc, Geom::C_color);
00305     }
00306   }
00307   
00308   geom->set_vertex_data(new_data._vdata);
00309   if (sc._vertex_data->get_ref_count() > 1) {
00310     _vdata_assoc[new_data._vdata]._might_have_unused = true;
00311     _vdata_assoc[sc._vertex_data]._might_have_unused = true;
00312   }
00313 
00314   return true;
00315 }
00316 
00317 
00318 ////////////////////////////////////////////////////////////////////
00319 //     Function: GeomTransformer::set_color
00320 //       Access: Public
00321 //  Description: Overrides the color indicated within the GeomNode
00322 //               with the given replacement color.  Returns true if
00323 //               any Geom in the GeomNode was changed, false
00324 //               otherwise.
00325 ////////////////////////////////////////////////////////////////////
00326 bool GeomTransformer::
00327 set_color(GeomNode *node, const LColor &color) {
00328   bool any_changed = false;
00329 
00330   GeomNode::CDWriter cdata(node->_cycler);
00331   GeomNode::GeomList::iterator gi;
00332   PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
00333   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00334     GeomNode::GeomEntry &entry = (*gi);
00335     PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy();
00336     if (set_color(new_geom, color)) {
00337       entry._geom = new_geom;
00338       any_changed = true;
00339     }
00340   }
00341 
00342   return any_changed;
00343 }
00344 
00345 ////////////////////////////////////////////////////////////////////
00346 //     Function: GeomTransformer::transform_colors
00347 //       Access: Public
00348 //  Description: Transforms the colors in the indicated Geom by the
00349 //               indicated scale.  Returns true if the Geom was
00350 //               changed, false otherwise.
00351 ////////////////////////////////////////////////////////////////////
00352 bool GeomTransformer::
00353 transform_colors(Geom *geom, const LVecBase4 &scale) {
00354   PStatTimer timer(_apply_scale_color_collector);
00355 
00356   nassertr(geom != (Geom *)NULL, false);
00357 
00358   SourceColors sc;
00359   sc._color = scale;
00360   sc._vertex_data = geom->get_vertex_data();
00361   
00362   NewVertexData &new_data = _tcolors[sc];
00363   if (new_data._vdata.is_null()) {
00364     // We have not yet converted these colors.  Do so now.
00365     if (sc._vertex_data->has_column(InternalName::get_color())) {
00366       new_data._vdata = sc._vertex_data->scale_color(scale);
00367     } else {
00368       new_data._vdata = sc._vertex_data->set_color
00369         (scale, 1, Geom::NT_packed_dabc, Geom::C_color);
00370     }
00371   }
00372   
00373   geom->set_vertex_data(new_data._vdata);
00374   if (sc._vertex_data->get_ref_count() > 1) {
00375     _vdata_assoc[new_data._vdata]._might_have_unused = true;
00376     _vdata_assoc[sc._vertex_data]._might_have_unused = true;
00377   }
00378 
00379   return true;
00380 }
00381 
00382 
00383 ////////////////////////////////////////////////////////////////////
00384 //     Function: GeomTransformer::transform_colors
00385 //       Access: Public
00386 //  Description: Transforms the colors in all of the Geoms within the
00387 //               indicated GeomNode by the indicated scale.  Does
00388 //               not destructively change Geoms; instead, a copy will
00389 //               be made of each Geom to be changed, in case multiple
00390 //               GeomNodes reference the same Geom. Returns true if
00391 //               the GeomNode was changed, false otherwise.
00392 ////////////////////////////////////////////////////////////////////
00393 bool GeomTransformer::
00394 transform_colors(GeomNode *node, const LVecBase4 &scale) {
00395   bool any_changed = false;
00396 
00397   GeomNode::CDWriter cdata(node->_cycler);
00398   GeomNode::GeomList::iterator gi;
00399   PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
00400   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00401     GeomNode::GeomEntry &entry = (*gi);
00402     PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy();
00403     if (transform_colors(new_geom, scale)) {
00404       entry._geom = new_geom;
00405       any_changed = true;
00406     }
00407   }
00408 
00409   return any_changed;
00410 }
00411 
00412 
00413 ////////////////////////////////////////////////////////////////////
00414 //     Function: GeomTransformer::apply_texture_colors
00415 //       Access: Public
00416 //  Description: Removes textures from Geoms by applying the texture
00417 //               colors to the vertices.  
00418 //
00419 //               See apply_texure_colors(GeomNode *, RenderState *).
00420 ////////////////////////////////////////////////////////////////////
00421 bool GeomTransformer::
00422 apply_texture_colors(Geom *geom, TextureStage *ts, Texture *tex, 
00423                      const TexMatrixAttrib *tma, const LColor &base_color,
00424                      bool keep_vertex_color) {
00425   PStatTimer timer(_apply_texture_color_collector);
00426 
00427   nassertr(geom != (Geom *)NULL, false);
00428 
00429   PT(TexturePeeker) peeker = tex->peek();
00430   if (peeker == (TexturePeeker *)NULL) {
00431     return false;
00432   }
00433 
00434   if (peeker->get_x_size() == 1 && 
00435       peeker->get_y_size() == 1 && 
00436       peeker->get_z_size() == 1) {
00437     // If it's just a one-pixel texture (e.g. a simple ram image),
00438     // don't bother scanning the UV's.  Just extract the color and
00439     // apply it.
00440     LColor color;
00441     peeker->lookup(color, 0.0f, 0.0f);
00442     color.set(color[0] * base_color[0],
00443               color[1] * base_color[1],
00444               color[2] * base_color[2],
00445               color[3] * base_color[3]);
00446     if (keep_vertex_color) {
00447       return transform_colors(geom, color);
00448     } else {
00449       return set_color(geom, color);
00450     }
00451   }
00452 
00453   bool got_mat = false;
00454   LMatrix4 mat = LMatrix4::ident_mat();
00455   if (tma != (TexMatrixAttrib *)NULL && tma->has_stage(ts)) {
00456     mat = tma->get_mat(ts);
00457     got_mat = !mat.almost_equal(LMatrix4::ident_mat());
00458   }
00459 
00460   // This version of the code just applied one overall flat color to
00461   // the entire mesh.  Turned out not to be good enough.  Instead,
00462   // we'll look up each vertex in the texture map and apply the
00463   // nearest color to the vertex.
00464   /*
00465   // Scan the UV's to get the used range.  This is particularly
00466   // necessary for palettized textures.
00467 
00468   LPoint3 min_point, max_point;
00469   bool found_any = false;
00470   geom->calc_tight_bounds(min_point, max_point, found_any,
00471                           geom->get_vertex_data(),
00472                           got_mat, mat,
00473                           ts->get_texcoord_name(),
00474                           Thread::get_current_thread());
00475   if (found_any) {
00476     // Now use that UV range to determine the overall color of the
00477     // geom's texture.
00478     LColor color;
00479     peeker->filter_rect(color, 
00480                         min_point[0], min_point[1], min_point[2],
00481                         max_point[0], max_point[1], max_point[2]);
00482     color.set(color[0] * base_color[0],
00483               color[1] * base_color[1],
00484               color[2] * base_color[2],
00485               color[3] * base_color[3]);
00486     if (keep_vertex_color) {
00487       return transform_colors(geom, color);
00488     } else {
00489       return set_color(geom, color);
00490     }
00491   }
00492 
00493   return false;
00494   */
00495 
00496   SourceTextureColors stc;
00497   stc._ts = ts;
00498   stc._tex = tex;
00499   stc._tma = tma;
00500   stc._base_color = base_color;
00501   stc._keep_vertex_color = keep_vertex_color;
00502   stc._vertex_data = geom->get_vertex_data();
00503   
00504   NewVertexData &new_data = _tex_colors[stc];
00505   if (new_data._vdata.is_null()) {
00506     // We have not yet applied these texture colors.  Do so now.
00507 
00508     PT(GeomVertexData) vdata;
00509 
00510     // Make sure the vdata has a color column.
00511     if (stc._vertex_data->has_column(InternalName::get_color())) {
00512       vdata = new GeomVertexData(*stc._vertex_data);
00513     } else {
00514       // Create a color column where there wasn't one before.
00515       vdata = new GeomVertexData(*stc._vertex_data->set_color
00516                                  (LColor(1.0f, 1.0f, 1.0f, 1.0f), 1, Geom::NT_packed_dabc, Geom::C_color));
00517       keep_vertex_color = false;
00518     }
00519     
00520     // Check whether it has 2-d or 3-d texture coordinates.
00521     bool tex3d = false;
00522     const GeomVertexColumn *column = vdata->get_format()->get_column(ts->get_texcoord_name());
00523     if (column == (GeomVertexColumn *)NULL) {
00524       return false;
00525     }
00526     if (column->get_num_components() >= 3) {
00527       tex3d = true;
00528     }
00529     
00530     // Now walk through the vertices and apply each color from the
00531     // texture as we go.
00532     if (keep_vertex_color) {
00533       // We want to modulate the existing vertex color.
00534       GeomVertexReader gtexcoord(vdata, ts->get_texcoord_name());
00535       GeomVertexRewriter gcolor(vdata, InternalName::get_color());
00536       
00537       if (got_mat || tex3d) {
00538         while (!gtexcoord.is_at_end()) {
00539           LTexCoord3 p = gtexcoord.get_data3();
00540           LColor c = gcolor.get_data4();
00541           p = p * mat;
00542           LColor color;
00543           peeker->lookup(color, p[0], p[1], p[2]);
00544           color.set(color[0] * base_color[0] * c[0],
00545                     color[1] * base_color[1] * c[1],
00546                     color[2] * base_color[2] * c[2],
00547                     color[3] * base_color[3] * c[3]);
00548           gcolor.set_data4(color);
00549         }
00550       } else {
00551         while (!gtexcoord.is_at_end()) {
00552           LTexCoord p = gtexcoord.get_data2();
00553           LColor c = gcolor.get_data4();
00554           LColor color;
00555           peeker->lookup(color, p[0], p[1]);
00556           color.set(color[0] * base_color[0] * c[0],
00557                     color[1] * base_color[1] * c[1],
00558                     color[2] * base_color[2] * c[2],
00559                     color[3] * base_color[3] * c[3]);
00560           gcolor.set_data4(color);
00561         }
00562       }
00563     } else {
00564       // We want to replace any existing vertex color.
00565       GeomVertexReader gtexcoord(vdata, ts->get_texcoord_name());
00566       GeomVertexWriter gcolor(vdata, InternalName::get_color());
00567       
00568       if (got_mat || tex3d) {
00569         while (!gtexcoord.is_at_end()) {
00570           LTexCoord3 p = gtexcoord.get_data3();
00571           p = p * mat;
00572           LColor color;
00573           peeker->lookup(color, p[0], p[1], p[2]);
00574           color.set(color[0] * base_color[0],
00575                     color[1] * base_color[1],
00576                     color[2] * base_color[2],
00577                     color[3] * base_color[3]);
00578           gcolor.set_data4(color);
00579         }
00580       } else {
00581         while (!gtexcoord.is_at_end()) {
00582           LTexCoord p = gtexcoord.get_data2();
00583           LColor color;
00584           peeker->lookup(color, p[0], p[1]);
00585           color.set(color[0] * base_color[0],
00586                     color[1] * base_color[1],
00587                     color[2] * base_color[2],
00588                     color[3] * base_color[3]);
00589           gcolor.set_data4(color);
00590         }
00591       }
00592     }
00593 
00594     new_data._vdata = vdata;
00595   }
00596 
00597   geom->set_vertex_data(new_data._vdata);
00598   if (stc._vertex_data->get_ref_count() > 1) {
00599     _vdata_assoc[new_data._vdata]._might_have_unused = true;
00600     _vdata_assoc[stc._vertex_data]._might_have_unused = true;
00601   }
00602 
00603   return true;
00604 }
00605 
00606 ////////////////////////////////////////////////////////////////////
00607 //     Function: GeomTransformer::apply_texture_colors
00608 //       Access: Public
00609 //  Description: Removes textures from Geoms by applying the texture
00610 //               colors to the vertices.  This is primarily useful to
00611 //               simplify a low-LOD model.
00612 //
00613 //               Only the bottommost texture is used (if there is more
00614 //               than one), and it is applied as if it were
00615 //               M_modulate, and WM_repeat, regardless of its actual
00616 //               settings.  If the texture has a simple_ram_image,
00617 //               this may be used if the main image isn't resident.
00618 //
00619 //               After this call, there will be no texturing specified
00620 //               on the GeomNode level.  Of course, there might still
00621 //               be texturing inherited from above.
00622 ////////////////////////////////////////////////////////////////////
00623 bool GeomTransformer::
00624 apply_texture_colors(GeomNode *node, const RenderState *state) {
00625   bool any_changed = false;
00626 
00627   GeomNode::CDWriter cdata(node->_cycler);
00628   GeomNode::GeomList::iterator gi;
00629   PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
00630   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00631     GeomNode::GeomEntry &entry = (*gi);
00632     CPT(RenderState) geom_state = state->compose(entry._state);
00633 
00634     const TextureAttrib *ta = DCAST(TextureAttrib, geom_state->get_attrib(TextureAttrib::get_class_slot()));
00635     if (ta != (TextureAttrib *)NULL) {
00636       CPT(TextureAttrib) ta2 = ta->filter_to_max(1);
00637       if (ta2->get_num_on_stages() > 0) {
00638         TextureStage *ts = ta2->get_on_stage(0);
00639         Texture *tex = ta2->get_on_texture(ts);
00640         const TexMatrixAttrib *tma = DCAST(TexMatrixAttrib, geom_state->get_attrib(TexMatrixAttrib::get_class_slot()));
00641 
00642         const ColorAttrib *ca = DCAST(ColorAttrib, geom_state->get_attrib(ColorAttrib::get_class_slot()));
00643         LColor base_color(1.0f, 1.0f, 1.0f, 1.0f);
00644         bool keep_vertex_color = true;
00645         if (ca != (ColorAttrib *)NULL && ca->get_color_type() == ColorAttrib::T_flat) {
00646           base_color = ca->get_color();
00647           keep_vertex_color = false;
00648         }
00649 
00650         PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy();
00651         if (apply_texture_colors(new_geom, ts, tex, tma, base_color, keep_vertex_color)) {
00652           entry._geom = new_geom;
00653           any_changed = true;
00654 
00655           if (new_geom->get_vertex_data()->has_column(InternalName::get_color())) {
00656             // Ensure we have a ColorAttrib::make_vertex() attrib.
00657             CPT(RenderState) color_state = entry._state->set_attrib(ColorAttrib::make_vertex());
00658             if (entry._state != color_state) {
00659               entry._state = color_state;
00660               any_changed = true;
00661             }
00662           }
00663         }
00664 
00665         // Also remove any texture references from the GeomState.
00666         CPT(RenderState) no_tex_state = entry._state->remove_attrib(TextureAttrib::get_class_slot());
00667         if (entry._state != no_tex_state) {
00668           entry._state = no_tex_state;
00669           any_changed = true;
00670         }
00671       }
00672     }
00673   }
00674 
00675   return any_changed;
00676 }
00677 
00678 ////////////////////////////////////////////////////////////////////
00679 //     Function: GeomTransformer::apply_state
00680 //       Access: Public
00681 //  Description: Applies the indicated render state to all the of
00682 //               Geoms.  Returns true if the GeomNode was changed,
00683 //               false otherwise.
00684 ////////////////////////////////////////////////////////////////////
00685 bool GeomTransformer::
00686 apply_state(GeomNode *node, const RenderState *state) {
00687   bool any_changed = false;
00688 
00689   GeomNode::CDWriter cdata(node->_cycler);
00690   GeomNode::GeomList::iterator gi;
00691   PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
00692   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00693     GeomNode::GeomEntry &entry = (*gi);
00694     CPT(RenderState) new_state = state->compose(entry._state);
00695     if (entry._state != new_state) {
00696       entry._state = new_state;
00697       any_changed = true;
00698     }
00699   }
00700 
00701   return any_changed;
00702 }
00703 
00704 ////////////////////////////////////////////////////////////////////
00705 //     Function: GeomTransformer::set_format
00706 //       Access: Public
00707 //  Description: Changes the GeomVertexData of the indicated Geom to
00708 //               use the specified format.
00709 ////////////////////////////////////////////////////////////////////
00710 bool GeomTransformer::
00711 set_format(Geom *geom, const GeomVertexFormat *new_format) {
00712   PStatTimer timer(_apply_set_format_collector);
00713 
00714   nassertr(geom != (Geom *)NULL, false);
00715 
00716   SourceFormat sf;
00717   sf._format = new_format;
00718   sf._vertex_data = geom->get_vertex_data();
00719   
00720   NewVertexData &new_data = _format[sf];
00721   if (new_data._vdata.is_null()) {
00722     if (sf._vertex_data->get_format() == new_format) {
00723       // No change.
00724       return false;
00725     }
00726 
00727     // We have not yet converted this vertex data.  Do so now.
00728     PT(GeomVertexData) new_vdata = new GeomVertexData(*sf._vertex_data);
00729     new_vdata->set_format(new_format);
00730     new_data._vdata = new_vdata;
00731   }
00732   
00733   geom->set_vertex_data(new_data._vdata);
00734   if (sf._vertex_data->get_ref_count() > 1) {
00735     _vdata_assoc[new_data._vdata]._might_have_unused = true;
00736     _vdata_assoc[sf._vertex_data]._might_have_unused = true;
00737   }
00738 
00739   return true;
00740 }
00741 
00742 ////////////////////////////////////////////////////////////////////
00743 //     Function: GeomTransformer::remove_column
00744 //       Access: Public
00745 //  Description: Removes the named column from the vertex data in the
00746 //               Geom.  Returns true if the Geom was changed, false
00747 //               otherwise.
00748 ////////////////////////////////////////////////////////////////////
00749 bool GeomTransformer::
00750 remove_column(Geom *geom, const InternalName *column) {
00751   CPT(GeomVertexFormat) format = geom->get_vertex_data()->get_format();
00752   if (!format->has_column(column)) {
00753     return false;
00754   }
00755 
00756   PT(GeomVertexFormat) new_format = new GeomVertexFormat(*format);
00757   new_format->remove_column(column);
00758   new_format->pack_columns();
00759   format = GeomVertexFormat::register_format(new_format);
00760 
00761   return set_format(geom, format);
00762 }
00763 
00764 
00765 ////////////////////////////////////////////////////////////////////
00766 //     Function: GeomTransformer::remove_column
00767 //       Access: Public
00768 //  Description: Removes the named column from the vertex datas within
00769 //               the GeomNode.  Returns true if the GeomNode was
00770 //               changed, false otherwise.
00771 ////////////////////////////////////////////////////////////////////
00772 bool GeomTransformer::
00773 remove_column(GeomNode *node, const InternalName *column) {
00774   bool any_changed = false;
00775 
00776   GeomNode::CDWriter cdata(node->_cycler);
00777   GeomNode::GeomList::iterator gi;
00778   PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
00779   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
00780     GeomNode::GeomEntry &entry = (*gi);
00781     PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy();
00782     if (remove_column(new_geom, column)) {
00783       entry._geom = new_geom;
00784       any_changed = true;
00785     }
00786   }
00787 
00788   return any_changed;
00789 }
00790 
00791 ////////////////////////////////////////////////////////////////////
00792 //     Function: GeomTransformer::make_compatible_state
00793 //       Access: Public
00794 //  Description: Checks if the different geoms in the GeomNode have
00795 //               different RenderStates.  If so, tries to make the 
00796 //               RenderStates the same.  It does this by
00797 //               canonicalizing the ColorAttribs, and in the future,
00798 //               possibly other attribs.
00799 ////////////////////////////////////////////////////////////////////
00800 bool GeomTransformer::
00801 make_compatible_state(GeomNode *node) {
00802   if (node->get_num_geoms() < 2) {
00803     return false;
00804   }
00805   
00806   GeomNode::CDWriter cdata(node->_cycler);
00807   GeomNode::GeomList::iterator gi;
00808   PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
00809 
00810   // For each geom, calculate a canonicalized RenderState, and
00811   // classify all the geoms according to that.  By "canonicalize"
00812   // here, we simply mean removing the ColorAttrib.
00813   
00814   typedef pmap <CPT(RenderState), pvector<int> > StateTable;
00815   StateTable state_table;
00816   
00817   for (int i = 0; i < (int)geoms->size(); i++) {
00818     GeomNode::GeomEntry &entry = (*geoms)[i];
00819     CPT(RenderState) canon = entry._state->remove_attrib(ColorAttrib::get_class_slot());
00820     state_table[canon].push_back(i);
00821   }
00822 
00823   // For each group of geoms, check for mismatch.
00824   
00825   bool any_changed = false;
00826   StateTable::iterator si;
00827   for (si = state_table.begin(); si != state_table.end(); si++) {
00828     
00829     // If the geoms in the group already have the same RenderStates,
00830     // then nothing needs to be done to this group.
00831     
00832     const pvector<int> &indices = (*si).second;
00833     bool mismatch = false;
00834     for (int i = 1; i < (int)indices.size(); i++) {
00835       if ((*geoms)[indices[i]]._state != (*geoms)[indices[0]]._state) {
00836         mismatch = true;
00837         break;
00838       }
00839     }
00840     if (!mismatch) {
00841       continue;
00842     }
00843     
00844     // The geoms do not have the same RenderState, but they could,
00845     // since their canonicalized states are the same.  Canonicalize
00846     // them, by applying the colors to the vertices.
00847     
00848     const RenderState *canon_state = (*si).first;
00849     for (int i = 0; i < (int)indices.size(); i++) {
00850       GeomNode::GeomEntry &entry = (*geoms)[indices[i]];
00851       const RenderAttrib *ra = entry._state->get_attrib_def(ColorAttrib::get_class_slot());
00852       const ColorAttrib *ca = DCAST(ColorAttrib, ra);
00853       if (ca->get_color_type() == ColorAttrib::T_vertex) {
00854         // All we need to do is ensure that the geom has a color column.
00855         if (!entry._geom.get_read_pointer()->get_vertex_data()->has_column(InternalName::get_color())) {
00856           PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy();
00857           if (set_color(new_geom, LColor(1,1,1,1))) {
00858             entry._geom = new_geom;
00859           }
00860         }
00861       } else {
00862         // A flat color (or "off", which is white).  Set the vertices
00863         // to the indicated flat color.
00864         LColor c = ca->get_color();
00865         PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy();
00866         if (set_color(new_geom, c)) {
00867           entry._geom = new_geom;
00868         }
00869       }
00870       entry._state = canon_state->add_attrib(ColorAttrib::make_vertex());
00871       any_changed = true;
00872     }
00873   }
00874   
00875   return any_changed;
00876 }
00877 
00878 ////////////////////////////////////////////////////////////////////
00879 //     Function: GeomTransformer::reverse_normals
00880 //       Access: Public
00881 //  Description: Reverses the lighting normals on the vertex data, if
00882 //               any.  Returns true if the Geom was changed, false
00883 //               otherwise.
00884 ////////////////////////////////////////////////////////////////////
00885 bool GeomTransformer::
00886 reverse_normals(Geom *geom) {
00887   nassertr(geom != (Geom *)NULL, false);
00888   CPT(GeomVertexData) orig_data = geom->get_vertex_data();
00889   NewVertexData &new_data = _reversed_normals[orig_data];
00890   if (new_data._vdata.is_null()) {
00891     new_data._vdata = orig_data->reverse_normals();
00892   }
00893 
00894   if (new_data._vdata == orig_data) {
00895     // No change.
00896     return false;
00897   }
00898 
00899   geom->set_vertex_data(new_data._vdata);
00900   if (orig_data->get_ref_count() > 1) {
00901     _vdata_assoc[new_data._vdata]._might_have_unused = true;
00902     _vdata_assoc[orig_data]._might_have_unused = true;
00903   }
00904 
00905   return true;
00906 }
00907 
00908 ////////////////////////////////////////////////////////////////////
00909 //     Function: GeomTransformer::doubleside
00910 //       Access: Public
00911 //  Description: Duplicates triangles in this GeomNode so that each
00912 //               triangle is back-to-back with another triangle facing
00913 //               in the opposite direction.  If the geometry has
00914 //               vertex normals, this will also duplicate and reverse
00915 //               the normals, so that lighting will work correctly
00916 //               from both sides.  Note that calling this when the
00917 //               geometry is already doublesided (with back-to-back
00918 //               polygons) will result in multiple redundant coplanar
00919 //               polygons.
00920 //
00921 //               Also see CullFaceAttrib, which can enable rendering
00922 //               of both sides of a triangle without having to
00923 //               duplicate it (but which doesn't necessarily work in
00924 //               the presence of lighting).
00925 //
00926 //               Returns true if any Geoms are modified, false
00927 //               otherwise.
00928 ////////////////////////////////////////////////////////////////////
00929 bool GeomTransformer::
00930 doubleside(GeomNode *node) {
00931   int num_geoms = node->get_num_geoms();
00932   for (int i = 0; i < num_geoms; ++i) {
00933     CPT(Geom) orig_geom = node->get_geom(i);
00934     bool has_normals = (orig_geom->get_vertex_data()->has_column(InternalName::get_normal()));
00935     if (has_normals) {
00936       // If the geometry has normals, we have to duplicate it to
00937       // reverse the normals on the duplicate copy.
00938       PT(Geom) new_geom = orig_geom->reverse();
00939       reverse_normals(new_geom);
00940       node->add_geom(new_geom, node->get_geom_state(i));
00941       
00942     } else {
00943       // If there are no normals, we can just doubleside it in
00944       // place.  This is preferable because we can share vertices.
00945       orig_geom.clear();
00946       node->modify_geom(i)->doubleside_in_place();
00947     }
00948   }
00949   
00950   return (num_geoms != 0);
00951 }
00952 
00953 
00954 ////////////////////////////////////////////////////////////////////
00955 //     Function: GeomTransformer::reverse
00956 //       Access: Public
00957 //  Description: Reverses the winding order of triangles in this
00958 //               GeomNode so that each triangle is facing in the
00959 //               opposite direction.  If the geometry has vertex
00960 //               normals, this will also reverse the normals, so that
00961 //               lighting will work correctly.
00962 //
00963 //               Also see CullFaceAttrib, which can effectively change
00964 //               the facing of a triangle having to modify its
00965 //               vertices (but which doesn't necessarily work in the
00966 //               presence of lighting).
00967 //
00968 //               Returns true if any Geoms are modified, false
00969 //               otherwise.
00970 ////////////////////////////////////////////////////////////////////
00971 bool GeomTransformer::
00972 reverse(GeomNode *node) {
00973   int num_geoms = node->get_num_geoms();
00974   for (int i = 0; i < num_geoms; ++i) {
00975     PT(Geom) geom = node->modify_geom(i);
00976     geom->reverse_in_place();
00977     reverse_normals(geom);
00978   }
00979   
00980   return (num_geoms != 0);
00981 }
00982 
00983 ////////////////////////////////////////////////////////////////////
00984 //     Function: GeomTransformer::finish_apply
00985 //       Access: Public
00986 //  Description: Should be called after performing any
00987 //               operations--particularly
00988 //               PandaNode::apply_attribs_to_vertices()--that might
00989 //               result in new GeomVertexData objects being duplicated
00990 //               and modified.  This walks through those newly
00991 //               duplicated objects and ensures that redundant unused
00992 //               vertices have not been created, removing them if they
00993 //               have.
00994 ////////////////////////////////////////////////////////////////////
00995 void GeomTransformer::
00996 finish_apply() {
00997   VertexDataAssocMap::iterator vi;
00998   for (vi = _vdata_assoc.begin(); vi != _vdata_assoc.end(); ++vi) {
00999     const GeomVertexData *vdata = (*vi).first;
01000     VertexDataAssoc &assoc = (*vi).second;
01001     if (assoc._might_have_unused) {
01002       assoc.remove_unused_vertices(vdata);
01003     }
01004   }
01005   _vdata_assoc.clear();
01006 
01007   _texcoords.clear();
01008   _fcolors.clear();
01009   _tcolors.clear();
01010   _format.clear();
01011   _reversed_normals.clear();
01012 }
01013   
01014 ////////////////////////////////////////////////////////////////////
01015 //     Function: GeomTransformer::collect_vertex_data
01016 //       Access: Public
01017 //  Description: Collects together GeomVertexDatas from different
01018 //               geoms into one big (or several big) GeomVertexDatas.
01019 //               Returns the number of unique GeomVertexDatas created.
01020 //
01021 //               If format_only is true, this only makes
01022 //               GeomVertexFormats compatible; it does not otherwise
01023 //               combine vertices.
01024 //
01025 //               You should follow this up with a call to
01026 //               finish_collect(), but you probably don't want to call
01027 //               this method directly anyway.  Call
01028 //               SceneGraphReducer::collect_vertex_data() instead.
01029 ////////////////////////////////////////////////////////////////////
01030 int GeomTransformer::
01031 collect_vertex_data(Geom *geom, int collect_bits, bool format_only) {
01032   CPT(GeomVertexData) vdata = geom->get_vertex_data();
01033   if (vdata->get_num_rows() > _max_collect_vertices) {
01034     // Don't even bother.
01035     return 0;
01036   }
01037 
01038   CPT(GeomVertexFormat) format = vdata->get_format();
01039 
01040   NewCollectedKey key;
01041   if ((collect_bits & SceneGraphReducer::CVD_name) != 0) {
01042     key._name = vdata->get_name();
01043   }
01044   if ((collect_bits & SceneGraphReducer::CVD_format) != 0) {
01045     key._format = format;
01046   }
01047   if ((collect_bits & SceneGraphReducer::CVD_usage_hint) != 0) {
01048     key._usage_hint = vdata->get_usage_hint();
01049   } else {
01050     key._usage_hint = Geom::UH_unspecified;
01051   }
01052   if ((collect_bits & SceneGraphReducer::CVD_animation_type) != 0) {
01053     key._animation_type = format->get_animation().get_animation_type();
01054   } else {
01055     key._animation_type = Geom::AT_none;
01056   }
01057 
01058   AlreadyCollectedMap::const_iterator ai;
01059   ai = _already_collected_map.find(vdata);
01060   if (ai != _already_collected_map.end()) {
01061     // We've previously collected this vertex data; reuse it.
01062     const AlreadyCollectedData &acd = (*ai).second;
01063     SourceGeom source_geom;
01064     source_geom._geom = geom;
01065     source_geom._vertex_offset = acd._vertex_offset;
01066     acd._ncd->_source_geoms.push_back(source_geom);
01067     return 0;
01068   }
01069 
01070   // We haven't collected this vertex data yet; associate it with a
01071   // new data.
01072   NewCollectedMap::iterator ni = _new_collected_map.find(key);
01073   NewCollectedData *ncd;
01074   if (ni != _new_collected_map.end()) {
01075     ncd = (*ni).second;
01076 
01077   } else {
01078     // We haven't encountered a compatible GeomVertexData before.
01079     // Create a new entry.
01080     ncd = new NewCollectedData(vdata);
01081     _new_collected_list.push_back(ncd);
01082     _new_collected_map[key] = ncd;
01083   }
01084 
01085   if (ncd->_new_format != format) {
01086     ncd->_new_format = format->get_union_format(ncd->_new_format);
01087   }
01088 
01089   int this_num_vertices = vdata->get_num_rows();
01090 
01091   if (!format_only &&
01092       ncd->_num_vertices + this_num_vertices > _max_collect_vertices) {
01093     // Whoa, hold the phone!  Too many vertices going into this one
01094     // GeomVertexData object; we'd better start over.
01095     ncd = new NewCollectedData(vdata);
01096     _new_collected_list.push_back(ncd);
01097     _new_collected_map[key] = ncd;
01098   }
01099 
01100   int vertex_offset = ncd->_num_vertices;
01101 
01102   AlreadyCollectedData &acd = _already_collected_map[vdata];
01103   acd._ncd = ncd;
01104   acd._vertex_offset = vertex_offset;
01105 
01106   SourceGeom source_geom;
01107   source_geom._geom = geom;
01108   source_geom._vertex_offset = vertex_offset;
01109   ncd->_source_geoms.push_back(source_geom);
01110   
01111   SourceData source_data;
01112   source_data._vdata = vdata;
01113   source_data._num_vertices = this_num_vertices;
01114 
01115   ncd->_source_datas.push_back(source_data);
01116   ncd->_num_vertices += this_num_vertices;
01117 
01118   return 0;
01119 }
01120 
01121 
01122 ////////////////////////////////////////////////////////////////////
01123 //     Function: GeomTransformer::collect_vertex_data
01124 //       Access: Public
01125 //  Description: Collects together individual GeomVertexData
01126 //               structures that share the same format into one big
01127 //               GeomVertexData structure.  This is intended to
01128 //               minimize context switches on the graphics card.
01129 //
01130 //               If format_only is true, this only makes
01131 //               GeomVertexFormats compatible; it does not otherwise
01132 //               combine vertices.
01133 //
01134 //               You should follow this up with a call to
01135 //               finish_collect(), but you probably don't want to call
01136 //               this method directly anyway.  Call
01137 //               SceneGraphReducer::collect_vertex_data() instead.
01138 ////////////////////////////////////////////////////////////////////
01139 int GeomTransformer::
01140 collect_vertex_data(GeomNode *node, int collect_bits, bool format_only) {
01141   int num_adjusted = 0;
01142   GeomTransformer *dynamic = NULL;
01143 
01144   GeomNode::CDWriter cdata(node->_cycler);
01145   GeomNode::GeomList::iterator gi;
01146   PT(GeomNode::GeomList) geoms = cdata->modify_geoms();
01147   for (gi = geoms->begin(); gi != geoms->end(); ++gi) {
01148     GeomNode::GeomEntry &entry = (*gi);
01149     PT(Geom) new_geom = entry._geom.get_read_pointer()->make_copy();
01150     entry._geom = new_geom;
01151 
01152     if ((collect_bits & SceneGraphReducer::CVD_avoid_dynamic) != 0 &&
01153         new_geom->get_vertex_data()->get_usage_hint() < Geom::UH_static) {
01154       // This one has some dynamic properties.  Collect it
01155       // independently of the outside world.
01156       if (dynamic == (GeomTransformer *)NULL) {
01157         dynamic = new GeomTransformer(*this);
01158       }
01159       num_adjusted += dynamic->collect_vertex_data(new_geom, collect_bits, format_only);
01160       
01161     } else {
01162       num_adjusted += collect_vertex_data(new_geom, collect_bits, format_only);
01163     }
01164   }
01165 
01166   if (dynamic != (GeomTransformer *)NULL) {
01167     num_adjusted += dynamic->finish_collect(format_only);
01168     delete dynamic;
01169   }
01170 
01171   return num_adjusted;
01172 }
01173 
01174 ////////////////////////////////////////////////////////////////////
01175 //     Function: GeomTransformer::finish_collect
01176 //       Access: Public
01177 //  Description: This should be called after a call to
01178 //               collect_vertex_data() to finalize the changes and
01179 //               apply them to the vertices in the graph.  If this is
01180 //               not called, it will be called automatically by the
01181 //               GeomTransformer destructor.
01182 //
01183 //               If format_only is true, this returns the number of
01184 //               GeomVertexDatas modified to use a new format.  If
01185 //               false, it returns the number of GeomVertexDatas
01186 //               created.
01187 ////////////////////////////////////////////////////////////////////
01188 int GeomTransformer::
01189 finish_collect(bool format_only) {
01190   int num_adjusted = 0;
01191 
01192   NewCollectedList::iterator nci;
01193   for (nci = _new_collected_list.begin(); 
01194        nci != _new_collected_list.end();
01195        ++nci) {
01196     NewCollectedData *ncd = (*nci);
01197     if (format_only) {
01198       num_adjusted += ncd->apply_format_only_changes();
01199     } else {
01200       num_adjusted += ncd->apply_collect_changes();
01201     }
01202     delete ncd;
01203   }
01204 
01205   _new_collected_list.clear();
01206   _new_collected_map.clear();
01207   _already_collected_map.clear();
01208 
01209   return num_adjusted;
01210 }
01211 
01212 ////////////////////////////////////////////////////////////////////
01213 //     Function: GeomTransformer::premunge_geom
01214 //       Access: Public
01215 //  Description: Uses the indicated munger to premunge the given Geom
01216 //               to optimize it for eventual rendering.  See
01217 //               SceneGraphReducer::premunge().
01218 ////////////////////////////////////////////////////////////////////
01219 PT(Geom) GeomTransformer::
01220 premunge_geom(const Geom *geom, GeomMunger *munger) {
01221   // This method had been originally provided to cache the result for
01222   // a particular geom/munger and vdata/munger combination, similar to
01223   // the way other GeomTransformer methods work.  On reflection, this
01224   // additional caching is not necessary, since the GeomVertexFormat
01225   // does its own caching, and there's no danger of that cache filling
01226   // up during the span of one frame.
01227 
01228   CPT(GeomVertexData) vdata = geom->get_vertex_data();
01229   vdata = munger->premunge_data(vdata);
01230   CPT(Geom) pgeom = geom;
01231   munger->premunge_geom(pgeom, vdata);
01232 
01233   PT(Geom) geom_copy = pgeom->make_copy();
01234   geom_copy->set_vertex_data(vdata);
01235 
01236   return geom_copy;
01237 }
01238 
01239 ////////////////////////////////////////////////////////////////////
01240 //     Function: GeomTransformer::NewCollectedData::Constructor
01241 //       Access: Public
01242 //  Description: 
01243 ////////////////////////////////////////////////////////////////////
01244 GeomTransformer::NewCollectedData::
01245 NewCollectedData(const GeomVertexData *source_data) {
01246   _new_format = source_data->get_format();
01247   _vdata_name = source_data->get_name();
01248   _usage_hint = source_data->get_usage_hint();
01249   _num_vertices = 0;
01250 }
01251 
01252 ////////////////////////////////////////////////////////////////////
01253 //     Function: GeomTransformer::NewCollectedData::apply_format_only_changes
01254 //       Access: Public
01255 //  Description: Actually adjusts the GeomVertexDatas found in a
01256 //               collect_vertex_data() format-only call to have the
01257 //               same vertex format.  Returns the number of vdatas
01258 //               modified.
01259 ////////////////////////////////////////////////////////////////////
01260 int GeomTransformer::NewCollectedData::
01261 apply_format_only_changes() {
01262   int num_modified = 0;
01263 
01264   // We probably don't need to use a map, since
01265   // GeomVertexData::convert_to() already caches its result, but we do
01266   // it anyway just in case there's danger of overflowing the cache.
01267   // What the heck, it's easy to do.
01268   typedef pmap< CPT(GeomVertexData), CPT(GeomVertexData) > VDataMap;
01269   VDataMap vdata_map;
01270 
01271   SourceGeoms::iterator sgi;
01272   for (sgi = _source_geoms.begin(); sgi != _source_geoms.end(); ++sgi) {
01273     SourceGeom &sg = (*sgi);
01274     CPT(GeomVertexData) orig_data = sg._geom->get_vertex_data();
01275 
01276     if (orig_data->get_format() != _new_format) {
01277       VDataMap::iterator mi = vdata_map.find(orig_data);
01278       if (mi != vdata_map.end()) {
01279         // Already modified this vdata.
01280         sg._geom->set_vertex_data((*mi).second);
01281 
01282       } else {
01283         // Modify this vdata to the new format.
01284         CPT(GeomVertexData) new_data = orig_data->convert_to(_new_format);
01285         vdata_map[orig_data] = new_data;
01286         ++num_modified;
01287 
01288         sg._geom->set_vertex_data(new_data);
01289       }
01290     }
01291   }
01292 
01293   return num_modified;
01294 }
01295 
01296 ////////////////////////////////////////////////////////////////////
01297 //     Function: GeomTransformer::NewCollectedData::apply_collect_changes
01298 //       Access: Public
01299 //  Description: Actually combines all of the vertex datas found in a
01300 //               previous call to collect_vertex_data().
01301 ////////////////////////////////////////////////////////////////////
01302 int GeomTransformer::NewCollectedData::
01303 apply_collect_changes() {
01304   if (_num_vertices == 0) {
01305     return 0;
01306   }
01307 
01308   _new_data =
01309     new GeomVertexData(_vdata_name, _new_format, _usage_hint);
01310 
01311   _new_data->unclean_set_num_rows(_num_vertices);
01312 
01313   // Copy each source data into the new GeomVertexData, one at a time.
01314   int vertex_offset = 0;
01315   SourceDatas::iterator sdi;
01316   for (sdi = _source_datas.begin(); sdi != _source_datas.end(); ++sdi) {
01317     SourceData &sd = (*sdi);
01318     CPT(GeomVertexData) vdata = sd._vdata;
01319 
01320     if (_new_format != vdata->get_format()) {
01321       // Convert (non-destructively) the current Geom's vertex
01322       // data to the new format, so we can just blindly append the
01323       // vertices to _new_data, within append_vdata().
01324       vdata = vdata->convert_to(_new_format);
01325     }
01326 
01327     append_vdata(vdata, vertex_offset);
01328     vertex_offset += sd._num_vertices;
01329   }
01330 
01331   nassertr(vertex_offset == _num_vertices, 0);
01332 
01333   if (_new_btable != (TransformBlendTable *)NULL) {
01334     _new_btable->set_rows(_new_btable_rows);
01335     _new_data->set_transform_blend_table(_new_btable);
01336   }
01337 
01338   update_geoms();
01339 
01340   _new_data.clear();
01341   _new_btable.clear();
01342   _new_btable_rows.clear();
01343 
01344   return 1;
01345 }
01346 
01347 ////////////////////////////////////////////////////////////////////
01348 //     Function: GeomTransformer::NewCollectedData::append_vdata
01349 //       Access: Public
01350 //  Description: Appends the vertices from the indicated source
01351 //               GeomVertexData to the end of the working data.
01352 ////////////////////////////////////////////////////////////////////
01353 void GeomTransformer::NewCollectedData::
01354 append_vdata(const GeomVertexData *vdata, int vertex_offset) {
01355   for (int i = 0; i < vdata->get_num_arrays(); ++i) {
01356     PT(GeomVertexArrayData) new_array = _new_data->modify_array(i);
01357     CPT(GeomVertexArrayData) old_array = vdata->get_array(i);
01358     int stride = _new_format->get_array(i)->get_stride();
01359     int start_byte = vertex_offset * stride;
01360     int copy_bytes = old_array->get_data_size_bytes();
01361     nassertv(start_byte + copy_bytes <= new_array->get_data_size_bytes());
01362     
01363     new_array->modify_handle()->copy_subdata_from
01364       (start_byte, copy_bytes, 
01365        old_array->get_handle(), 0, copy_bytes);
01366   }
01367 
01368   // Also, copy the animation data (if any).  This means combining
01369   // transform and/or slider tables, and might therefore mean
01370   // remapping transform indices in the vertices.  Each of these has a
01371   // slightly different way to handle the remapping, because they have
01372   // slightly different kinds of data.
01373   
01374   if (vdata->get_transform_table() != (TransformTable *)NULL ||
01375       _new_data->get_transform_table() != (TransformTable *)NULL) {
01376     // The TransformTable.
01377     CPT(TransformTable) old_table;
01378     if (vdata->get_transform_table() != (TransformTable *)NULL) {
01379       old_table = vdata->get_transform_table();
01380     } else {
01381       PT(TransformTable) temp_table = new TransformTable;
01382       // There's an implicit identity transform for all nodes.
01383       PT(VertexTransform) identity_transform = new UserVertexTransform("identity");
01384       temp_table->add_transform(identity_transform);
01385       old_table = TransformTable::register_table(temp_table);
01386     }
01387     
01388     // First, build a mapping of the transforms we already have in the
01389     // current table.  We must do this because the TransformTable
01390     // doesn't automatically unquify index numbers for us (it doesn't
01391     // store an index).
01392     typedef pmap<const VertexTransform *, int> AddedTransforms;
01393     AddedTransforms added_transforms;
01394     
01395     int num_old_transforms = old_table->get_num_transforms();
01396     for (int i = 0; i < num_old_transforms; i++) {
01397       added_transforms[old_table->get_transform(i)] = i;
01398     }
01399     
01400     // Now create a new table.  We have to create a new table instead
01401     // of modifying the existing one, since a registered
01402     // TransformTable cannot be modified.
01403     PT(TransformTable) new_table;
01404     if (_new_data->get_transform_table() != (TransformTable *)NULL) {
01405       new_table = new TransformTable(*_new_data->get_transform_table());
01406     } else {
01407       new_table = new TransformTable;
01408     }
01409     
01410     // Now walk through the old table and copy over its transforms.
01411     // We will build up an IndexMap of old index numbers to new index
01412     // numbers while we go, which we can use to modify the vertices.
01413     IndexMap transform_map;
01414     
01415     int num_transforms = old_table->get_num_transforms();
01416     transform_map.reserve(num_transforms);
01417     for (int ti = 0; ti < num_transforms; ++ti) {
01418       const VertexTransform *transform = old_table->get_transform(ti);
01419       AddedTransforms::iterator ai = added_transforms.find(transform);
01420       if (ai != added_transforms.end()) {
01421         // Already got this one in the table.
01422         transform_map.push_back((*ai).second);
01423       } else {
01424         // This is a new one.
01425         int tj = new_table->add_transform(transform);
01426         transform_map.push_back(tj);
01427         added_transforms[transform] = tj;
01428       }
01429     }
01430     _new_data->set_transform_table(TransformTable::register_table(new_table));
01431 
01432     // And now modify the vertices to update the indices to their new
01433     // values in the new table.  This requires a nested loop, since
01434     // each column of transform_index might define multiple index
01435     // values.
01436     GeomVertexRewriter index(_new_data, InternalName::get_transform_index());
01437     if (index.has_column()) {
01438       int num_values = index.get_column()->get_num_values();
01439       int num_rows = vdata->get_num_rows();
01440       int new_index[4];
01441       
01442       index.set_row_unsafe(vertex_offset);
01443       for (int ci = 0; ci < num_rows; ++ci) {
01444         const int *orig_index = index.get_data4i();
01445         for (int i = 0; i < num_values; i++) {
01446           nassertv(orig_index[i] >= 0 && orig_index[i] < (int)transform_map.size());
01447           new_index[i] = transform_map[orig_index[i]];
01448         }
01449         index.set_data4i(new_index);
01450       }
01451     }
01452   }
01453 
01454   if (vdata->get_transform_blend_table() != (TransformBlendTable *)NULL) {
01455     // The TransformBlendTable.  This one is the easiest, because we
01456     // can modify it directly, and it will uniquify blend objects for
01457     // us.
01458 
01459     // We have few special optimizations to handle the
01460     // TransformBlendTable, since it's a very common case and
01461     // therefore worth spending a bit of effort to optimize deeply.
01462     
01463     CPT(TransformBlendTable) old_btable = vdata->get_transform_blend_table();
01464     
01465     if (_new_btable == (TransformBlendTable *)NULL) {
01466       _new_btable = new TransformBlendTable;
01467       _new_btable->add_blend(TransformBlend());
01468     }
01469 
01470     SparseArray new_rows = old_btable->get_rows();
01471     new_rows <<= vertex_offset;
01472     _new_btable_rows |= new_rows;
01473 
01474     // We still need to build up the IndexMap.
01475     IndexMap blend_map;
01476 
01477     int num_blends = old_btable->get_num_blends();
01478     blend_map.reserve(num_blends);
01479     for (int bi = 0; bi < num_blends; ++bi) {
01480       int bj = _new_btable->add_blend(old_btable->get_blend(bi));
01481       blend_map.push_back(bj);
01482     }
01483 
01484     // Modify the indices.  This is simpler than the transform_index,
01485     // above, because each column of transform_blend may only define
01486     // one index value.
01487     GeomVertexRewriter index(_new_data, InternalName::get_transform_blend());
01488     if (index.has_column()) {
01489       int num_rows = vdata->get_num_rows();
01490       index.set_row_unsafe(vertex_offset);
01491 
01492       for (int ci = 0; ci < num_rows; ++ci) {
01493         int orig_index = index.get_data1i();
01494         nassertv(orig_index >= 0 && orig_index < (int)blend_map.size());
01495         int new_index = blend_map[orig_index];
01496         index.set_data1i(new_index);
01497       }
01498     }
01499   }
01500   
01501   if (vdata->get_slider_table() != (SliderTable *)NULL) {
01502     // The SliderTable.  This one requires making a copy, like the
01503     // TransformTable (since it can't be modified once registered
01504     // either), but at least it uniquifies sliders added to it.  Also,
01505     // it doesn't require indexing into it, so we don't have to build
01506     // an IndexMap to modify the vertices with.
01507     const SliderTable *old_sliders = vdata->get_slider_table();
01508     PT(SliderTable) new_sliders;
01509     if (_new_data->get_slider_table() != (SliderTable *)NULL) {
01510       new_sliders = new SliderTable(*_new_data->get_slider_table());
01511     } else {
01512       new_sliders = new SliderTable;
01513     }
01514     int num_sliders = old_sliders->get_num_sliders();
01515     for (int si = 0; si < num_sliders; ++si) {
01516       SparseArray new_rows = old_sliders->get_slider_rows(si);
01517       new_rows <<= vertex_offset;
01518       new_sliders->add_slider(old_sliders->get_slider(si), new_rows);
01519     }
01520     _new_data->set_slider_table(SliderTable::register_table(new_sliders));
01521   }
01522 }
01523 
01524 ////////////////////////////////////////////////////////////////////
01525 //     Function: GeomTransformer::NewCollectedData::update_geoms
01526 //       Access: Public
01527 //  Description: Updates all of the source Geoms to reference the new
01528 //               vertex data.
01529 ////////////////////////////////////////////////////////////////////
01530 void GeomTransformer::NewCollectedData::
01531 update_geoms() {
01532   SourceGeoms::iterator sgi;
01533   for (sgi = _source_geoms.begin(); sgi != _source_geoms.end(); ++sgi) {
01534     SourceGeom &sg = (*sgi);
01535     sg._geom->offset_vertices(_new_data, sg._vertex_offset);
01536   }
01537 }
01538 
01539 ////////////////////////////////////////////////////////////////////
01540 //     Function: GeomTransformer::VertexDataAssoc::remove_unused_vertices
01541 //       Access: Public
01542 //  Description: 
01543 ////////////////////////////////////////////////////////////////////
01544 void GeomTransformer::VertexDataAssoc::
01545 remove_unused_vertices(const GeomVertexData *vdata) {
01546   if (_geoms.empty()) {
01547     // Trivial case.
01548     return;
01549   }
01550 
01551   PT(Thread) current_thread = Thread::get_current_thread();
01552 
01553   BitArray referenced_vertices;
01554   bool any_referenced = false;
01555   GeomList::iterator gi;
01556   for (gi = _geoms.begin(); gi != _geoms.end(); ++gi) {
01557     Geom *geom = (*gi);
01558     if (geom->get_vertex_data() != vdata) {
01559       continue;
01560     }
01561 
01562     any_referenced = true;
01563     int num_primitives = geom->get_num_primitives();
01564     for (int i = 0; i < num_primitives; ++i) {
01565       CPT(GeomPrimitive) prim = geom->get_primitive(i);
01566 
01567       GeomPrimitivePipelineReader reader(prim, current_thread);
01568       int num_vertices = reader.get_num_vertices();
01569       for (int vi = 0; vi < num_vertices; ++vi) {
01570         referenced_vertices.set_bit(reader.get_vertex(vi));
01571       }
01572     }
01573   }
01574 
01575   if (!any_referenced) {
01576     return;
01577   }
01578 
01579   int num_vertices = vdata->get_num_rows();
01580   int new_num_vertices = referenced_vertices.get_num_on_bits();
01581   if (num_vertices <= new_num_vertices) {
01582     // All vertices are used.
01583     nassertv(num_vertices == new_num_vertices);
01584     return;
01585   }
01586 
01587   // Remap the vertices.
01588   int *remap_array = (int *)alloca(sizeof(int) * num_vertices);
01589   int new_index = 0;
01590   int index;
01591   int next_index = 0;
01592   for (index = 0; index < num_vertices; ++index) {
01593     if (referenced_vertices.get_bit(index)) {
01594       while (next_index <= index) {
01595         remap_array[next_index] = new_index;
01596         ++next_index;
01597       }
01598       ++new_index;
01599     }
01600   }
01601   while (next_index < num_vertices) {
01602     remap_array[next_index] = new_num_vertices - 1;
01603     ++next_index;
01604   }
01605 
01606   // Now recopy the actual vertex data, one array at a time.
01607   PT(GeomVertexData) new_vdata = new GeomVertexData(*vdata);
01608   new_vdata->unclean_set_num_rows(new_num_vertices);
01609 
01610   int num_arrays = vdata->get_num_arrays();
01611   nassertv(num_arrays == new_vdata->get_num_arrays());
01612 
01613   GeomVertexDataPipelineReader reader(vdata, current_thread);
01614   reader.check_array_readers();
01615   GeomVertexDataPipelineWriter writer(new_vdata, true, current_thread);
01616   writer.check_array_writers();
01617 
01618   for (int a = 0; a < num_arrays; ++a) {
01619     const GeomVertexArrayDataHandle *array_reader = reader.get_array_reader(a);
01620     GeomVertexArrayDataHandle *array_writer = writer.get_array_writer(a);
01621 
01622     int stride = array_reader->get_array_format()->get_stride();
01623     nassertv(stride == array_writer->get_array_format()->get_stride());
01624 
01625     int new_index = 0;
01626     int index;
01627     for (index = 0; index < num_vertices; ++index) {
01628       if (referenced_vertices.get_bit(index)) {
01629         array_writer->copy_subdata_from(new_index * stride, stride,
01630                                         array_reader,
01631                                         index * stride, stride);
01632         ++new_index;
01633       }
01634     }
01635   }
01636 
01637   // Update the subranges in the TransformBlendTable, if any.
01638   PT(TransformBlendTable) tbtable = new_vdata->modify_transform_blend_table();
01639   if (!tbtable.is_null()) {
01640     const SparseArray &rows = tbtable->get_rows();
01641     SparseArray new_rows;
01642     int num_subranges = rows.get_num_subranges();
01643     for (int si = 0; si < num_subranges; ++si) {
01644       int from = rows.get_subrange_begin(si);
01645       int to = rows.get_subrange_end(si);
01646       nassertv(from >= 0 && from < num_vertices && to > from && to <= num_vertices);
01647       int new_from = remap_array[from];
01648       int new_to = remap_array[to - 1] + 1;
01649       nassertv(new_from >= 0 && new_from < new_num_vertices && new_to >= new_from && new_to <= new_num_vertices);
01650       new_rows.set_range(new_from, new_to - new_from);
01651     }
01652     tbtable->set_rows(new_rows);
01653   }
01654 
01655   // Finally, reindex the Geoms.
01656   for (gi = _geoms.begin(); gi != _geoms.end(); ++gi) {
01657     Geom *geom = (*gi);
01658     if (geom->get_vertex_data() != vdata) {
01659       continue;
01660     }
01661 
01662     int num_primitives = geom->get_num_primitives();
01663     for (int i = 0; i < num_primitives; ++i) {
01664       PT(GeomPrimitive) prim = geom->modify_primitive(i);
01665       prim->make_indexed();
01666       PT(GeomVertexArrayData) vertices = prim->modify_vertices();
01667       GeomVertexRewriter rewriter(vertices, 0, current_thread);
01668 
01669       while (!rewriter.is_at_end()) {
01670         index = rewriter.get_data1i();
01671         nassertv(index >= 0 && index < num_vertices);
01672         new_index = remap_array[index];
01673         nassertv(new_index >= 0 && new_index < new_num_vertices);
01674         rewriter.set_data1i(new_index);
01675       }
01676     }
01677 
01678     geom->set_vertex_data(new_vdata);
01679   }
01680 }
 All Classes Functions Variables Enumerations