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