Panda3D
|
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 ©) : 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 }