Panda3D
|
00001 // Filename: geom.cxx 00002 // Created by: drose (06Mar05) 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 "geom.h" 00016 #include "geomPoints.h" 00017 #include "geomVertexReader.h" 00018 #include "geomVertexRewriter.h" 00019 #include "graphicsStateGuardianBase.h" 00020 #include "preparedGraphicsObjects.h" 00021 #include "pStatTimer.h" 00022 #include "bamReader.h" 00023 #include "bamWriter.h" 00024 #include "boundingSphere.h" 00025 #include "boundingBox.h" 00026 #include "lightMutexHolder.h" 00027 #include "config_mathutil.h" 00028 00029 UpdateSeq Geom::_next_modified; 00030 PStatCollector Geom::_draw_primitive_setup_pcollector("Draw:Primitive:Setup"); 00031 00032 TypeHandle Geom::_type_handle; 00033 TypeHandle Geom::CDataCache::_type_handle; 00034 TypeHandle Geom::CacheEntry::_type_handle; 00035 TypeHandle Geom::CData::_type_handle; 00036 TypeHandle GeomPipelineReader::_type_handle; 00037 00038 //////////////////////////////////////////////////////////////////// 00039 // Function: Geom::make_cow_copy 00040 // Access: Protected, Virtual 00041 // Description: Required to implement CopyOnWriteObject. 00042 //////////////////////////////////////////////////////////////////// 00043 PT(CopyOnWriteObject) Geom:: 00044 make_cow_copy() { 00045 return make_copy(); 00046 } 00047 00048 //////////////////////////////////////////////////////////////////// 00049 // Function: Geom::Constructor 00050 // Access: Published 00051 // Description: 00052 //////////////////////////////////////////////////////////////////// 00053 Geom:: 00054 Geom(const GeomVertexData *data) { 00055 // Let's ensure the vertex data gets set on all stages at once. 00056 OPEN_ITERATE_ALL_STAGES(_cycler) { 00057 CDStageWriter cdata(_cycler, pipeline_stage); 00058 cdata->_data = (GeomVertexData *)data; 00059 } 00060 CLOSE_ITERATE_ALL_STAGES(_cycler); 00061 } 00062 00063 //////////////////////////////////////////////////////////////////// 00064 // Function: Geom::Copy Constructor 00065 // Access: Protected 00066 // Description: Use make_copy() to duplicate a Geom. 00067 //////////////////////////////////////////////////////////////////// 00068 Geom:: 00069 Geom(const Geom ©) : 00070 CopyOnWriteObject(copy), 00071 _cycler(copy._cycler) 00072 { 00073 } 00074 00075 //////////////////////////////////////////////////////////////////// 00076 // Function: Geom::Copy Assignment Operator 00077 // Access: Published 00078 // Description: The copy assignment operator is not pipeline-safe. 00079 // This will completely obliterate all stages of the 00080 // pipeline, so don't do it for a Geom that is actively 00081 // being used for rendering. 00082 //////////////////////////////////////////////////////////////////// 00083 void Geom:: 00084 operator = (const Geom ©) { 00085 CopyOnWriteObject::operator = (copy); 00086 00087 clear_cache(); 00088 00089 _cycler = copy._cycler; 00090 00091 OPEN_ITERATE_ALL_STAGES(_cycler) { 00092 CDStageWriter cdata(_cycler, pipeline_stage); 00093 mark_internal_bounds_stale(cdata); 00094 } 00095 CLOSE_ITERATE_ALL_STAGES(_cycler); 00096 } 00097 00098 //////////////////////////////////////////////////////////////////// 00099 // Function: Geom::Destructor 00100 // Access: Published, Virtual 00101 // Description: 00102 //////////////////////////////////////////////////////////////////// 00103 Geom:: 00104 ~Geom() { 00105 clear_cache(); 00106 release_all(); 00107 } 00108 00109 //////////////////////////////////////////////////////////////////// 00110 // Function: Geom::make_copy 00111 // Access: Protected, Virtual 00112 // Description: Returns a newly-allocated Geom that is a shallow copy 00113 // of this one. It will be a different Geom pointer, 00114 // but its internal data may or may not be shared with 00115 // that of the original Geom. 00116 //////////////////////////////////////////////////////////////////// 00117 Geom *Geom:: 00118 make_copy() const { 00119 return new Geom(*this); 00120 } 00121 00122 //////////////////////////////////////////////////////////////////// 00123 // Function: Geom::set_usage_hint 00124 // Access: Published 00125 // Description: Changes the UsageHint hint for all of the primitives 00126 // on this Geom to the same value. See 00127 // get_usage_hint(). 00128 // 00129 // Don't call this in a downstream thread unless you 00130 // don't mind it blowing away other changes you might 00131 // have recently made in an upstream thread. 00132 //////////////////////////////////////////////////////////////////// 00133 void Geom:: 00134 set_usage_hint(Geom::UsageHint usage_hint) { 00135 Thread *current_thread = Thread::get_current_thread(); 00136 CDWriter cdata(_cycler, true, current_thread); 00137 cdata->_usage_hint = usage_hint; 00138 00139 Primitives::iterator pi; 00140 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { 00141 PT(GeomPrimitive) prim = (*pi).get_write_pointer(); 00142 prim->set_usage_hint(usage_hint); 00143 } 00144 00145 clear_cache_stage(current_thread); 00146 cdata->_modified = Geom::get_next_modified(); 00147 } 00148 00149 //////////////////////////////////////////////////////////////////// 00150 // Function: Geom::modify_vertex_data 00151 // Access: Published 00152 // Description: Returns a modifiable pointer to the GeomVertexData, 00153 // so that application code may directly maniuplate the 00154 // geom's underlying data. 00155 // 00156 // Don't call this in a downstream thread unless you 00157 // don't mind it blowing away other changes you might 00158 // have recently made in an upstream thread. 00159 //////////////////////////////////////////////////////////////////// 00160 PT(GeomVertexData) Geom:: 00161 modify_vertex_data() { 00162 Thread *current_thread = Thread::get_current_thread(); 00163 // Perform copy-on-write: if the reference count on the vertex data 00164 // is greater than 1, assume some other Geom has the same pointer, 00165 // so make a copy of it first. 00166 CDWriter cdata(_cycler, true, current_thread); 00167 clear_cache_stage(current_thread); 00168 mark_internal_bounds_stale(cdata); 00169 return cdata->_data.get_write_pointer(); 00170 } 00171 00172 //////////////////////////////////////////////////////////////////// 00173 // Function: Geom::set_vertex_data 00174 // Access: Published 00175 // Description: Replaces the Geom's underlying vertex data table with 00176 // a completely new table. 00177 // 00178 // Don't call this in a downstream thread unless you 00179 // don't mind it blowing away other changes you might 00180 // have recently made in an upstream thread. 00181 //////////////////////////////////////////////////////////////////// 00182 void Geom:: 00183 set_vertex_data(const GeomVertexData *data) { 00184 Thread *current_thread = Thread::get_current_thread(); 00185 nassertv(check_will_be_valid(data)); 00186 CDWriter cdata(_cycler, true, current_thread); 00187 cdata->_data = (GeomVertexData *)data; 00188 clear_cache_stage(current_thread); 00189 mark_internal_bounds_stale(cdata); 00190 reset_geom_rendering(cdata); 00191 } 00192 00193 //////////////////////////////////////////////////////////////////// 00194 // Function: Geom::offset_vertices 00195 // Access: Published 00196 // Description: Replaces a Geom's vertex table with a new table, and 00197 // simultaneously adds the indicated offset to all 00198 // vertex references within the Geom's primitives. This 00199 // is intended to be used to combine multiple 00200 // GeomVertexDatas from different Geoms into a single 00201 // big buffer, with each Geom referencing a subset of 00202 // the vertices in the buffer. 00203 // 00204 // Don't call this in a downstream thread unless you 00205 // don't mind it blowing away other changes you might 00206 // have recently made in an upstream thread. 00207 //////////////////////////////////////////////////////////////////// 00208 void Geom:: 00209 offset_vertices(const GeomVertexData *data, int offset) { 00210 Thread *current_thread = Thread::get_current_thread(); 00211 CDWriter cdata(_cycler, true, current_thread); 00212 cdata->_data = (GeomVertexData *)data; 00213 00214 #ifndef NDEBUG 00215 bool all_is_valid = true; 00216 #endif 00217 Primitives::iterator pi; 00218 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { 00219 PT(GeomPrimitive) prim = (*pi).get_write_pointer(); 00220 prim->offset_vertices(offset); 00221 00222 #ifndef NDEBUG 00223 if (!prim->check_valid(data)) { 00224 gobj_cat.warning() 00225 << *prim << " is invalid for " << *data << ":\n"; 00226 prim->write(gobj_cat.warning(false), 4); 00227 00228 all_is_valid = false; 00229 } 00230 #endif 00231 } 00232 00233 cdata->_modified = Geom::get_next_modified(); 00234 clear_cache_stage(current_thread); 00235 nassertv(all_is_valid); 00236 } 00237 00238 //////////////////////////////////////////////////////////////////// 00239 // Function: Geom::make_nonindexed 00240 // Access: Published 00241 // Description: Converts the geom from indexed to nonindexed by 00242 // duplicating vertices as necessary. If composite_only 00243 // is true, then only composite primitives such as 00244 // trifans and tristrips are converted. Returns the 00245 // number of GeomPrimitive objects converted. 00246 // 00247 // Don't call this in a downstream thread unless you 00248 // don't mind it blowing away other changes you might 00249 // have recently made in an upstream thread. 00250 //////////////////////////////////////////////////////////////////// 00251 int Geom:: 00252 make_nonindexed(bool composite_only) { 00253 Thread *current_thread = Thread::get_current_thread(); 00254 int num_changed = 0; 00255 00256 CDWriter cdata(_cycler, true, current_thread); 00257 CPT(GeomVertexData) orig_data = cdata->_data.get_read_pointer(); 00258 PT(GeomVertexData) new_data = new GeomVertexData(*orig_data); 00259 new_data->clear_rows(); 00260 00261 #ifndef NDEBUG 00262 bool all_is_valid = true; 00263 #endif 00264 Primitives::iterator pi; 00265 Primitives new_prims; 00266 new_prims.reserve(cdata->_primitives.size()); 00267 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { 00268 PT(GeomPrimitive) primitive = (*pi).get_read_pointer()->make_copy(); 00269 new_prims.push_back(primitive.p()); 00270 00271 // GeomPoints are considered "composite" for the purposes of 00272 // making nonindexed, since there's no particular advantage to 00273 // having indexed points (as opposed to, say, indexed triangles or 00274 // indexed lines). 00275 if (primitive->is_indexed() && 00276 (primitive->is_composite() || 00277 primitive->is_exact_type(GeomPoints::get_class_type()) || 00278 !composite_only)) { 00279 primitive->make_nonindexed(new_data, orig_data); 00280 ++num_changed; 00281 } else { 00282 // If it's a simple primitive, pack it anyway, so it can share 00283 // the same GeomVertexData. 00284 primitive->pack_vertices(new_data, orig_data); 00285 } 00286 00287 #ifndef NDEBUG 00288 if (!primitive->check_valid(new_data)) { 00289 all_is_valid = false; 00290 } 00291 #endif 00292 } 00293 00294 nassertr(all_is_valid, 0); 00295 00296 if (num_changed != 0) { 00297 // If any at all were changed, then keep the result (otherwise, 00298 // discard it, since we might have de-optimized the indexed 00299 // geometry a bit). 00300 cdata->_data = new_data; 00301 cdata->_primitives.swap(new_prims); 00302 cdata->_modified = Geom::get_next_modified(); 00303 clear_cache_stage(current_thread); 00304 } 00305 00306 return num_changed; 00307 } 00308 00309 //////////////////////////////////////////////////////////////////// 00310 // Function: Geom::set_primitive 00311 // Access: Published 00312 // Description: Replaces the ith GeomPrimitive object stored within 00313 // the Geom with the new object. 00314 // 00315 // Don't call this in a downstream thread unless you 00316 // don't mind it blowing away other changes you might 00317 // have recently made in an upstream thread. 00318 //////////////////////////////////////////////////////////////////// 00319 void Geom:: 00320 set_primitive(int i, const GeomPrimitive *primitive) { 00321 Thread *current_thread = Thread::get_current_thread(); 00322 CDWriter cdata(_cycler, true, current_thread); 00323 nassertv(i >= 0 && i < (int)cdata->_primitives.size()); 00324 nassertv(primitive->check_valid(cdata->_data.get_read_pointer())); 00325 00326 // All primitives within a particular Geom must have the same 00327 // fundamental primitive type (triangles, points, or lines). 00328 nassertv(cdata->_primitive_type == PT_none || 00329 cdata->_primitive_type == primitive->get_primitive_type()); 00330 00331 // They also should have the a compatible shade model. 00332 CPT(GeomPrimitive) compat = primitive->match_shade_model(cdata->_shade_model); 00333 nassertv_always(compat != (GeomPrimitive *)NULL); 00334 00335 cdata->_primitives[i] = (GeomPrimitive *)compat.p(); 00336 PrimitiveType new_primitive_type = compat->get_primitive_type(); 00337 if (new_primitive_type != cdata->_primitive_type) { 00338 cdata->_primitive_type = new_primitive_type; 00339 } 00340 ShadeModel new_shade_model = compat->get_shade_model(); 00341 if (new_shade_model != cdata->_shade_model && 00342 new_shade_model != SM_uniform) { 00343 cdata->_shade_model = new_shade_model; 00344 } 00345 00346 reset_geom_rendering(cdata); 00347 cdata->_got_usage_hint = false; 00348 cdata->_modified = Geom::get_next_modified(); 00349 clear_cache_stage(current_thread); 00350 mark_internal_bounds_stale(cdata); 00351 } 00352 00353 //////////////////////////////////////////////////////////////////// 00354 // Function: Geom::add_primitive 00355 // Access: Published 00356 // Description: Adds a new GeomPrimitive structure to the Geom 00357 // object. This specifies a particular subset of 00358 // vertices that are used to define geometric primitives 00359 // of the indicated type. 00360 // 00361 // Don't call this in a downstream thread unless you 00362 // don't mind it blowing away other changes you might 00363 // have recently made in an upstream thread. 00364 //////////////////////////////////////////////////////////////////// 00365 void Geom:: 00366 add_primitive(const GeomPrimitive *primitive) { 00367 Thread *current_thread = Thread::get_current_thread(); 00368 CDWriter cdata(_cycler, true, current_thread); 00369 00370 nassertv(primitive->check_valid(cdata->_data.get_read_pointer())); 00371 00372 // All primitives within a particular Geom must have the same 00373 // fundamental primitive type (triangles, points, or lines). 00374 nassertv(cdata->_primitive_type == PT_none || 00375 cdata->_primitive_type == primitive->get_primitive_type()); 00376 00377 // They also should have the a compatible shade model. 00378 CPT(GeomPrimitive) compat = primitive->match_shade_model(cdata->_shade_model); 00379 nassertv_always(compat != (GeomPrimitive *)NULL); 00380 00381 cdata->_primitives.push_back((GeomPrimitive *)compat.p()); 00382 PrimitiveType new_primitive_type = compat->get_primitive_type(); 00383 if (new_primitive_type != cdata->_primitive_type) { 00384 cdata->_primitive_type = new_primitive_type; 00385 } 00386 ShadeModel new_shade_model = compat->get_shade_model(); 00387 if (new_shade_model != cdata->_shade_model && 00388 new_shade_model != SM_uniform) { 00389 cdata->_shade_model = new_shade_model; 00390 } 00391 00392 reset_geom_rendering(cdata); 00393 cdata->_got_usage_hint = false; 00394 cdata->_modified = Geom::get_next_modified(); 00395 clear_cache_stage(current_thread); 00396 mark_internal_bounds_stale(cdata); 00397 } 00398 00399 //////////////////////////////////////////////////////////////////// 00400 // Function: Geom::remove_primitive 00401 // Access: Published 00402 // Description: Removes the ith primitive from the list. 00403 // 00404 // Don't call this in a downstream thread unless you 00405 // don't mind it blowing away other changes you might 00406 // have recently made in an upstream thread. 00407 //////////////////////////////////////////////////////////////////// 00408 void Geom:: 00409 remove_primitive(int i) { 00410 Thread *current_thread = Thread::get_current_thread(); 00411 CDWriter cdata(_cycler, true, current_thread); 00412 nassertv(i >= 0 && i < (int)cdata->_primitives.size()); 00413 cdata->_primitives.erase(cdata->_primitives.begin() + i); 00414 if (cdata->_primitives.empty()) { 00415 cdata->_primitive_type = PT_none; 00416 cdata->_shade_model = SM_uniform; 00417 } 00418 reset_geom_rendering(cdata); 00419 cdata->_got_usage_hint = false; 00420 cdata->_modified = Geom::get_next_modified(); 00421 clear_cache_stage(current_thread); 00422 mark_internal_bounds_stale(cdata); 00423 } 00424 00425 //////////////////////////////////////////////////////////////////// 00426 // Function: Geom::clear_primitives 00427 // Access: Published 00428 // Description: Removes all the primitives from the Geom object (but 00429 // keeps the same table of vertices). You may then 00430 // re-add primitives one at a time via calls to 00431 // add_primitive(). 00432 // 00433 // Don't call this in a downstream thread unless you 00434 // don't mind it blowing away other changes you might 00435 // have recently made in an upstream thread. 00436 //////////////////////////////////////////////////////////////////// 00437 void Geom:: 00438 clear_primitives() { 00439 Thread *current_thread = Thread::get_current_thread(); 00440 CDWriter cdata(_cycler, true, current_thread); 00441 cdata->_primitives.clear(); 00442 cdata->_primitive_type = PT_none; 00443 cdata->_shade_model = SM_uniform; 00444 reset_geom_rendering(cdata); 00445 clear_cache_stage(current_thread); 00446 mark_internal_bounds_stale(cdata); 00447 } 00448 00449 //////////////////////////////////////////////////////////////////// 00450 // Function: Geom::decompose_in_place 00451 // Access: Published 00452 // Description: Decomposes all of the primitives within this Geom, 00453 // leaving the results in place. See 00454 // GeomPrimitive::decompose(). 00455 // 00456 // Don't call this in a downstream thread unless you 00457 // don't mind it blowing away other changes you might 00458 // have recently made in an upstream thread. 00459 //////////////////////////////////////////////////////////////////// 00460 void Geom:: 00461 decompose_in_place() { 00462 Thread *current_thread = Thread::get_current_thread(); 00463 CDWriter cdata(_cycler, true, current_thread); 00464 00465 #ifndef NDEBUG 00466 bool all_is_valid = true; 00467 #endif 00468 Primitives::iterator pi; 00469 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { 00470 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->decompose(); 00471 (*pi) = (GeomPrimitive *)new_prim.p(); 00472 00473 #ifndef NDEBUG 00474 if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { 00475 all_is_valid = false; 00476 } 00477 #endif 00478 } 00479 00480 cdata->_modified = Geom::get_next_modified(); 00481 reset_geom_rendering(cdata); 00482 clear_cache_stage(current_thread); 00483 00484 nassertv(all_is_valid); 00485 } 00486 00487 //////////////////////////////////////////////////////////////////// 00488 // Function: Geom::doubleside_in_place 00489 // Access: Published 00490 // Description: Doublesides all of the primitives within this Geom, 00491 // leaving the results in place. See 00492 // GeomPrimitive::doubleside(). 00493 // 00494 // Don't call this in a downstream thread unless you 00495 // don't mind it blowing away other changes you might 00496 // have recently made in an upstream thread. 00497 //////////////////////////////////////////////////////////////////// 00498 void Geom:: 00499 doubleside_in_place() { 00500 Thread *current_thread = Thread::get_current_thread(); 00501 CDWriter cdata(_cycler, true, current_thread); 00502 00503 #ifndef NDEBUG 00504 bool all_is_valid = true; 00505 #endif 00506 Primitives::iterator pi; 00507 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { 00508 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->doubleside(); 00509 (*pi) = (GeomPrimitive *)new_prim.p(); 00510 00511 #ifndef NDEBUG 00512 if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { 00513 all_is_valid = false; 00514 } 00515 #endif 00516 } 00517 00518 cdata->_modified = Geom::get_next_modified(); 00519 reset_geom_rendering(cdata); 00520 clear_cache_stage(current_thread); 00521 00522 nassertv(all_is_valid); 00523 } 00524 00525 //////////////////////////////////////////////////////////////////// 00526 // Function: Geom::reverse_in_place 00527 // Access: Published 00528 // Description: Reverses all of the primitives within this Geom, 00529 // leaving the results in place. See 00530 // GeomPrimitive::reverse(). 00531 // 00532 // Don't call this in a downstream thread unless you 00533 // don't mind it blowing away other changes you might 00534 // have recently made in an upstream thread. 00535 //////////////////////////////////////////////////////////////////// 00536 void Geom:: 00537 reverse_in_place() { 00538 Thread *current_thread = Thread::get_current_thread(); 00539 CDWriter cdata(_cycler, true, current_thread); 00540 00541 #ifndef NDEBUG 00542 bool all_is_valid = true; 00543 #endif 00544 Primitives::iterator pi; 00545 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { 00546 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->reverse(); 00547 (*pi) = (GeomPrimitive *)new_prim.p(); 00548 00549 #ifndef NDEBUG 00550 if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { 00551 all_is_valid = false; 00552 } 00553 #endif 00554 } 00555 00556 cdata->_modified = Geom::get_next_modified(); 00557 reset_geom_rendering(cdata); 00558 clear_cache_stage(current_thread); 00559 00560 nassertv(all_is_valid); 00561 } 00562 00563 //////////////////////////////////////////////////////////////////// 00564 // Function: Geom::rotate_in_place 00565 // Access: Published 00566 // Description: Rotates all of the primitives within this Geom, 00567 // leaving the results in place. See 00568 // GeomPrimitive::rotate(). 00569 // 00570 // Don't call this in a downstream thread unless you 00571 // don't mind it blowing away other changes you might 00572 // have recently made in an upstream thread. 00573 //////////////////////////////////////////////////////////////////// 00574 void Geom:: 00575 rotate_in_place() { 00576 Thread *current_thread = Thread::get_current_thread(); 00577 CDWriter cdata(_cycler, true, current_thread); 00578 00579 #ifndef NDEBUG 00580 bool all_is_valid = true; 00581 #endif 00582 Primitives::iterator pi; 00583 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { 00584 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->rotate(); 00585 (*pi) = (GeomPrimitive *)new_prim.p(); 00586 00587 #ifndef NDEBUG 00588 if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { 00589 all_is_valid = false; 00590 } 00591 #endif 00592 } 00593 00594 cdata->_modified = Geom::get_next_modified(); 00595 clear_cache_stage(current_thread); 00596 00597 nassertv(all_is_valid); 00598 } 00599 00600 //////////////////////////////////////////////////////////////////// 00601 // Function: Geom::unify_in_place 00602 // Access: Published 00603 // Description: Unifies all of the primitives contained within this 00604 // Geom into a single (or as few as possible, within the 00605 // constraints of max_indices) primitive objects. This 00606 // may require decomposing the primitives if, for 00607 // instance, the Geom contains both triangle strips and 00608 // triangle fans. 00609 // 00610 // max_indices represents the maximum number of indices 00611 // that will be put in any one GeomPrimitive. If 00612 // preserve_order is true, then the primitives will not 00613 // be reordered during the operation, even if this 00614 // results in a suboptimal result. 00615 // 00616 // Don't call this in a downstream thread unless you 00617 // don't mind it blowing away other changes you might 00618 // have recently made in an upstream thread. 00619 //////////////////////////////////////////////////////////////////// 00620 void Geom:: 00621 unify_in_place(int max_indices, bool preserve_order) { 00622 if (gobj_cat.is_debug()) { 00623 gobj_cat.debug() 00624 << "unify_in_place(" << max_indices << ", " << preserve_order 00625 << "): " << *this << "\n"; 00626 } 00627 00628 Thread *current_thread = Thread::get_current_thread(); 00629 if (get_num_primitives() <= 1) { 00630 // If we don't have more than one primitive to start with, no need 00631 // to do anything. 00632 return; 00633 } 00634 00635 CDWriter cdata(_cycler, true, current_thread); 00636 00637 typedef pmap<TypeHandle, PT(GeomPrimitive) > NewPrims; 00638 00639 NewPrims new_prims; 00640 00641 bool keep_different_types = preserve_triangle_strips && !preserve_order; 00642 00643 Primitives::const_iterator pi; 00644 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { 00645 CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(); 00646 NewPrims::iterator npi = new_prims.find(primitive->get_type()); 00647 if (npi == new_prims.end()) { 00648 // This is the first primitive of this type. 00649 if (!keep_different_types && !new_prims.empty()) { 00650 // Actually, since we aren't trying to keep the different 00651 // types of primitives, we should try to combine this type and 00652 // the other type by decomposing them both (into triangles, 00653 // segments, or whatever). 00654 00655 // First, decompose the incoming one. 00656 primitive = primitive->decompose(); 00657 npi = new_prims.find(primitive->get_type()); 00658 if (npi == new_prims.end()) { 00659 // That didn't help, so decompose the one already in the 00660 // table. 00661 nassertv(new_prims.size() == 1); 00662 npi = new_prims.begin(); 00663 CPT(GeomPrimitive) np = (*npi).second->decompose(); 00664 new_prims.clear(); 00665 new_prims.insert(NewPrims::value_type(np->get_type(), np->make_copy())); 00666 npi = new_prims.find(primitive->get_type()); 00667 } 00668 } 00669 } 00670 00671 if (npi == new_prims.end()) { 00672 // This is the first primitive of this type. Just store it. 00673 new_prims.insert(NewPrims::value_type(primitive->get_type(), primitive->make_copy())); 00674 00675 } else { 00676 // We have already encountered another primitive of this type. 00677 // Combine them. 00678 combine_primitives((*npi).second, primitive, current_thread); 00679 } 00680 } 00681 00682 // Now, we have one or more primitives, but only one of each type. 00683 #ifndef NDEBUG 00684 if (!keep_different_types && new_prims.size() > 1) { 00685 // This shouldn't be possible, because we decompose as we go, in 00686 // the loop above. (We have to decompose as we go to preserve the 00687 // ordering of the primitives.) 00688 nassertv(false); 00689 } 00690 #endif 00691 00692 // Finally, iterate through the remaining primitives, and copy them 00693 // to the output list. 00694 cdata->_primitives.clear(); 00695 NewPrims::iterator npi; 00696 for (npi = new_prims.begin(); npi != new_prims.end(); ++npi) { 00697 GeomPrimitive *prim = (*npi).second; 00698 00699 nassertv(prim->check_valid(cdata->_data.get_read_pointer())); 00700 00701 // Each new primitive, naturally, inherits the Geom's overall 00702 // shade model. 00703 prim->set_shade_model(cdata->_shade_model); 00704 00705 // Should we split it up again to satisfy max_indices? 00706 if (prim->get_num_vertices() > max_indices) { 00707 // Copy prim into smaller prims, no one of which has more than 00708 // max_indices vertices. 00709 int i = 0; 00710 00711 while (i < prim->get_num_primitives()) { 00712 PT(GeomPrimitive) smaller = prim->make_copy(); 00713 smaller->clear_vertices(); 00714 while (i < prim->get_num_primitives() && 00715 smaller->get_num_vertices() + prim->get_primitive_num_vertices(i) < max_indices) { 00716 int start = prim->get_primitive_start(i); 00717 int end = prim->get_primitive_end(i); 00718 for (int n = start; n < end; ++n) { 00719 smaller->add_vertex(prim->get_vertex(n)); 00720 } 00721 smaller->close_primitive(); 00722 00723 ++i; 00724 } 00725 00726 cdata->_primitives.push_back(smaller.p()); 00727 } 00728 00729 } else { 00730 // The prim has few enough vertices; keep it. 00731 cdata->_primitives.push_back(prim); 00732 } 00733 } 00734 00735 cdata->_modified = Geom::get_next_modified(); 00736 clear_cache_stage(current_thread); 00737 reset_geom_rendering(cdata); 00738 } 00739 00740 //////////////////////////////////////////////////////////////////// 00741 // Function: Geom::make_points_in_place 00742 // Access: Published 00743 // Description: Replaces the GeomPrimitives within this Geom with 00744 // corresponding GeomPoints. See 00745 // GeomPrimitive::make_points(). 00746 // 00747 // Don't call this in a downstream thread unless you 00748 // don't mind it blowing away other changes you might 00749 // have recently made in an upstream thread. 00750 //////////////////////////////////////////////////////////////////// 00751 void Geom:: 00752 make_points_in_place() { 00753 Thread *current_thread = Thread::get_current_thread(); 00754 CDWriter cdata(_cycler, true, current_thread); 00755 00756 #ifndef NDEBUG 00757 bool all_is_valid = true; 00758 #endif 00759 Primitives::iterator pi; 00760 for (pi = cdata->_primitives.begin(); pi != cdata->_primitives.end(); ++pi) { 00761 CPT(GeomPrimitive) new_prim = (*pi).get_read_pointer()->make_points(); 00762 (*pi) = (GeomPrimitive *)new_prim.p(); 00763 00764 #ifndef NDEBUG 00765 if (!new_prim->check_valid(cdata->_data.get_read_pointer())) { 00766 all_is_valid = false; 00767 } 00768 #endif 00769 } 00770 00771 cdata->_modified = Geom::get_next_modified(); 00772 reset_geom_rendering(cdata); 00773 clear_cache_stage(current_thread); 00774 00775 nassertv(all_is_valid); 00776 } 00777 00778 00779 //////////////////////////////////////////////////////////////////// 00780 // Function: Geom::copy_primitives_from 00781 // Access: Published, Virtual 00782 // Description: Copies the primitives from the indicated Geom into 00783 // this one. This does require that both Geoms contain 00784 // the same fundamental type primitives, both have a 00785 // compatible shade model, and both use the same 00786 // GeomVertexData. Both Geoms must also be the same 00787 // specific class type (i.e. if one is a GeomTextGlyph, 00788 // they both must be.) 00789 // 00790 // Returns true if the copy is successful, or false 00791 // otherwise (because the Geoms were mismatched). 00792 //////////////////////////////////////////////////////////////////// 00793 bool Geom:: 00794 copy_primitives_from(const Geom *other) { 00795 if (get_primitive_type() != PT_none && 00796 other->get_primitive_type() != get_primitive_type()) { 00797 return false; 00798 } 00799 if (get_vertex_data() != other->get_vertex_data()) { 00800 return false; 00801 } 00802 if (get_type() != other->get_type()) { 00803 return false; 00804 } 00805 00806 ShadeModel this_shade_model = get_shade_model(); 00807 ShadeModel other_shade_model = other->get_shade_model(); 00808 if (this_shade_model != SM_uniform && other_shade_model != SM_uniform && 00809 this_shade_model != other_shade_model) { 00810 if ((this_shade_model == SM_flat_first_vertex && other_shade_model == SM_flat_last_vertex) || 00811 (this_shade_model == SM_flat_last_vertex && other_shade_model == SM_flat_first_vertex)) { 00812 // This is acceptable; we can rotate the primitives to match. 00813 00814 } else { 00815 // Otherwise, we have incompatible shade models. 00816 return false; 00817 } 00818 } 00819 00820 int num_primitives = other->get_num_primitives(); 00821 for (int i = 0; i < num_primitives; i++) { 00822 add_primitive(other->get_primitive(i)); 00823 } 00824 00825 return true; 00826 } 00827 00828 //////////////////////////////////////////////////////////////////// 00829 // Function: Geom::get_num_bytes 00830 // Access: Published 00831 // Description: Returns the number of bytes consumed by the geom and 00832 // its primitives (but not including its vertex table). 00833 //////////////////////////////////////////////////////////////////// 00834 int Geom:: 00835 get_num_bytes() const { 00836 CDReader cdata(_cycler); 00837 00838 int num_bytes = sizeof(Geom); 00839 Primitives::const_iterator pi; 00840 for (pi = cdata->_primitives.begin(); 00841 pi != cdata->_primitives.end(); 00842 ++pi) { 00843 num_bytes += (*pi).get_read_pointer()->get_num_bytes(); 00844 } 00845 00846 return num_bytes; 00847 } 00848 00849 //////////////////////////////////////////////////////////////////// 00850 // Function: Geom::request_resident 00851 // Access: Published 00852 // Description: Returns true if all the primitive arrays are 00853 // currently resident in memory. If this returns false, 00854 // the data will be brought back into memory shortly; 00855 // try again later. 00856 // 00857 // This does not also test the Geom's associated 00858 // GeomVertexData. That must be tested separately. 00859 //////////////////////////////////////////////////////////////////// 00860 bool Geom:: 00861 request_resident() const { 00862 CDReader cdata(_cycler); 00863 00864 bool resident = true; 00865 00866 Primitives::const_iterator pi; 00867 for (pi = cdata->_primitives.begin(); 00868 pi != cdata->_primitives.end(); 00869 ++pi) { 00870 if (!(*pi).get_read_pointer()->request_resident()) { 00871 resident = false; 00872 } 00873 } 00874 00875 return resident; 00876 } 00877 00878 //////////////////////////////////////////////////////////////////// 00879 // Function: Geom::transform_vertices 00880 // Access: Published 00881 // Description: Applies the indicated transform to all of the 00882 // vertices in the Geom. If the Geom happens to share a 00883 // vertex table with another Geom, this operation will 00884 // duplicate the vertex table instead of breaking the 00885 // other Geom; however, if multiple Geoms with shared 00886 // tables are transformed by the same matrix, they will 00887 // no longer share tables after the operation. Consider 00888 // using the GeomTransformer if you will be applying the 00889 // same transform to multiple Geoms. 00890 //////////////////////////////////////////////////////////////////// 00891 void Geom:: 00892 transform_vertices(const LMatrix4 &mat) { 00893 PT(GeomVertexData) new_data = modify_vertex_data(); 00894 CPT(GeomVertexFormat) format = new_data->get_format(); 00895 00896 int ci; 00897 for (ci = 0; ci < format->get_num_points(); ci++) { 00898 GeomVertexRewriter data(new_data, format->get_point(ci)); 00899 00900 while (!data.is_at_end()) { 00901 const LPoint3 &point = data.get_data3(); 00902 data.set_data3(point * mat); 00903 } 00904 } 00905 for (ci = 0; ci < format->get_num_vectors(); ci++) { 00906 GeomVertexRewriter data(new_data, format->get_vector(ci)); 00907 00908 while (!data.is_at_end()) { 00909 const LVector3 &vector = data.get_data3(); 00910 data.set_data3(normalize(vector * mat)); 00911 } 00912 } 00913 } 00914 00915 //////////////////////////////////////////////////////////////////// 00916 // Function: Geom::check_valid 00917 // Access: Published 00918 // Description: Verifies that the all of the primitives within the 00919 // geom reference vertices that actually exist within 00920 // the geom's GeomVertexData. Returns true if the geom 00921 // appears to be valid, false otherwise. 00922 //////////////////////////////////////////////////////////////////// 00923 bool Geom:: 00924 check_valid() const { 00925 Thread *current_thread = Thread::get_current_thread(); 00926 GeomPipelineReader geom_reader(this, current_thread); 00927 GeomVertexDataPipelineReader data_reader(geom_reader.get_vertex_data(), current_thread); 00928 data_reader.check_array_readers(); 00929 return geom_reader.check_valid(&data_reader); 00930 } 00931 00932 //////////////////////////////////////////////////////////////////// 00933 // Function: Geom::check_valid 00934 // Access: Published 00935 // Description: Verifies that the all of the primitives within the 00936 // geom reference vertices that actually exist within 00937 // the indicated GeomVertexData. Returns true if the 00938 // geom appears to be valid, false otherwise. 00939 //////////////////////////////////////////////////////////////////// 00940 bool Geom:: 00941 check_valid(const GeomVertexData *vertex_data) const { 00942 Thread *current_thread = Thread::get_current_thread(); 00943 GeomPipelineReader geom_reader(this, current_thread); 00944 GeomVertexDataPipelineReader data_reader(vertex_data, current_thread); 00945 data_reader.check_array_readers(); 00946 return geom_reader.check_valid(&data_reader); 00947 } 00948 00949 //////////////////////////////////////////////////////////////////// 00950 // Function: Geom::get_bounds 00951 // Access: Published 00952 // Description: Returns the bounding volume for the Geom. 00953 //////////////////////////////////////////////////////////////////// 00954 CPT(BoundingVolume) Geom:: 00955 get_bounds(Thread *current_thread) const { 00956 CDLockedReader cdata(_cycler, current_thread); 00957 if (cdata->_user_bounds != (BoundingVolume *)NULL) { 00958 return cdata->_user_bounds; 00959 } 00960 00961 if (cdata->_internal_bounds_stale) { 00962 CDWriter cdataw(((Geom *)this)->_cycler, cdata, false); 00963 compute_internal_bounds(cdataw, current_thread); 00964 return cdataw->_internal_bounds; 00965 } 00966 return cdata->_internal_bounds; 00967 } 00968 00969 //////////////////////////////////////////////////////////////////// 00970 // Function: Geom::get_nested_vertices 00971 // Access: Published 00972 // Description: Returns the number of vertices rendered by all 00973 // primitives within the Geom. 00974 //////////////////////////////////////////////////////////////////// 00975 int Geom:: 00976 get_nested_vertices(Thread *current_thread) const { 00977 CDLockedReader cdata(_cycler, current_thread); 00978 if (cdata->_internal_bounds_stale) { 00979 CDWriter cdataw(((Geom *)this)->_cycler, cdata, false); 00980 compute_internal_bounds(cdataw, current_thread); 00981 return cdataw->_nested_vertices; 00982 } 00983 return cdata->_nested_vertices; 00984 } 00985 00986 //////////////////////////////////////////////////////////////////// 00987 // Function: Geom::output 00988 // Access: Published, Virtual 00989 // Description: 00990 //////////////////////////////////////////////////////////////////// 00991 void Geom:: 00992 output(ostream &out) const { 00993 CDReader cdata(_cycler); 00994 00995 // Get a list of the primitive types contained within this object. 00996 int num_faces = 0; 00997 pset<TypeHandle> types; 00998 Primitives::const_iterator pi; 00999 for (pi = cdata->_primitives.begin(); 01000 pi != cdata->_primitives.end(); 01001 ++pi) { 01002 CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); 01003 num_faces += prim->get_num_faces(); 01004 types.insert(prim->get_type()); 01005 } 01006 01007 out << get_type() << " ["; 01008 pset<TypeHandle>::iterator ti; 01009 for (ti = types.begin(); ti != types.end(); ++ti) { 01010 out << " " << (*ti); 01011 } 01012 out << " ], " << num_faces << " faces"; 01013 } 01014 01015 //////////////////////////////////////////////////////////////////// 01016 // Function: Geom::write 01017 // Access: Published, Virtual 01018 // Description: 01019 //////////////////////////////////////////////////////////////////// 01020 void Geom:: 01021 write(ostream &out, int indent_level) const { 01022 CDReader cdata(_cycler); 01023 01024 // Get a list of the primitive types contained within this object. 01025 Primitives::const_iterator pi; 01026 for (pi = cdata->_primitives.begin(); 01027 pi != cdata->_primitives.end(); 01028 ++pi) { 01029 (*pi).get_read_pointer()->write(out, indent_level); 01030 } 01031 } 01032 01033 //////////////////////////////////////////////////////////////////// 01034 // Function: Geom::clear_cache 01035 // Access: Published 01036 // Description: Removes all of the previously-cached results of 01037 // munge_geom(). 01038 // 01039 // This blows away the entire cache, upstream and 01040 // downstream the pipeline. Use clear_cache_stage() 01041 // instead if you only want to blow away the cache at 01042 // the current stage and upstream. 01043 //////////////////////////////////////////////////////////////////// 01044 void Geom:: 01045 clear_cache() { 01046 LightMutexHolder holder(_cache_lock); 01047 for (Cache::iterator ci = _cache.begin(); 01048 ci != _cache.end(); 01049 ++ci) { 01050 CacheEntry *entry = (*ci).second; 01051 entry->erase(); 01052 } 01053 _cache.clear(); 01054 } 01055 01056 //////////////////////////////////////////////////////////////////// 01057 // Function: Geom::clear_cache_stage 01058 // Access: Published 01059 // Description: Removes all of the previously-cached results of 01060 // munge_geom(), at the current pipeline stage and 01061 // upstream. Does not affect the downstream cache. 01062 // 01063 // Don't call this in a downstream thread unless you 01064 // don't mind it blowing away other changes you might 01065 // have recently made in an upstream thread. 01066 //////////////////////////////////////////////////////////////////// 01067 void Geom:: 01068 clear_cache_stage(Thread *current_thread) { 01069 LightMutexHolder holder(_cache_lock); 01070 for (Cache::iterator ci = _cache.begin(); 01071 ci != _cache.end(); 01072 ++ci) { 01073 CacheEntry *entry = (*ci).second; 01074 CDCacheWriter cdata(entry->_cycler, current_thread); 01075 cdata->set_result(NULL, NULL); 01076 } 01077 } 01078 01079 //////////////////////////////////////////////////////////////////// 01080 // Function: Geom::prepare 01081 // Access: Published 01082 // Description: Indicates that the geom should be enqueued to be 01083 // prepared in the indicated prepared_objects at the 01084 // beginning of the next frame. This will ensure the 01085 // geom is already loaded into geom memory if it 01086 // is expected to be rendered soon. 01087 // 01088 // Use this function instead of prepare_now() to preload 01089 // geoms from a user interface standpoint. 01090 //////////////////////////////////////////////////////////////////// 01091 void Geom:: 01092 prepare(PreparedGraphicsObjects *prepared_objects) { 01093 prepared_objects->enqueue_geom(this); 01094 } 01095 01096 //////////////////////////////////////////////////////////////////// 01097 // Function: Geom::is_prepared 01098 // Access: Published 01099 // Description: Returns true if the geom has already been prepared 01100 // or enqueued for preparation on the indicated GSG, 01101 // false otherwise. 01102 //////////////////////////////////////////////////////////////////// 01103 bool Geom:: 01104 is_prepared(PreparedGraphicsObjects *prepared_objects) const { 01105 Contexts::const_iterator ci; 01106 ci = _contexts.find(prepared_objects); 01107 if (ci != _contexts.end()) { 01108 return true; 01109 } 01110 return prepared_objects->is_geom_queued(this); 01111 } 01112 01113 //////////////////////////////////////////////////////////////////// 01114 // Function: Geom::release 01115 // Access: Published 01116 // Description: Frees the geom context only on the indicated object, 01117 // if it exists there. Returns true if it was released, 01118 // false if it had not been prepared. 01119 //////////////////////////////////////////////////////////////////// 01120 bool Geom:: 01121 release(PreparedGraphicsObjects *prepared_objects) { 01122 Contexts::iterator ci; 01123 ci = _contexts.find(prepared_objects); 01124 if (ci != _contexts.end()) { 01125 GeomContext *gc = (*ci).second; 01126 prepared_objects->release_geom(gc); 01127 return true; 01128 } 01129 01130 // Maybe it wasn't prepared yet, but it's about to be. 01131 return prepared_objects->dequeue_geom(this); 01132 } 01133 01134 //////////////////////////////////////////////////////////////////// 01135 // Function: Geom::release_all 01136 // Access: Published 01137 // Description: Frees the context allocated on all objects for which 01138 // the geom has been declared. Returns the number of 01139 // contexts which have been freed. 01140 //////////////////////////////////////////////////////////////////// 01141 int Geom:: 01142 release_all() { 01143 // We have to traverse a copy of the _contexts list, because the 01144 // PreparedGraphicsObjects object will call clear_prepared() in response 01145 // to each release_geom(), and we don't want to be modifying the 01146 // _contexts list while we're traversing it. 01147 Contexts temp = _contexts; 01148 int num_freed = (int)_contexts.size(); 01149 01150 Contexts::const_iterator ci; 01151 for (ci = temp.begin(); ci != temp.end(); ++ci) { 01152 PreparedGraphicsObjects *prepared_objects = (*ci).first; 01153 GeomContext *gc = (*ci).second; 01154 prepared_objects->release_geom(gc); 01155 } 01156 01157 // Now that we've called release_geom() on every known context, 01158 // the _contexts list should have completely emptied itself. 01159 nassertr(_contexts.empty(), num_freed); 01160 01161 return num_freed; 01162 } 01163 01164 //////////////////////////////////////////////////////////////////// 01165 // Function: Geom::prepare_now 01166 // Access: Public 01167 // Description: Creates a context for the geom on the particular 01168 // GSG, if it does not already exist. Returns the new 01169 // (or old) GeomContext. This assumes that the 01170 // GraphicsStateGuardian is the currently active 01171 // rendering context and that it is ready to accept new 01172 // geoms. If this is not necessarily the case, you 01173 // should use prepare() instead. 01174 // 01175 // Normally, this is not called directly except by the 01176 // GraphicsStateGuardian; a geom does not need to be 01177 // explicitly prepared by the user before it may be 01178 // rendered. 01179 //////////////////////////////////////////////////////////////////// 01180 GeomContext *Geom:: 01181 prepare_now(PreparedGraphicsObjects *prepared_objects, 01182 GraphicsStateGuardianBase *gsg) { 01183 Contexts::const_iterator ci; 01184 ci = _contexts.find(prepared_objects); 01185 if (ci != _contexts.end()) { 01186 return (*ci).second; 01187 } 01188 01189 GeomContext *gc = prepared_objects->prepare_geom_now(this, gsg); 01190 if (gc != (GeomContext *)NULL) { 01191 _contexts[prepared_objects] = gc; 01192 } 01193 return gc; 01194 } 01195 01196 //////////////////////////////////////////////////////////////////// 01197 // Function: Geom::draw 01198 // Access: Public 01199 // Description: Actually draws the Geom with the indicated GSG, using 01200 // the indicated vertex data (which might have been 01201 // pre-munged to support the GSG's needs). 01202 // 01203 // Returns true if all of the primitives were drawn 01204 // normally, false if there was a problem (for instance, 01205 // some of the data was nonresident). If force is 01206 // passed true, it will wait for the data to become 01207 // resident if necessary. 01208 //////////////////////////////////////////////////////////////////// 01209 bool Geom:: 01210 draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger, 01211 const GeomVertexData *vertex_data, bool force, 01212 Thread *current_thread) const { 01213 GeomPipelineReader geom_reader(this, current_thread); 01214 geom_reader.check_usage_hint(); 01215 01216 GeomVertexDataPipelineReader data_reader(vertex_data, current_thread); 01217 data_reader.check_array_readers(); 01218 01219 return geom_reader.draw(gsg, munger, &data_reader, force); 01220 } 01221 01222 //////////////////////////////////////////////////////////////////// 01223 // Function: Geom::get_next_modified 01224 // Access: Public, Static 01225 // Description: Returns a monotonically increasing sequence. Each 01226 // time this is called, a new sequence number is 01227 // returned, higher than the previous value. 01228 // 01229 // This is used to ensure that 01230 // GeomVertexArrayData::get_modified() and 01231 // GeomPrimitive::get_modified() update from the same 01232 // space, so that Geom::get_modified() returns a 01233 // meaningful value. 01234 //////////////////////////////////////////////////////////////////// 01235 UpdateSeq Geom:: 01236 get_next_modified() { 01237 ++_next_modified; 01238 return _next_modified; 01239 } 01240 01241 //////////////////////////////////////////////////////////////////// 01242 // Function: Geom::compute_internal_bounds 01243 // Access: Private 01244 // Description: Recomputes the dynamic bounding volume for this Geom. 01245 // This includes all of the vertices. 01246 //////////////////////////////////////////////////////////////////// 01247 void Geom:: 01248 compute_internal_bounds(Geom::CData *cdata, Thread *current_thread) const { 01249 int num_vertices = 0; 01250 01251 // Get the vertex data, after animation. 01252 CPT(GeomVertexData) vertex_data = cdata->_data.get_read_pointer(); 01253 vertex_data = vertex_data->animate_vertices(true, current_thread); 01254 01255 // Now actually compute the bounding volume. We do this by using 01256 // calc_tight_bounds to determine our box first. 01257 LPoint3 min, max; 01258 bool found_any = false; 01259 do_calc_tight_bounds(min, max, found_any, vertex_data, 01260 false, LMatrix4::ident_mat(), 01261 InternalName::get_vertex(), 01262 cdata, current_thread); 01263 01264 BoundingVolume::BoundsType btype = cdata->_bounds_type; 01265 if (btype == BoundingVolume::BT_default) { 01266 btype = bounds_type; 01267 } 01268 01269 if (found_any) { 01270 // Then we put the bounding volume around both of those points. 01271 if (btype == BoundingVolume::BT_sphere) { 01272 // The user specifically requested a BoundingSphere, so oblige. 01273 BoundingBox box(min, max); 01274 box.local_object(); 01275 01276 PT(BoundingSphere) sphere = new BoundingSphere; 01277 sphere->extend_by(&box); 01278 cdata->_internal_bounds = sphere; 01279 01280 } else { 01281 // The user requested a BoundingBox, or did not specify. 01282 cdata->_internal_bounds = new BoundingBox(min, max); 01283 } 01284 01285 Primitives::const_iterator pi; 01286 for (pi = cdata->_primitives.begin(); 01287 pi != cdata->_primitives.end(); 01288 ++pi) { 01289 CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); 01290 num_vertices += prim->get_num_vertices(); 01291 } 01292 01293 } else { 01294 // No points; empty bounding volume. 01295 if (btype == BoundingVolume::BT_sphere) { 01296 cdata->_internal_bounds = new BoundingSphere; 01297 } else { 01298 cdata->_internal_bounds = new BoundingBox; 01299 } 01300 } 01301 01302 cdata->_nested_vertices = num_vertices; 01303 cdata->_internal_bounds_stale = false; 01304 } 01305 01306 //////////////////////////////////////////////////////////////////// 01307 // Function: Geom::do_calc_tight_bounds 01308 // Access: Private 01309 // Description: The private implementation of calc_tight_bounds(). 01310 //////////////////////////////////////////////////////////////////// 01311 void Geom:: 01312 do_calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, 01313 bool &found_any, 01314 const GeomVertexData *vertex_data, 01315 bool got_mat, const LMatrix4 &mat, 01316 const InternalName *column_name, 01317 const CData *cdata, Thread *current_thread) const { 01318 Primitives::const_iterator pi; 01319 for (pi = cdata->_primitives.begin(); 01320 pi != cdata->_primitives.end(); 01321 ++pi) { 01322 CPT(GeomPrimitive) prim = (*pi).get_read_pointer(); 01323 prim->calc_tight_bounds(min_point, max_point, found_any, vertex_data, 01324 got_mat, mat, column_name, current_thread); 01325 } 01326 } 01327 01328 //////////////////////////////////////////////////////////////////// 01329 // Function: Geom::clear_prepared 01330 // Access: Private 01331 // Description: Removes the indicated PreparedGraphicsObjects table 01332 // from the Geom's table, without actually releasing 01333 // the geom. This is intended to be called only from 01334 // PreparedGraphicsObjects::release_geom(); it should 01335 // never be called by user code. 01336 //////////////////////////////////////////////////////////////////// 01337 void Geom:: 01338 clear_prepared(PreparedGraphicsObjects *prepared_objects) { 01339 Contexts::iterator ci; 01340 ci = _contexts.find(prepared_objects); 01341 if (ci != _contexts.end()) { 01342 _contexts.erase(ci); 01343 } else { 01344 // If this assertion fails, clear_prepared() was given a 01345 // prepared_objects that the geom didn't know about. 01346 nassertv(false); 01347 } 01348 } 01349 01350 //////////////////////////////////////////////////////////////////// 01351 // Function: Geom::check_will_be_valid 01352 // Access: Private 01353 // Description: Verifies that the all of the primitives within the 01354 // geom reference vertices that actually exist within 01355 // the indicated GeomVertexData (presumably in 01356 // preparation for assigning the geom to use this data). 01357 // Returns true if the data appears to be valid, false 01358 // otherwise. 01359 //////////////////////////////////////////////////////////////////// 01360 bool Geom:: 01361 check_will_be_valid(const GeomVertexData *vertex_data) const { 01362 CDReader cdata(_cycler); 01363 01364 Primitives::const_iterator pi; 01365 for (pi = cdata->_primitives.begin(); 01366 pi != cdata->_primitives.end(); 01367 ++pi) { 01368 if (!(*pi).get_read_pointer()->check_valid(vertex_data)) { 01369 return false; 01370 } 01371 } 01372 01373 return true; 01374 } 01375 01376 //////////////////////////////////////////////////////////////////// 01377 // Function: Geom::reset_usage_hint 01378 // Access: Private 01379 // Description: Recomputes the minimum usage_hint. 01380 //////////////////////////////////////////////////////////////////// 01381 void Geom:: 01382 reset_usage_hint(Geom::CData *cdata) { 01383 cdata->_usage_hint = UH_unspecified; 01384 Primitives::const_iterator pi; 01385 for (pi = cdata->_primitives.begin(); 01386 pi != cdata->_primitives.end(); 01387 ++pi) { 01388 cdata->_usage_hint = min(cdata->_usage_hint, 01389 (*pi).get_read_pointer()->get_usage_hint()); 01390 } 01391 cdata->_got_usage_hint = true; 01392 } 01393 01394 //////////////////////////////////////////////////////////////////// 01395 // Function: Geom::reset_geom_rendering 01396 // Access: Private 01397 // Description: Rederives the _geom_rendering member. 01398 //////////////////////////////////////////////////////////////////// 01399 void Geom:: 01400 reset_geom_rendering(Geom::CData *cdata) { 01401 cdata->_geom_rendering = 0; 01402 Primitives::const_iterator pi; 01403 for (pi = cdata->_primitives.begin(); 01404 pi != cdata->_primitives.end(); 01405 ++pi) { 01406 cdata->_geom_rendering |= (*pi).get_read_pointer()->get_geom_rendering(); 01407 } 01408 01409 if ((cdata->_geom_rendering & GR_point) != 0) { 01410 CPT(GeomVertexData) data = cdata->_data.get_read_pointer(); 01411 if (data->has_column(InternalName::get_size())) { 01412 cdata->_geom_rendering |= GR_per_point_size; 01413 } 01414 if (data->has_column(InternalName::get_aspect_ratio())) { 01415 cdata->_geom_rendering |= GR_point_aspect_ratio; 01416 } 01417 if (data->has_column(InternalName::get_rotate())) { 01418 cdata->_geom_rendering |= GR_point_rotate; 01419 } 01420 } 01421 01422 switch (get_shade_model()) { 01423 case SM_flat_first_vertex: 01424 cdata->_geom_rendering |= GR_flat_first_vertex; 01425 break; 01426 01427 case SM_flat_last_vertex: 01428 cdata->_geom_rendering |= GR_flat_last_vertex; 01429 break; 01430 01431 default: 01432 break; 01433 } 01434 } 01435 01436 //////////////////////////////////////////////////////////////////// 01437 // Function: Geom::combine_primitives 01438 // Access: Private 01439 // Description: Combines two primitives of the same type into a 01440 // single primitive. a_prim is modified to append the 01441 // vertices from b_prim, which is unmodified. 01442 //////////////////////////////////////////////////////////////////// 01443 void Geom:: 01444 combine_primitives(GeomPrimitive *a_prim, const GeomPrimitive *b_prim, 01445 Thread *current_thread) { 01446 nassertv(a_prim != b_prim); 01447 nassertv(a_prim->get_type() == b_prim->get_type()); 01448 01449 CPT(GeomPrimitive) b_prim2 = b_prim; 01450 01451 if (a_prim->get_index_type() != b_prim2->get_index_type()) { 01452 GeomPrimitive::NumericType index_type = max(a_prim->get_index_type(), b_prim2->get_index_type()); 01453 a_prim->set_index_type(index_type); 01454 if (b_prim2->get_index_type() != index_type) { 01455 PT(GeomPrimitive) b_prim_copy = b_prim2->make_copy(); 01456 b_prim_copy->set_index_type(index_type); 01457 b_prim2 = b_prim_copy; 01458 } 01459 } 01460 01461 if (!b_prim2->is_indexed()) { 01462 PT(GeomPrimitive) b_prim_copy = b_prim2->make_copy(); 01463 b_prim_copy->make_indexed(); 01464 b_prim2 = b_prim_copy; 01465 } 01466 01467 PT(GeomVertexArrayData) a_vertices = a_prim->modify_vertices(); 01468 CPT(GeomVertexArrayData) b_vertices = b_prim2->get_vertices(); 01469 01470 if (a_prim->requires_unused_vertices()) { 01471 GeomVertexReader index(b_vertices, 0); 01472 int b_vertex = index.get_data1i(); 01473 a_prim->append_unused_vertices(a_vertices, b_vertex); 01474 } 01475 01476 PT(GeomVertexArrayDataHandle) a_handle = a_vertices->modify_handle(current_thread); 01477 CPT(GeomVertexArrayDataHandle) b_handle = b_vertices->get_handle(current_thread); 01478 01479 size_t orig_a_vertices = a_handle->get_num_rows(); 01480 01481 a_handle->copy_subdata_from(a_handle->get_data_size_bytes(), 0, 01482 b_handle, 0, b_handle->get_data_size_bytes()); 01483 a_prim->clear_minmax(); 01484 if (a_prim->is_composite()) { 01485 // Also copy the ends array. 01486 PTA_int a_ends = a_prim->modify_ends(); 01487 CPTA_int b_ends = b_prim2->get_ends(); 01488 for (size_t i = 0; i < b_ends.size(); ++i) { 01489 a_ends.push_back(b_ends[i] + orig_a_vertices); 01490 } 01491 } 01492 } 01493 01494 //////////////////////////////////////////////////////////////////// 01495 // Function: Geom::register_with_read_factory 01496 // Access: Public, Static 01497 // Description: Tells the BamReader how to create objects of type 01498 // Geom. 01499 //////////////////////////////////////////////////////////////////// 01500 void Geom:: 01501 register_with_read_factory() { 01502 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam); 01503 } 01504 01505 //////////////////////////////////////////////////////////////////// 01506 // Function: Geom::write_datagram 01507 // Access: Public, Virtual 01508 // Description: Writes the contents of this object to the datagram 01509 // for shipping out to a Bam file. 01510 //////////////////////////////////////////////////////////////////// 01511 void Geom:: 01512 write_datagram(BamWriter *manager, Datagram &dg) { 01513 TypedWritable::write_datagram(manager, dg); 01514 01515 manager->write_cdata(dg, _cycler); 01516 } 01517 01518 //////////////////////////////////////////////////////////////////// 01519 // Function: Geom::make_from_bam 01520 // Access: Protected, Static 01521 // Description: This function is called by the BamReader's factory 01522 // when a new object of type Geom is encountered 01523 // in the Bam file. It should create the Geom 01524 // and extract its information from the file. 01525 //////////////////////////////////////////////////////////////////// 01526 TypedWritable *Geom:: 01527 make_from_bam(const FactoryParams ¶ms) { 01528 Geom *object = new Geom(NULL); 01529 DatagramIterator scan; 01530 BamReader *manager; 01531 01532 parse_params(params, scan, manager); 01533 object->fillin(scan, manager); 01534 manager->register_finalize(object); 01535 01536 return object; 01537 } 01538 01539 //////////////////////////////////////////////////////////////////// 01540 // Function: Geom::finalize 01541 // Access: Public, Virtual 01542 // Description: Called by the BamReader to perform any final actions 01543 // needed for setting up the object after all objects 01544 // have been read and all pointers have been completed. 01545 //////////////////////////////////////////////////////////////////// 01546 void Geom:: 01547 finalize(BamReader *manager) { 01548 CDWriter cdata(_cycler, true); 01549 01550 // Make sure our GeomVertexData is finalized first. This may result 01551 // in the data getting finalized multiple times, but it doesn't mind 01552 // that. 01553 if (!cdata->_data.is_null()) { 01554 // We shouldn't call get_write_pointer(), which might replicate 01555 // the GeomVertexData unnecessarily. 01556 cdata->_data.get_unsafe_pointer()->finalize(manager); 01557 } 01558 01559 reset_geom_rendering(cdata); 01560 } 01561 01562 //////////////////////////////////////////////////////////////////// 01563 // Function: Geom::fillin 01564 // Access: Protected 01565 // Description: This internal function is called by make_from_bam to 01566 // read in all of the relevant data from the BamFile for 01567 // the new Geom. 01568 //////////////////////////////////////////////////////////////////// 01569 void Geom:: 01570 fillin(DatagramIterator &scan, BamReader *manager) { 01571 TypedWritable::fillin(scan, manager); 01572 01573 manager->read_cdata(scan, _cycler); 01574 } 01575 01576 //////////////////////////////////////////////////////////////////// 01577 // Function: Geom::CDataCache::Destructor 01578 // Access: Public, Virtual 01579 // Description: 01580 //////////////////////////////////////////////////////////////////// 01581 Geom::CDataCache:: 01582 ~CDataCache() { 01583 set_result(NULL, NULL); 01584 } 01585 01586 //////////////////////////////////////////////////////////////////// 01587 // Function: Geom::CDataCache::make_copy 01588 // Access: Public, Virtual 01589 // Description: 01590 //////////////////////////////////////////////////////////////////// 01591 CycleData *Geom::CDataCache:: 01592 make_copy() const { 01593 return new CDataCache(*this); 01594 } 01595 01596 //////////////////////////////////////////////////////////////////// 01597 // Function: Geom::CacheEntry::evict_callback 01598 // Access: Public, Virtual 01599 // Description: Called when the entry is evicted from the cache, this 01600 // should clean up the owning object appropriately. 01601 //////////////////////////////////////////////////////////////////// 01602 void Geom::CacheEntry:: 01603 evict_callback() { 01604 LightMutexHolder holder(_source->_cache_lock); 01605 Cache::iterator ci = _source->_cache.find(&_key); 01606 nassertv(ci != _source->_cache.end()); 01607 nassertv((*ci).second == this); 01608 _source->_cache.erase(ci); 01609 } 01610 01611 //////////////////////////////////////////////////////////////////// 01612 // Function: Geom::CacheEntry::output 01613 // Access: Public, Virtual 01614 // Description: 01615 //////////////////////////////////////////////////////////////////// 01616 void Geom::CacheEntry:: 01617 output(ostream &out) const { 01618 out << "geom " << (void *)_source << ", " 01619 << (const void *)_key._modifier; 01620 } 01621 01622 01623 //////////////////////////////////////////////////////////////////// 01624 // Function: Geom::CData::make_copy 01625 // Access: Public, Virtual 01626 // Description: 01627 //////////////////////////////////////////////////////////////////// 01628 CycleData *Geom::CData:: 01629 make_copy() const { 01630 return new CData(*this); 01631 } 01632 01633 //////////////////////////////////////////////////////////////////// 01634 // Function: Geom::CData::write_datagram 01635 // Access: Public, Virtual 01636 // Description: Writes the contents of this object to the datagram 01637 // for shipping out to a Bam file. 01638 //////////////////////////////////////////////////////////////////// 01639 void Geom::CData:: 01640 write_datagram(BamWriter *manager, Datagram &dg) const { 01641 manager->write_pointer(dg, _data.get_read_pointer()); 01642 01643 dg.add_uint16(_primitives.size()); 01644 Primitives::const_iterator pi; 01645 for (pi = _primitives.begin(); pi != _primitives.end(); ++pi) { 01646 manager->write_pointer(dg, (*pi).get_read_pointer()); 01647 } 01648 01649 dg.add_uint8(_primitive_type); 01650 dg.add_uint8(_shade_model); 01651 01652 // Actually, we shouldn't bother writing out _geom_rendering; we'll 01653 // just throw it away anyway. 01654 dg.add_uint16(_geom_rendering); 01655 01656 dg.add_uint8(_bounds_type); 01657 } 01658 01659 //////////////////////////////////////////////////////////////////// 01660 // Function: Geom::CData::complete_pointers 01661 // Access: Public, Virtual 01662 // Description: Receives an array of pointers, one for each time 01663 // manager->read_pointer() was called in fillin(). 01664 // Returns the number of pointers processed. 01665 //////////////////////////////////////////////////////////////////// 01666 int Geom::CData:: 01667 complete_pointers(TypedWritable **p_list, BamReader *manager) { 01668 int pi = CycleData::complete_pointers(p_list, manager); 01669 01670 _data = DCAST(GeomVertexData, p_list[pi++]); 01671 01672 Primitives::iterator pri; 01673 for (pri = _primitives.begin(); pri != _primitives.end(); ++pri) { 01674 (*pri) = DCAST(GeomPrimitive, p_list[pi++]); 01675 } 01676 01677 return pi; 01678 } 01679 01680 //////////////////////////////////////////////////////////////////// 01681 // Function: Geom::CData::fillin 01682 // Access: Public, Virtual 01683 // Description: This internal function is called by make_from_bam to 01684 // read in all of the relevant data from the BamFile for 01685 // the new Geom. 01686 //////////////////////////////////////////////////////////////////// 01687 void Geom::CData:: 01688 fillin(DatagramIterator &scan, BamReader *manager) { 01689 manager->read_pointer(scan); 01690 01691 int num_primitives = scan.get_uint16(); 01692 _primitives.reserve(num_primitives); 01693 for (int i = 0; i < num_primitives; ++i) { 01694 manager->read_pointer(scan); 01695 _primitives.push_back(NULL); 01696 } 01697 01698 _primitive_type = (PrimitiveType)scan.get_uint8(); 01699 _shade_model = (ShadeModel)scan.get_uint8(); 01700 01701 // To be removed: we no longer read _geom_rendering from the bam 01702 // file; instead, we rederive it in finalize(). 01703 scan.get_uint16(); 01704 01705 _got_usage_hint = false; 01706 _modified = Geom::get_next_modified(); 01707 01708 _bounds_type = BoundingVolume::BT_default; 01709 if (manager->get_file_minor_ver() >= 19) { 01710 _bounds_type = (BoundingVolume::BoundsType)scan.get_uint8(); 01711 } 01712 } 01713 01714 //////////////////////////////////////////////////////////////////// 01715 // Function: GeomPipelineReader::check_usage_hint 01716 // Access: Public 01717 // Description: Ensures that the Geom's usage_hint cache has been 01718 // computed. 01719 //////////////////////////////////////////////////////////////////// 01720 void GeomPipelineReader:: 01721 check_usage_hint() const { 01722 if (!_cdata->_got_usage_hint) { 01723 // We'll need to get a fresh pointer, since another thread might 01724 // already have modified the pointer on the object since we 01725 // queried it. 01726 { 01727 #ifdef DO_PIPELINING 01728 unref_delete((CycleData *)_cdata); 01729 #endif 01730 Geom::CDWriter fresh_cdata(((Geom *)_object.p())->_cycler, 01731 false, _current_thread); 01732 ((GeomPipelineReader *)this)->_cdata = fresh_cdata; 01733 #ifdef DO_PIPELINING 01734 _cdata->ref(); 01735 #endif 01736 if (!fresh_cdata->_got_usage_hint) { 01737 // The cache is still stale. We have to do the work of 01738 // freshening it. 01739 ((Geom *)_object.p())->reset_usage_hint(fresh_cdata); 01740 nassertv(fresh_cdata->_got_usage_hint); 01741 } 01742 01743 // When fresh_cdata goes out of scope, its write lock is 01744 // released, and _cdata reverts to our usual convention of an 01745 // unlocked copy of the data. 01746 } 01747 } 01748 01749 nassertv(_cdata->_got_usage_hint); 01750 } 01751 01752 //////////////////////////////////////////////////////////////////// 01753 // Function: GeomPipelineReader::check_valid 01754 // Access: Public 01755 // Description: 01756 //////////////////////////////////////////////////////////////////// 01757 bool GeomPipelineReader:: 01758 check_valid(const GeomVertexDataPipelineReader *data_reader) const { 01759 Geom::Primitives::const_iterator pi; 01760 for (pi = _cdata->_primitives.begin(); 01761 pi != _cdata->_primitives.end(); 01762 ++pi) { 01763 CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(); 01764 GeomPrimitivePipelineReader reader(primitive, _current_thread); 01765 reader.check_minmax(); 01766 if (!reader.check_valid(data_reader)) { 01767 return false; 01768 } 01769 } 01770 01771 return true; 01772 } 01773 01774 //////////////////////////////////////////////////////////////////// 01775 // Function: GeomPipelineReader::draw 01776 // Access: Public 01777 // Description: The implementation of Geom::draw(). 01778 //////////////////////////////////////////////////////////////////// 01779 bool GeomPipelineReader:: 01780 draw(GraphicsStateGuardianBase *gsg, const GeomMunger *munger, 01781 const GeomVertexDataPipelineReader *data_reader, bool force) const { 01782 PStatTimer timer(Geom::_draw_primitive_setup_pcollector); 01783 bool all_ok = gsg->begin_draw_primitives(this, munger, data_reader, force); 01784 if (all_ok) { 01785 Geom::Primitives::const_iterator pi; 01786 for (pi = _cdata->_primitives.begin(); 01787 pi != _cdata->_primitives.end(); 01788 ++pi) { 01789 CPT(GeomPrimitive) primitive = (*pi).get_read_pointer(); 01790 GeomPrimitivePipelineReader reader(primitive, _current_thread); 01791 if (reader.get_num_vertices() != 0) { 01792 reader.check_minmax(); 01793 nassertr(reader.check_valid(data_reader), false); 01794 if (!primitive->draw(gsg, &reader, force)) { 01795 all_ok = false; 01796 } 01797 } 01798 } 01799 gsg->end_draw_primitives(); 01800 } 01801 01802 return all_ok; 01803 }