00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "lodNode.h"
00016 #include "fadeLodNode.h"
00017 #include "cullTraverserData.h"
00018 #include "cullTraverser.h"
00019 #include "config_pgraphnodes.h"
00020 #include "geomVertexData.h"
00021 #include "geomVertexWriter.h"
00022 #include "geomVertexFormat.h"
00023 #include "geomTristrips.h"
00024 #include "mathNumbers.h"
00025 #include "geom.h"
00026 #include "geomNode.h"
00027 #include "transformState.h"
00028 #include "material.h"
00029 #include "materialAttrib.h"
00030 #include "materialPool.h"
00031 #include "renderState.h"
00032 #include "cullFaceAttrib.h"
00033 #include "textureAttrib.h"
00034 #include "boundingSphere.h"
00035 #include "geometricBoundingVolume.h"
00036 #include "look_at.h"
00037 #include "nodePath.h"
00038 #include "shaderAttrib.h"
00039 #include "colorAttrib.h"
00040 #include "clipPlaneAttrib.h"
00041
00042 TypeHandle LODNode::_type_handle;
00043
00044
00045
00046
00047
00048
00049
00050 PT(LODNode) LODNode::
00051 make_default_lod(const string &name) {
00052 switch (default_lod_type.get_value()) {
00053 case LNT_pop:
00054 return new LODNode(name);
00055
00056 case LNT_fade:
00057 return new FadeLODNode(name);
00058
00059 default:
00060 pgraph_cat.error()
00061 << "Invalid LODNodeType value: " << (int)default_lod_type << "\n";
00062 return new LODNode(name);
00063 }
00064 }
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074 PandaNode *LODNode::
00075 make_copy() const {
00076 return new LODNode(*this);
00077 }
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 bool LODNode::
00090 safe_to_combine() const {
00091 return false;
00092 }
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103 bool LODNode::
00104 safe_to_combine_children() const {
00105 return false;
00106 }
00107
00108
00109
00110
00111
00112
00113
00114
00115 void LODNode::
00116 xform(const LMatrix4 &mat) {
00117 CDWriter cdata(_cycler);
00118
00119 cdata->_center = cdata->_center * mat;
00120
00121
00122 LVector3 y;
00123 mat.get_row3(y, 1);
00124 PN_stdfloat factor = y.length();
00125
00126 SwitchVector::iterator si;
00127 for (si = cdata->_switch_vector.begin();
00128 si != cdata->_switch_vector.end();
00129 ++si) {
00130 (*si).rescale(factor);
00131 }
00132 }
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 bool LODNode::
00160 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00161 if (is_any_shown()) {
00162 return show_switches_cull_callback(trav, data);
00163 }
00164
00165 consider_verify_lods(trav, data);
00166
00167 CDReader cdata(_cycler);
00168
00169 CPT(TransformState) rel_transform = get_rel_transform(trav, data);
00170 LPoint3 center = cdata->_center * rel_transform->get_mat();
00171 PN_stdfloat dist2 = center.dot(center);
00172
00173 int num_children = min(get_num_children(), (int)cdata->_switch_vector.size());
00174 for (int index = 0; index < num_children; ++index) {
00175 const Switch &sw = cdata->_switch_vector[index];
00176 bool in_range;
00177 if (cdata->_got_force_switch) {
00178 in_range = (cdata->_force_switch == index);
00179 } else {
00180 in_range = sw.in_range_2(dist2*cdata->_lod_scale);
00181 }
00182
00183 if (in_range) {
00184
00185 PandaNode *child = get_child(index);
00186 if (child != (PandaNode *)NULL) {
00187 CullTraverserData next_data(data, child);
00188 trav->traverse(next_data);
00189 }
00190 }
00191 }
00192
00193
00194
00195 return false;
00196 }
00197
00198
00199
00200
00201
00202
00203 void LODNode::
00204 output(ostream &out) const {
00205 PandaNode::output(out);
00206 CDReader cdata(_cycler);
00207 out << " center(" << cdata->_center << ") ";
00208 if (cdata->_switch_vector.empty()) {
00209 out << "no switches.";
00210 } else {
00211 SwitchVector::const_iterator si;
00212 si = cdata->_switch_vector.begin();
00213 out << "(" << (*si).get_in() << "/" << (*si).get_out() << ")";
00214 ++si;
00215 while (si != cdata->_switch_vector.end()) {
00216 out << " (" << (*si).get_in() << "/" << (*si).get_out() << ")";
00217 ++si;
00218 }
00219 }
00220 }
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 bool LODNode::
00233 is_lod_node() const {
00234 return true;
00235 }
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00253 void LODNode::
00254 show_switch(int index) {
00255 CDWriter cdata(_cycler);
00256 do_show_switch(cdata, index, get_default_show_color(index));
00257 mark_internal_bounds_stale();
00258 }
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276 void LODNode::
00277 show_switch(int index, const LColor &color) {
00278 CDWriter cdata(_cycler);
00279 do_show_switch(cdata, index, color);
00280 mark_internal_bounds_stale();
00281 }
00282
00283
00284
00285
00286
00287
00288 void LODNode::
00289 hide_switch(int index) {
00290 CDWriter cdata(_cycler);
00291 do_hide_switch(cdata, index);
00292 mark_internal_bounds_stale();
00293 }
00294
00295
00296
00297
00298
00299
00300 void LODNode::
00301 show_all_switches() {
00302 CDWriter cdata(_cycler);
00303 for (int i = 0; i < (int)cdata->_switch_vector.size(); ++i) {
00304 do_show_switch(cdata, i, get_default_show_color(i));
00305 }
00306 mark_internal_bounds_stale();
00307 }
00308
00309
00310
00311
00312
00313
00314
00315 void LODNode::
00316 hide_all_switches() {
00317 CDWriter cdata(_cycler);
00318 for (int i = 0; i < (int)cdata->_switch_vector.size(); ++i) {
00319 do_hide_switch(cdata, i);
00320 }
00321 mark_internal_bounds_stale();
00322 }
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333 bool LODNode::
00334 verify_child_bounds() const {
00335 bool okflag = true;
00336 CDReader cdata(_cycler);
00337
00338 for (int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
00339 PN_stdfloat suggested_radius;
00340 if (!do_verify_child_bounds(cdata, index, suggested_radius)) {
00341 const Switch &sw = cdata->_switch_vector[index];
00342 pgraph_cat.warning()
00343 << "Level " << index << " geometry of " << *this
00344 << " is larger than its switch radius; suggest radius of "
00345 << suggested_radius << " instead of " << sw.get_in() << "\n";
00346 okflag = false;
00347 }
00348 }
00349
00350 return okflag;
00351 }
00352
00353
00354
00355
00356
00357
00358
00359
00360 int LODNode::
00361 compute_child(CullTraverser *trav, CullTraverserData &data) {
00362 if (data.get_net_transform(trav)->is_singular()) {
00363
00364
00365 return -1;
00366 }
00367
00368 CDReader cdata(_cycler);
00369
00370 if (cdata->_got_force_switch) {
00371 return cdata->_force_switch;
00372 }
00373
00374 CPT(TransformState) rel_transform = get_rel_transform(trav, data);
00375 LPoint3 center = cdata->_center * rel_transform->get_mat();
00376 PN_stdfloat dist2 = center.dot(center);
00377
00378 for (int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
00379 if (cdata->_switch_vector[index].in_range_2(dist2*cdata->_lod_scale)) {
00380 if (pgraph_cat.is_debug()) {
00381 pgraph_cat.debug()
00382 << data._node_path << " at distance " << sqrt(dist2)
00383 << ", selected child " << index << "\n";
00384 }
00385
00386 return index;
00387 }
00388 }
00389
00390 if (pgraph_cat.is_debug()) {
00391 pgraph_cat.debug()
00392 << data._node_path << " at distance " << sqrt(dist2)
00393 << ", no children in range.\n";
00394 }
00395
00396 return -1;
00397 }
00398
00399
00400
00401
00402
00403
00404
00405
00406
00407
00408 bool LODNode::
00409 show_switches_cull_callback(CullTraverser *trav, CullTraverserData &data) {
00410 CDReader cdata(_cycler);
00411
00412 CPT(TransformState) rel_transform = get_rel_transform(trav, data);
00413 LPoint3 center = cdata->_center * rel_transform->get_mat();
00414 PN_stdfloat dist2 = center.dot(center);
00415
00416
00417
00418 LMatrix4 mat;
00419 look_at(mat, -center, LVector3(0.0f, 0.0f, 1.0f));
00420 mat.set_row(3, center);
00421 CPT(TransformState) viz_transform =
00422 rel_transform->invert_compose(TransformState::make_mat(mat));
00423
00424 for (int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
00425 const Switch &sw = cdata->_switch_vector[index];
00426 if (sw.is_shown()) {
00427 bool in_range;
00428 if (cdata->_got_force_switch) {
00429 in_range = (cdata->_force_switch == index);
00430 } else {
00431 in_range = sw.in_range_2(dist2);
00432 }
00433
00434 if (in_range) {
00435
00436
00437 if (index < get_num_children()) {
00438 PandaNode *child = get_child(index);
00439 if (child != (PandaNode *)NULL) {
00440 CullTraverserData next_data3(data, child);
00441 next_data3._state = next_data3._state->compose(sw.get_viz_model_state());
00442 trav->traverse(next_data3);
00443 }
00444 }
00445
00446
00447 CullTraverserData next_data2(data, sw.get_spindle_viz());
00448 next_data2.apply_transform_and_state(trav, viz_transform,
00449 RenderState::make_empty(),
00450 RenderEffects::make_empty(),
00451 ClipPlaneAttrib::make());
00452 trav->traverse(next_data2);
00453 }
00454
00455
00456
00457 CullTraverserData next_data(data, sw.get_ring_viz());
00458 next_data.apply_transform_and_state(trav, viz_transform,
00459 RenderState::make_empty(),
00460 RenderEffects::make_empty(),
00461 ClipPlaneAttrib::make());
00462 trav->traverse(next_data);
00463 }
00464 }
00465
00466
00467
00468 return false;
00469 }
00470
00471
00472
00473
00474
00475
00476
00477
00478
00479 void LODNode::
00480 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
00481 int &internal_vertices,
00482 int pipeline_stage,
00483 Thread *current_thread) const {
00484
00485 PT(BoundingVolume) bound = new BoundingSphere;
00486
00487
00488 if (is_any_shown()) {
00489
00490
00491 pvector<const BoundingVolume *> child_volumes;
00492 pvector<PT(BoundingVolume) > pt_volumes;
00493
00494 CDStageReader cdata(_cycler, pipeline_stage, current_thread);
00495
00496 SwitchVector::const_iterator si;
00497 for (si = cdata->_switch_vector.begin();
00498 si != cdata->_switch_vector.end();
00499 ++si) {
00500 const Switch &sw = (*si);
00501 if (sw.is_shown()) {
00502 PT(BoundingVolume) sphere = new BoundingSphere(cdata->_center, sw.get_in());
00503 child_volumes.push_back(sphere);
00504 pt_volumes.push_back(sphere);
00505 }
00506 }
00507
00508 const BoundingVolume **child_begin = &child_volumes[0];
00509 const BoundingVolume **child_end = child_begin + child_volumes.size();
00510
00511 bound->around(child_begin, child_end);
00512 }
00513
00514 internal_bounds = bound;
00515 internal_vertices = 0;
00516 }
00517
00518
00519
00520
00521
00522
00523
00524 CPT(TransformState) LODNode::
00525 get_rel_transform(CullTraverser *trav, CullTraverserData &data) {
00526
00527 Camera *camera = trav->get_scene()->get_camera_node();
00528
00529
00530 CPT(TransformState) rel_transform;
00531
00532 NodePath lod_center = camera->get_lod_center();
00533 if (!lod_center.is_empty()) {
00534 rel_transform =
00535 lod_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
00536 } else {
00537 NodePath cull_center = camera->get_cull_center();
00538 if (!cull_center.is_empty()) {
00539 rel_transform =
00540 cull_center.get_net_transform()->invert_compose(data.get_net_transform(trav));
00541 } else {
00542 rel_transform = data.get_modelview_transform(trav);
00543 }
00544 }
00545
00546 return rel_transform;
00547 }
00548
00549
00550
00551
00552
00553
00554 void LODNode::
00555 do_show_switch(LODNode::CData *cdata, int index, const LColor &color) {
00556 nassertv(index >= 0 && index < (int)cdata->_switch_vector.size());
00557
00558 if (!cdata->_switch_vector[index].is_shown()) {
00559 ++cdata->_num_shown;
00560 }
00561 cdata->_switch_vector[index].show(color);
00562 }
00563
00564
00565
00566
00567
00568
00569 void LODNode::
00570 do_hide_switch(LODNode::CData *cdata, int index) {
00571 nassertv(index >= 0 && index < (int)cdata->_switch_vector.size());
00572
00573 if (cdata->_switch_vector[index].is_shown()) {
00574 --cdata->_num_shown;
00575 }
00576 cdata->_switch_vector[index].hide();
00577 }
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589 bool LODNode::
00590 do_verify_child_bounds(const LODNode::CData *cdata, int index,
00591 PN_stdfloat &suggested_radius) const {
00592 suggested_radius = 0.0f;
00593
00594 if (index < get_num_children()) {
00595 const Switch &sw = cdata->_switch_vector[index];
00596 PandaNode *child = get_child(index);
00597 if (child != (PandaNode *)NULL) {
00598 UpdateSeq seq;
00599 CPT(BoundingVolume) bv = child->get_bounds(seq);
00600
00601 if (seq == sw._bounds_seq) {
00602
00603
00604 return sw._verify_ok;
00605 }
00606
00607 ((Switch &)sw)._bounds_seq = seq;
00608 ((Switch &)sw)._verify_ok = true;
00609
00610 if (bv->is_empty()) {
00611
00612 return true;
00613 }
00614 if (bv->is_infinite()) {
00615
00616
00617
00618
00619 return true;
00620 }
00621
00622 const Switch &sw = cdata->_switch_vector[index];
00623
00624 const GeometricBoundingVolume *gbv;
00625 DCAST_INTO_R(gbv, bv, false);
00626 BoundingSphere sphere(cdata->_center, sw.get_in());
00627 sphere.local_object();
00628
00629 int flags = sphere.contains(gbv);
00630 if ((flags & BoundingVolume::IF_all) != 0) {
00631
00632
00633 return true;
00634 }
00635
00636 if (flags == 0) {
00637
00638
00639 nassertr(!gbv->is_infinite(), false);
00640 sphere.extend_by(gbv);
00641 suggested_radius = sphere.get_radius();
00642 ((Switch &)sw)._verify_ok = false;
00643 return false;
00644 }
00645
00646
00647
00648
00649 LPoint3 min_point(0.0f, 0.0f, 0.0f);
00650 LPoint3 max_point(0.0f, 0.0f, 0.0f);
00651
00652 bool found_any = false;
00653 child->calc_tight_bounds(min_point, max_point, found_any,
00654 TransformState::make_identity(),
00655 Thread::get_current_thread());
00656 if (!found_any) {
00657
00658 return true;
00659 }
00660
00661
00662
00663
00664
00665 LPoint3 box_center = (min_point + max_point) / 2.0f;
00666 PN_stdfloat box_radius = min(min(max_point[0] - box_center[0],
00667 max_point[1] - box_center[1]),
00668 max_point[2] - box_center[2]);
00669
00670 BoundingSphere box_sphere(box_center, box_radius);
00671 box_sphere.local_object();
00672
00673
00674
00675 flags = sphere.contains(&box_sphere);
00676 if ((flags & BoundingVolume::IF_all) == 0) {
00677
00678 if (gbv->is_infinite()) {
00679 sphere.extend_by(&box_sphere);
00680 } else {
00681 sphere.extend_by(gbv);
00682 }
00683 suggested_radius = sphere.get_radius();
00684 ((Switch &)sw)._verify_ok = false;
00685 return false;
00686 }
00687 }
00688 }
00689
00690 return true;
00691 }
00692
00693
00694
00695
00696
00697
00698 void LODNode::
00699 do_auto_verify_lods(CullTraverser *trav, CullTraverserData &data) {
00700 UpdateSeq seq;
00701 get_bounds(seq);
00702 CDLockedReader cdata(_cycler);
00703
00704 if (cdata->_got_force_switch) {
00705
00706
00707
00708 return;
00709 }
00710
00711 if (seq != cdata->_bounds_seq) {
00712
00713 for (int index = 0; index < (int)cdata->_switch_vector.size(); ++index) {
00714 PN_stdfloat suggested_radius;
00715 if (!do_verify_child_bounds(cdata, index, suggested_radius)) {
00716 const Switch &sw = cdata->_switch_vector[index];
00717 ostringstream strm;
00718 strm
00719 << "Level " << index << " geometry of " << data._node_path
00720 << " is larger than its switch radius; suggest radius of "
00721 << suggested_radius << " instead of " << sw.get_in()
00722 << " (configure verify-lods 0 to ignore this error)";
00723 nassert_raise(strm.str());
00724 }
00725 }
00726 CDWriter cdataw(_cycler, cdata);
00727 cdataw->_bounds_seq = seq;
00728 }
00729 }
00730
00731
00732
00733
00734
00735
00736
00737 const LColor &LODNode::
00738 get_default_show_color(int index) {
00739 static LColor default_colors[] = {
00740 LColor(1.0f, 0.0f, 0.0f, 0.7f),
00741 LColor(0.0f, 1.0f, 0.0f, 0.7f),
00742 LColor(0.0f, 0.0f, 1.0f, 0.7f),
00743 LColor(0.0f, 1.0f, 1.0f, 0.7f),
00744 LColor(1.0f, 0.0f, 1.0f, 0.7f),
00745 LColor(1.0f, 1.0f, 0.0f, 0.7f),
00746 };
00747 static const int num_default_colors = sizeof(default_colors) / sizeof(LColor);
00748
00749 return default_colors[index % num_default_colors];
00750 }
00751
00752
00753
00754
00755
00756
00757
00758
00759 void LODNode::
00760 register_with_read_factory() {
00761 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00762 }
00763
00764
00765
00766
00767
00768
00769
00770 void LODNode::
00771 write_datagram(BamWriter *manager, Datagram &dg) {
00772 PandaNode::write_datagram(manager, dg);
00773 manager->write_cdata(dg, _cycler);
00774 }
00775
00776
00777
00778
00779
00780
00781
00782
00783
00784 TypedWritable *LODNode::
00785 make_from_bam(const FactoryParams ¶ms) {
00786 LODNode *node = new LODNode("");
00787
00788 DatagramIterator scan;
00789 BamReader *manager;
00790
00791 parse_params(params, scan, manager);
00792 node->fillin(scan, manager);
00793
00794 return node;
00795 }
00796
00797
00798
00799
00800
00801
00802
00803
00804 void LODNode::
00805 fillin(DatagramIterator &scan, BamReader *manager) {
00806 PandaNode::fillin(scan, manager);
00807 manager->read_cdata(scan, _cycler);
00808 }
00809
00810
00811
00812
00813
00814
00815 CycleData *LODNode::CData::
00816 make_copy() const {
00817 return new CData(*this);
00818 }
00819
00820
00821
00822
00823
00824
00825
00826 void LODNode::CData::
00827 check_limits() {
00828 _lowest = 0;
00829 _highest = 0;
00830 for (size_t i = 1; i < _switch_vector.size(); ++i) {
00831 if (_switch_vector[i].get_out() > _switch_vector[_lowest].get_out()) {
00832 _lowest = i;
00833 }
00834 if (_switch_vector[i].get_in() < _switch_vector[_highest].get_in()) {
00835 _highest = i;
00836 }
00837 }
00838 }
00839
00840
00841
00842
00843
00844
00845
00846 void LODNode::CData::
00847 write_datagram(BamWriter *manager, Datagram &dg) const {
00848 _center.write_datagram(dg);
00849
00850 dg.add_uint16(_switch_vector.size());
00851
00852 SwitchVector::const_iterator si;
00853 for (si = _switch_vector.begin();
00854 si != _switch_vector.end();
00855 ++si) {
00856 (*si).write_datagram(dg);
00857 }
00858 }
00859
00860
00861
00862
00863
00864
00865
00866
00867 void LODNode::CData::
00868 fillin(DatagramIterator &scan, BamReader *manager) {
00869 _center.read_datagram(scan);
00870
00871 _switch_vector.clear();
00872
00873 int num_switches = scan.get_uint16();
00874 _switch_vector.reserve(num_switches);
00875 for (int i = 0; i < num_switches; i++) {
00876 Switch sw(0, 0);
00877 sw.read_datagram(scan);
00878
00879 _switch_vector.push_back(sw);
00880 }
00881 _lod_scale = 1;
00882 }
00883
00884
00885
00886
00887
00888
00889
00890 void LODNode::Switch::
00891 compute_ring_viz() {
00892
00893
00894 static const int num_slices = 50;
00895 static const int num_rings = 1;
00896
00897
00898
00899 static const PN_stdfloat edge_ratio = 0.1;
00900
00901 const GeomVertexFormat *format = GeomVertexFormat::get_v3n3cp();
00902 PT(GeomVertexData) vdata = new GeomVertexData("LOD_ring", format, Geom::UH_static);
00903
00904
00905 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00906 GeomVertexWriter normal(vdata, InternalName::get_normal());
00907 GeomVertexWriter color(vdata, InternalName::get_color());
00908
00909
00910 int ri, si;
00911 for (ri = 0; ri <= num_rings; ++ri) {
00912
00913 PN_stdfloat r = (PN_stdfloat)ri / (PN_stdfloat)num_rings;
00914
00915
00916 PN_stdfloat d = r * (_in - _out) + _out;
00917
00918 for (si = 0; si < num_slices; ++si) {
00919
00920 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
00921
00922
00923 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
00924
00925 PN_stdfloat x = ccos(t);
00926 PN_stdfloat y = csin(t);
00927 vertex.add_data3(x * d, y * d, 0.0f);
00928 normal.add_data3(0.0f, 0.0f, 1.0f);
00929 color.add_data4(_show_color);
00930 }
00931 }
00932
00933
00934 for (ri = 0; ri <= 1; ++ri) {
00935 PN_stdfloat r = (PN_stdfloat)ri;
00936 PN_stdfloat d = r * (_in - _out) + _out;
00937
00938 for (si = 0; si < num_slices; ++si) {
00939 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
00940 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
00941
00942 PN_stdfloat x = ccos(t);
00943 PN_stdfloat y = csin(t);
00944
00945 vertex.add_data3(x * d, y * d, 0.5f * edge_ratio * d);
00946 normal.add_data3(x, y, 0.0f);
00947 color.add_data4(_show_color);
00948 }
00949
00950 for (si = 0; si < num_slices; ++si) {
00951 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
00952 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
00953
00954 PN_stdfloat x = ccos(t);
00955 PN_stdfloat y = csin(t);
00956
00957 vertex.add_data3(x * d, y * d, -0.5f * edge_ratio * d);
00958 normal.add_data3(x, y, 0.0f);
00959 color.add_data4(_show_color);
00960 }
00961 }
00962
00963
00964 PT(GeomTristrips) strips = new GeomTristrips(Geom::UH_static);
00965 for (ri = 0; ri < num_rings; ++ri) {
00966 for (si = 0; si < num_slices; ++si) {
00967 strips->add_vertex(ri * num_slices + si);
00968 strips->add_vertex((ri + 1) * num_slices + si);
00969 }
00970 strips->add_vertex(ri * num_slices);
00971 strips->add_vertex((ri + 1) * num_slices);
00972 strips->close_primitive();
00973 }
00974
00975
00976
00977 for (ri = 0; ri <= 1; ++ri) {
00978 for (si = 0; si < num_slices; ++si) {
00979 strips->add_vertex((num_rings + 1 + ri * 2) * num_slices + si);
00980 strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices + si);
00981 }
00982 strips->add_vertex((num_rings + 1 + ri * 2) * num_slices);
00983 strips->add_vertex((num_rings + 1 + ri * 2 + 1) * num_slices);
00984 strips->close_primitive();
00985 }
00986
00987 PT(Geom) ring_geom = new Geom(vdata);
00988 ring_geom->add_primitive(strips);
00989
00990 PT(GeomNode) geom_node = new GeomNode("ring");
00991 geom_node->add_geom(ring_geom);
00992
00993
00994 PT(Material) material = new Material();
00995 material->set_twoside(true);
00996 material = MaterialPool::get_material(material);
00997
00998 CPT(RenderState) viz_state =
00999 RenderState::make(CullFaceAttrib::make(CullFaceAttrib::M_cull_none),
01000 TextureAttrib::make_off(),
01001 ShaderAttrib::make_off(),
01002 MaterialAttrib::make(material),
01003 RenderState::get_max_priority());
01004 if (_show_color[3] != 1.0f) {
01005 viz_state = viz_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha),
01006 RenderState::get_max_priority());
01007 }
01008
01009 geom_node->set_state(viz_state);
01010
01011 _ring_viz = geom_node.p();
01012 }
01013
01014
01015
01016
01017
01018
01019
01020 void LODNode::Switch::
01021 compute_spindle_viz() {
01022
01023
01024
01025
01026 static const int num_slices = 10;
01027 static const int num_rings = 10;
01028
01029 const GeomVertexFormat *format = GeomVertexFormat::get_v3n3cp();
01030 PT(GeomVertexData) vdata = new GeomVertexData("LOD_spindle", format, Geom::UH_static);
01031
01032
01033 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
01034 GeomVertexWriter normal(vdata, InternalName::get_normal());
01035 GeomVertexWriter color(vdata, InternalName::get_color());
01036
01037 int ri, si;
01038 for (ri = 0; ri <= num_rings; ++ri) {
01039
01040 PN_stdfloat r = (PN_stdfloat)ri / (PN_stdfloat)num_rings;
01041
01042
01043 PN_stdfloat z = 100.0f - r * 200.0f;
01044
01045 for (si = 0; si < num_slices; ++si) {
01046
01047 PN_stdfloat s = (PN_stdfloat)si / (PN_stdfloat)num_slices;
01048
01049
01050 PN_stdfloat t = MathNumbers::pi * 2.0f * s;
01051
01052 PN_stdfloat x = ccos(t);
01053 PN_stdfloat y = csin(t);
01054 vertex.add_data3(x, y, z);
01055 normal.add_data3(x, y, 0.0f);
01056 color.add_data4(_show_color);
01057 }
01058 }
01059
01060
01061 PT(GeomTristrips) strips = new GeomTristrips(Geom::UH_static);
01062 for (ri = 0; ri < num_rings; ++ri) {
01063 for (si = 0; si < num_slices; ++si) {
01064 strips->add_vertex(ri * num_slices + si);
01065 strips->add_vertex((ri + 1) * num_slices + si);
01066 }
01067 strips->add_vertex(ri * num_slices);
01068 strips->add_vertex((ri + 1) * num_slices);
01069 strips->close_primitive();
01070 }
01071
01072 PT(Geom) spindle_geom = new Geom(vdata);
01073 spindle_geom->add_primitive(strips);
01074
01075 PT(GeomNode) geom_node = new GeomNode("spindle");
01076 geom_node->add_geom(spindle_geom);
01077
01078 CPT(RenderState) viz_state =
01079 RenderState::make(CullFaceAttrib::make(CullFaceAttrib::M_cull_clockwise),
01080 TextureAttrib::make_off(),
01081 ShaderAttrib::make_off(),
01082 RenderState::get_max_priority());
01083 if (_show_color[3] != 1.0f) {
01084 viz_state = viz_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha),
01085 RenderState::get_max_priority());
01086 }
01087
01088 geom_node->set_state(viz_state);
01089
01090 _spindle_viz = geom_node.p();
01091 }
01092
01093
01094
01095
01096
01097
01098
01099 void LODNode::Switch::
01100 compute_viz_model_state() {
01101
01102
01103
01104 _viz_model_state = RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_wireframe),
01105 TextureAttrib::make_off(),
01106 ShaderAttrib::make_off(),
01107 ColorAttrib::make_flat(_show_color),
01108 RenderState::get_max_priority());
01109 CPT(RenderState) st2 = RenderState::make(TransparencyAttrib::make(TransparencyAttrib::M_none),
01110 RenderState::get_max_priority());
01111 _viz_model_state = _viz_model_state->compose(st2);
01112 }