00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "eggGroupNode.h"
00016 #include "eggCoordinateSystem.h"
00017 #include "eggData.h"
00018 #include "eggFilenameNode.h"
00019 #include "eggExternalReference.h"
00020 #include "eggPrimitive.h"
00021 #include "eggPolygon.h"
00022 #include "eggCompositePrimitive.h"
00023 #include "eggMesher.h"
00024 #include "eggVertexPool.h"
00025 #include "eggVertex.h"
00026 #include "eggTextureCollection.h"
00027 #include "eggMaterialCollection.h"
00028 #include "pt_EggTexture.h"
00029 #include "pt_EggMaterial.h"
00030 #include "config_egg.h"
00031
00032 #include "dSearchPath.h"
00033 #include "deg_2_rad.h"
00034 #include "dcast.h"
00035 #include "bamCacheRecord.h"
00036
00037 #include <algorithm>
00038
00039 TypeHandle EggGroupNode::_type_handle;
00040
00041
00042
00043
00044
00045
00046
00047 EggGroupNode::
00048 EggGroupNode(const EggGroupNode ©) : EggNode(copy) {
00049 if (!copy.empty()) {
00050 egg_cat.warning()
00051 << "The EggGroupNode copy constructor does not copy children!\n";
00052 }
00053 }
00054
00055
00056
00057
00058
00059
00060 EggGroupNode &EggGroupNode::
00061 operator =(const EggGroupNode ©) {
00062 if (!copy.empty()) {
00063 egg_cat.warning()
00064 << "The EggGroupNode copy assignment does not copy children!\n";
00065 }
00066 EggNode::operator =(copy);
00067 return *this;
00068 }
00069
00070
00071
00072
00073
00074
00075 EggGroupNode::
00076 ~EggGroupNode() {
00077 }
00078
00079
00080
00081
00082
00083
00084
00085
00086 void EggGroupNode::
00087 write(ostream &out, int indent_level) const {
00088 iterator i;
00089
00090
00091
00092
00093
00094
00095
00096 for (i = begin(); i != end(); ++i) {
00097 PT(EggNode) child = (*i);
00098 if (!child->is_joint()) {
00099 child->write(out, indent_level);
00100 }
00101 }
00102
00103 for (i = begin(); i != end(); ++i) {
00104 PT(EggNode) child = (*i);
00105 if (child->is_joint()) {
00106 child->write(out, indent_level);
00107 }
00108 }
00109 }
00110
00111
00112
00113
00114
00115
00116 EggGroupNode::iterator EggGroupNode::
00117 begin() const {
00118 return _children.begin();
00119 }
00120
00121
00122
00123
00124
00125
00126 EggGroupNode::iterator EggGroupNode::
00127 end() const {
00128 return _children.end();
00129 }
00130
00131
00132
00133
00134
00135
00136 EggGroupNode::reverse_iterator EggGroupNode::
00137 rbegin() const {
00138 return _children.rbegin();
00139 }
00140
00141
00142
00143
00144
00145
00146 EggGroupNode::reverse_iterator EggGroupNode::
00147 rend() const {
00148 return _children.rend();
00149 }
00150
00151
00152
00153
00154
00155
00156 EggGroupNode::iterator EggGroupNode::
00157 insert(iterator position, PT(EggNode) x) {
00158 prepare_add_child(x);
00159 return _children.insert((Children::iterator &)position, x);
00160 }
00161
00162
00163
00164
00165
00166
00167 EggGroupNode::iterator EggGroupNode::
00168 erase(iterator position) {
00169 prepare_remove_child(*position);
00170 return _children.erase((Children::iterator &)position);
00171 }
00172
00173
00174
00175
00176
00177
00178 EggGroupNode::iterator EggGroupNode::
00179 erase(iterator first, iterator last) {
00180 iterator i;
00181 for (i = first; i != last; ++i) {
00182 prepare_remove_child(*i);
00183 }
00184 return _children.erase((Children::iterator &)first,
00185 (Children::iterator &)last);
00186 }
00187
00188
00189
00190
00191
00192
00193
00194
00195 void EggGroupNode::
00196 replace(iterator position, PT(EggNode) x) {
00197 nassertv(position != end());
00198
00199 prepare_remove_child(*position);
00200 prepare_add_child(x);
00201 *(Children::iterator &)position = x;
00202 }
00203
00204
00205
00206
00207
00208
00209 bool EggGroupNode::
00210 empty() const {
00211 return _children.empty();
00212 }
00213
00214
00215
00216
00217
00218
00219 EggGroupNode::size_type EggGroupNode::
00220 size() const {
00221 return _children.size();
00222 }
00223
00224
00225
00226
00227
00228
00229 void EggGroupNode::
00230 clear() {
00231 erase(begin(), end());
00232 }
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 EggNode *EggGroupNode::
00246 get_first_child() {
00247 _gnc_iterator = begin();
00248 return get_next_child();
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266 EggNode *EggGroupNode::
00267 get_next_child() {
00268 if (_gnc_iterator != end()) {
00269 return *_gnc_iterator++;
00270 }
00271 return NULL;
00272 }
00273
00274
00275
00276
00277
00278
00279
00280
00281 EggNode *EggGroupNode::
00282 add_child(EggNode *node) {
00283 test_ref_count_integrity();
00284 PT(EggNode) ptnode = node;
00285 if (node->_parent != NULL) {
00286 node->_parent->remove_child(node);
00287 }
00288 prepare_add_child(node);
00289 _children.push_back(node);
00290 return node;
00291 }
00292
00293
00294
00295
00296
00297
00298
00299
00300 PT(EggNode) EggGroupNode::
00301 remove_child(EggNode *node) {
00302 PT(EggNode) ptnode = node;
00303 iterator i = find(begin(), end(), ptnode);
00304 if (i == end()) {
00305 return PT(EggNode)();
00306 } else {
00307
00308 erase(i);
00309 return ptnode;
00310 }
00311 }
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321 void EggGroupNode::
00322 steal_children(EggGroupNode &other) {
00323 Children::iterator ci;
00324 for (ci = other._children.begin();
00325 ci != other._children.end();
00326 ++ci) {
00327 other.prepare_remove_child(*ci);
00328 prepare_add_child(*ci);
00329 }
00330
00331 _children.splice(_children.end(), other._children);
00332 }
00333
00334
00335
00336
00337
00338
00339
00340
00341 EggNode *EggGroupNode::
00342 find_child(const string &name) const {
00343 Children::const_iterator ci;
00344 for (ci = _children.begin(); ci != _children.end(); ++ci) {
00345 EggNode *child = (*ci);
00346 if (child->get_name() == name) {
00347 return child;
00348 }
00349 }
00350
00351 return NULL;
00352 }
00353
00354
00355
00356
00357
00358
00359
00360
00361 bool EggGroupNode::
00362 has_absolute_pathnames() const {
00363 Children::const_iterator ci;
00364 for (ci = _children.begin();
00365 ci != _children.end();
00366 ++ci) {
00367 EggNode *child = *ci;
00368 if (child->is_of_type(EggTexture::get_class_type())) {
00369 EggTexture *tex = DCAST(EggTexture, child);
00370 if (!tex->get_filename().is_local()) {
00371 if (egg_cat.is_debug()) {
00372 egg_cat.debug()
00373 << "Absolute pathname: " << tex->get_filename()
00374 << "\n";
00375 }
00376 return true;
00377 }
00378
00379 if (tex->has_alpha_filename()) {
00380 if (!tex->get_alpha_filename().is_local()) {
00381 if (egg_cat.is_debug()) {
00382 egg_cat.debug()
00383 << "Absolute pathname: " << tex->get_alpha_filename()
00384 << "\n";
00385 }
00386 return true;
00387 }
00388 }
00389
00390 } else if (child->is_of_type(EggFilenameNode::get_class_type())) {
00391 EggFilenameNode *fnode = DCAST(EggFilenameNode, child);
00392 if (!fnode->get_filename().is_local()) {
00393 if (egg_cat.is_debug()) {
00394 egg_cat.debug()
00395 << "Absolute pathname: " << fnode->get_filename()
00396 << "\n";
00397 }
00398 return true;
00399 }
00400
00401 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00402 if (DCAST(EggGroupNode, child)->has_absolute_pathnames()) {
00403 return true;
00404 }
00405 }
00406 }
00407
00408 return false;
00409 }
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419 void EggGroupNode::
00420 resolve_filenames(const DSearchPath &searchpath) {
00421 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00422
00423 Children::iterator ci;
00424 for (ci = _children.begin();
00425 ci != _children.end();
00426 ++ci) {
00427 EggNode *child = *ci;
00428 if (child->is_of_type(EggTexture::get_class_type())) {
00429 EggTexture *tex = DCAST(EggTexture, child);
00430 Filename tex_filename = tex->get_filename();
00431 vfs->resolve_filename(tex_filename, searchpath);
00432 tex->set_filename(tex_filename);
00433
00434 if (tex->has_alpha_filename()) {
00435 Filename alpha_filename = tex->get_alpha_filename();
00436 vfs->resolve_filename(alpha_filename, searchpath);
00437 tex->set_alpha_filename(alpha_filename);
00438 }
00439
00440 } else if (child->is_of_type(EggFilenameNode::get_class_type())) {
00441 EggFilenameNode *fnode = DCAST(EggFilenameNode, child);
00442 Filename filename = fnode->get_filename();
00443 vfs->resolve_filename(filename, searchpath, fnode->get_default_extension());
00444 fnode->set_filename(filename);
00445
00446 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00447 DCAST(EggGroupNode, child)->resolve_filenames(searchpath);
00448 }
00449 }
00450 }
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460 void EggGroupNode::
00461 force_filenames(const Filename &directory) {
00462 Children::iterator ci;
00463 for (ci = _children.begin();
00464 ci != _children.end();
00465 ++ci) {
00466 EggNode *child = *ci;
00467 if (child->is_of_type(EggTexture::get_class_type())) {
00468 EggTexture *tex = DCAST(EggTexture, child);
00469 Filename tex_filename = tex->get_filename();
00470 if (tex_filename.is_local()) {
00471 tex->set_filename(Filename(directory, tex_filename));
00472 }
00473
00474 if (tex->has_alpha_filename()) {
00475 Filename alpha_filename = tex->get_alpha_filename();
00476 if (alpha_filename.is_local()) {
00477 tex->set_alpha_filename(Filename(directory, alpha_filename));
00478 }
00479 }
00480
00481 } else if (child->is_of_type(EggFilenameNode::get_class_type())) {
00482 EggFilenameNode *fnode = DCAST(EggFilenameNode, child);
00483 Filename filename = fnode->get_filename();
00484 if (filename.is_local()) {
00485 fnode->set_filename(Filename(directory, filename));
00486 }
00487
00488 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00489 DCAST(EggGroupNode, child)->force_filenames(directory);
00490 }
00491 }
00492 }
00493
00494
00495
00496
00497
00498
00499
00500
00501 void EggGroupNode::
00502 reverse_vertex_ordering() {
00503 Children::iterator ci;
00504 for (ci = _children.begin();
00505 ci != _children.end();
00506 ++ci) {
00507 EggNode *child = *ci;
00508 if (child->is_of_type(EggPrimitive::get_class_type())) {
00509 EggPrimitive *prim = DCAST(EggPrimitive, child);
00510 prim->reverse_vertex_ordering();
00511
00512 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00513 DCAST(EggGroupNode, child)->reverse_vertex_ordering();
00514 }
00515 }
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537
00538 void EggGroupNode::
00539 recompute_vertex_normals(double threshold, CoordinateSystem cs) {
00540
00541
00542 NVertexCollection collection;
00543 r_collect_vertex_normals(collection, threshold, cs);
00544
00545
00546
00547
00548
00549
00550 double cos_angle = cos(deg_2_rad(threshold));
00551
00552 NVertexCollection::iterator ci;
00553 for (ci = collection.begin(); ci != collection.end(); ++ci) {
00554 NVertexGroup &group = (*ci).second;
00555
00556
00557
00558
00559 NVertexGroup::iterator gi;
00560 gi = group.begin();
00561 while (gi != group.end()) {
00562 const NVertexReference &base_ref = (*gi);
00563 NVertexGroup new_group;
00564 NVertexGroup leftover_group;
00565 new_group.push_back(base_ref);
00566 ++gi;
00567
00568 while (gi != group.end()) {
00569 const NVertexReference &ref = (*gi);
00570 double dot = base_ref._normal.dot(ref._normal);
00571 if (dot > cos_angle) {
00572
00573 new_group.push_back(ref);
00574 } else {
00575
00576 leftover_group.push_back(ref);
00577 }
00578 ++gi;
00579 }
00580
00581
00582
00583 do_compute_vertex_normals(new_group);
00584
00585
00586 group.swap(leftover_group);
00587 gi = group.begin();
00588 }
00589 }
00590 }
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611 void EggGroupNode::
00612 recompute_polygon_normals(CoordinateSystem cs) {
00613 Children::iterator ci, cnext;
00614 ci = _children.begin();
00615 while (ci != _children.end()) {
00616 cnext = ci;
00617 ++cnext;
00618 EggNode *child = *ci;
00619
00620 if (child->is_of_type(EggPolygon::get_class_type())) {
00621 EggPolygon *polygon = DCAST(EggPolygon, child);
00622
00623 if (!polygon->recompute_polygon_normal(cs)) {
00624
00625 prepare_remove_child(child);
00626 _children.erase(ci);
00627
00628 } else {
00629
00630 size_t num_vertices = polygon->size();
00631 for (size_t i = 0; i < num_vertices; i++) {
00632 EggVertex *vertex = polygon->get_vertex(i);
00633 EggVertexPool *pool = vertex->get_pool();
00634
00635 if (vertex->has_normal()) {
00636 EggVertex new_vertex(*vertex);
00637 new_vertex.clear_normal();
00638 EggVertex *unique = pool->create_unique_vertex(new_vertex);
00639 unique->copy_grefs_from(*vertex);
00640
00641 polygon->set_vertex(i, unique);
00642 }
00643 }
00644 }
00645
00646 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00647 DCAST(EggGroupNode, child)->recompute_polygon_normals(cs);
00648 }
00649
00650 ci = cnext;
00651 }
00652 }
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665 void EggGroupNode::
00666 strip_normals() {
00667 Children::iterator ci;
00668 for (ci = _children.begin(); ci != _children.end(); ++ci) {
00669 EggNode *child = *ci;
00670
00671 if (child->is_of_type(EggPrimitive::get_class_type())) {
00672 EggPrimitive *prim = DCAST(EggPrimitive, child);
00673 prim->clear_normal();
00674
00675
00676 size_t num_vertices = prim->size();
00677 for (size_t i = 0; i < num_vertices; i++) {
00678 EggVertex *vertex = prim->get_vertex(i);
00679 EggVertexPool *pool = vertex->get_pool();
00680
00681 if (vertex->has_normal()) {
00682 EggVertex new_vertex(*vertex);
00683 new_vertex.clear_normal();
00684 EggVertex *unique = pool->create_unique_vertex(new_vertex);
00685 unique->copy_grefs_from(*vertex);
00686
00687 prim->set_vertex(i, unique);
00688 }
00689 }
00690
00691 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00692 DCAST(EggGroupNode, child)->strip_normals();
00693 }
00694 }
00695 }
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718 bool EggGroupNode::
00719 recompute_tangent_binormal(const GlobPattern &uv_name) {
00720
00721
00722 TBNVertexCollection collection;
00723 r_collect_tangent_binormal(uv_name, collection);
00724
00725
00726
00727 TBNVertexCollection::const_iterator ci;
00728 for (ci = collection.begin(); ci != collection.end(); ++ci) {
00729 const TBNVertexValue &value = (*ci).first;
00730 const TBNVertexGroup &group = (*ci).second;
00731
00732 do_compute_tangent_binormal(value, group);
00733 }
00734
00735 return true;
00736 }
00737
00738
00739
00740
00741
00742
00743
00744
00745 bool EggGroupNode::
00746 recompute_tangent_binormal(const vector_string &names) {
00747 bool changed = false;
00748
00749 for (vector_string::const_iterator si = names.begin();
00750 si != names.end();
00751 ++si) {
00752 GlobPattern uv_name(*si);
00753 nout << "Computing tangent and binormal for \"" << uv_name << "\"\n";
00754 recompute_tangent_binormal(uv_name);
00755 changed = true;
00756 }
00757
00758 return changed;
00759 }
00760
00761
00762
00763
00764
00765
00766
00767
00768 bool EggGroupNode::
00769 recompute_tangent_binormal_auto() {
00770 vector_string names;
00771 EggTextureCollection texs;
00772 EggTextureCollection::iterator eti;
00773 texs.find_used_textures(this);
00774 for (eti = texs.begin(); eti != texs.end(); eti++) {
00775 EggTexture *eggtex = (*eti);
00776 if ((eggtex->get_env_type() == EggTexture::ET_normal)||
00777 (eggtex->get_env_type() == EggTexture::ET_normal_height)||
00778 (eggtex->get_env_type() == EggTexture::ET_normal_gloss)) {
00779 string uv = eggtex->get_uv_name();
00780 vector_string::iterator it = find(names.begin(), names.end(), uv);
00781 if (it == names.end()) {
00782 names.push_back(uv);
00783 }
00784 }
00785 }
00786 return recompute_tangent_binormal(names);
00787 }
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801
00802
00803 int EggGroupNode::
00804 triangulate_polygons(int flags) {
00805 int num_produced = 0;
00806
00807 Children children_copy = _children;
00808
00809 Children::iterator ci;
00810 for (ci = children_copy.begin();
00811 ci != children_copy.end();
00812 ++ci) {
00813 EggNode *child = (*ci);
00814
00815 if (child->is_of_type(EggPolygon::get_class_type())) {
00816 if ((flags & T_polygon) != 0) {
00817 EggPolygon *poly = DCAST(EggPolygon, child);
00818 poly->triangulate_in_place((flags & T_convex) != 0);
00819 }
00820
00821 } else if (child->is_of_type(EggCompositePrimitive::get_class_type())) {
00822 if ((flags & T_composite) != 0) {
00823 EggCompositePrimitive *comp = DCAST(EggCompositePrimitive, child);
00824 comp->triangulate_in_place();
00825 }
00826
00827 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00828 if ((flags & T_recurse) != 0) {
00829 num_produced += DCAST(EggGroupNode, child)->triangulate_polygons(flags);
00830 }
00831 }
00832 }
00833
00834 num_produced += max(0, (int)(_children.size() - children_copy.size()));
00835 return num_produced;
00836 }
00837
00838
00839
00840
00841
00842
00843
00844 void EggGroupNode::
00845 mesh_triangles(int flags) {
00846 EggMesher mesher;
00847 mesher.mesh(this, (flags & T_flat_shaded) != 0);
00848
00849 if ((flags & T_recurse) != 0) {
00850 EggGroupNode::iterator ci;
00851 for (ci = begin(); ci != end(); ++ci) {
00852 if ((*ci)->is_of_type(EggGroupNode::get_class_type())) {
00853 EggGroupNode *group_child = DCAST(EggGroupNode, *ci);
00854 group_child->mesh_triangles(flags);
00855 }
00856 }
00857 }
00858 }
00859
00860
00861
00862
00863
00864
00865
00866
00867 void EggGroupNode::
00868 make_point_primitives() {
00869
00870
00871
00872 PT(EggGroupNode) temp = new EggGroup("temp");
00873
00874 EggGroupNode::iterator ci;
00875 for (ci = begin(); ci != end(); ++ci) {
00876 if ((*ci)->is_of_type(EggGroupNode::get_class_type())) {
00877 EggGroupNode *group_child = DCAST(EggGroupNode, *ci);
00878 group_child->make_point_primitives();
00879
00880 } else if ((*ci)->is_of_type(EggVertexPool::get_class_type())) {
00881 EggVertexPool *vpool = DCAST(EggVertexPool, *ci);
00882 PT(EggPrimitive) prim = new EggPoint;
00883 vpool->add_unused_vertices_to_prim(prim);
00884 if (!prim->empty()) {
00885 temp->add_child(prim);
00886 }
00887 }
00888 }
00889
00890 steal_children(*temp);
00891 }
00892
00893
00894
00895
00896
00897
00898 int EggGroupNode::
00899 rename_nodes(vector_string strip_prefix, bool recurse) {
00900 int num_renamed = 0;
00901 for (unsigned int ni = 0; ni < strip_prefix.size(); ++ni) {
00902 string axe_name = strip_prefix[ni];
00903 if (this->get_name().substr(0, axe_name.size()) == axe_name) {
00904 string new_name = this->get_name().substr(axe_name.size());
00905
00906 this->set_name(new_name);
00907 num_renamed += 1;
00908 }
00909 }
00910 if (recurse) {
00911 EggGroupNode::iterator ci;
00912 for (ci = begin(); ci != end(); ++ci) {
00913 if ((*ci)->is_of_type(EggGroupNode::get_class_type())) {
00914 EggGroupNode *group_child = DCAST(EggGroupNode, *ci);
00915 num_renamed += group_child->rename_nodes(strip_prefix, recurse);
00916 }
00917 else if ((*ci)->is_of_type(EggNode::get_class_type())) {
00918 EggNode *node_child = DCAST(EggNode, *ci);
00919 num_renamed += node_child->rename_node(strip_prefix);
00920 }
00921 }
00922 }
00923 return num_renamed;
00924 }
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937
00938
00939
00940
00941
00942
00943
00944
00945 int EggGroupNode::
00946 remove_unused_vertices(bool recurse) {
00947 int num_removed = 0;
00948
00949 Children::iterator ci, cnext;
00950 ci = _children.begin();
00951 while (ci != _children.end()) {
00952 cnext = ci;
00953 ++cnext;
00954 EggNode *child = *ci;
00955
00956 if (child->is_of_type(EggVertexPool::get_class_type())) {
00957 EggVertexPool *vpool = DCAST(EggVertexPool, child);
00958 num_removed += vpool->remove_unused_vertices();
00959
00960 if (vpool->empty()) {
00961
00962
00963 _children.erase(ci);
00964 }
00965
00966 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00967 if (recurse) {
00968 num_removed += DCAST(EggGroupNode, child)->remove_unused_vertices(recurse);
00969 }
00970 }
00971
00972 ci = cnext;
00973 }
00974
00975 return num_removed;
00976 }
00977
00978
00979
00980
00981
00982
00983
00984
00985
00986 int EggGroupNode::
00987 remove_invalid_primitives(bool recurse) {
00988 int num_removed = 0;
00989
00990 Children::iterator ci, cnext;
00991 ci = _children.begin();
00992 while (ci != _children.end()) {
00993 cnext = ci;
00994 ++cnext;
00995 EggNode *child = *ci;
00996
00997 if (child->is_of_type(EggPrimitive::get_class_type())) {
00998 EggPrimitive *prim = DCAST(EggPrimitive, child);
00999 if (!prim->cleanup()) {
01000 _children.erase(ci);
01001 num_removed++;
01002 }
01003
01004 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01005 if (recurse) {
01006 num_removed += DCAST(EggGroupNode, child)->remove_invalid_primitives(recurse);
01007 }
01008 }
01009
01010 ci = cnext;
01011 }
01012
01013 return num_removed;
01014 }
01015
01016
01017
01018
01019
01020
01021
01022
01023
01024
01025
01026
01027
01028 void EggGroupNode::
01029 clear_connected_shading() {
01030 Children::iterator ci;
01031 for (ci = _children.begin(); ci != _children.end(); ++ci) {
01032 EggNode *child = *ci;
01033
01034 if (child->is_of_type(EggPrimitive::get_class_type())) {
01035 EggPrimitive *prim = DCAST(EggPrimitive, child);
01036 prim->clear_connected_shading();
01037 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01038 DCAST(EggGroupNode, child)->clear_connected_shading();
01039 }
01040 }
01041 }
01042
01043
01044
01045
01046
01047
01048
01049
01050
01051 void EggGroupNode::
01052 get_connected_shading() {
01053 Children::iterator ci;
01054 for (ci = _children.begin(); ci != _children.end(); ++ci) {
01055 EggNode *child = *ci;
01056
01057 if (child->is_of_type(EggPrimitive::get_class_type())) {
01058 EggPrimitive *prim = DCAST(EggPrimitive, child);
01059 prim->get_connected_shading();
01060 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01061 DCAST(EggGroupNode, child)->get_connected_shading();
01062 }
01063 }
01064 }
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074
01075
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085
01086
01087
01088
01089
01090
01091
01092
01093
01094
01095
01096
01097 void EggGroupNode::
01098 unify_attributes(bool use_connected_shading, bool allow_per_primitive,
01099 bool recurse) {
01100 Children::iterator ci;
01101 for (ci = _children.begin(); ci != _children.end(); ++ci) {
01102 EggNode *child = *ci;
01103
01104 if (child->is_of_type(EggPrimitive::get_class_type())) {
01105 EggPrimitive *prim = DCAST(EggPrimitive, child);
01106
01107 EggPrimitive::Shading shading = EggPrimitive::S_per_vertex;
01108
01109 if (allow_per_primitive) {
01110 shading = prim->get_shading();
01111 if (use_connected_shading) {
01112 shading = prim->get_connected_shading();
01113 }
01114 }
01115
01116 prim->unify_attributes(shading);
01117
01118 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01119 if (recurse) {
01120 DCAST(EggGroupNode, child)->unify_attributes
01121 (use_connected_shading, allow_per_primitive, recurse);
01122 }
01123 }
01124 }
01125 }
01126
01127
01128
01129
01130
01131
01132
01133
01134
01135
01136
01137
01138
01139
01140
01141 void EggGroupNode::
01142 apply_last_attribute(bool recurse) {
01143 Children::iterator ci;
01144 for (ci = _children.begin(); ci != _children.end(); ++ci) {
01145 EggNode *child = *ci;
01146
01147 if (child->is_of_type(EggPrimitive::get_class_type())) {
01148 EggPrimitive *prim = DCAST(EggPrimitive, child);
01149 prim->apply_last_attribute();
01150 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01151 if (recurse) {
01152 DCAST(EggGroupNode, child)->apply_last_attribute(recurse);
01153 }
01154 }
01155 }
01156 }
01157
01158
01159
01160
01161
01162
01163
01164
01165
01166
01167
01168
01169
01170
01171
01172 void EggGroupNode::
01173 apply_first_attribute(bool recurse) {
01174 Children::iterator ci;
01175 for (ci = _children.begin(); ci != _children.end(); ++ci) {
01176 EggNode *child = *ci;
01177
01178 if (child->is_of_type(EggPrimitive::get_class_type())) {
01179 EggPrimitive *prim = DCAST(EggPrimitive, child);
01180 prim->apply_first_attribute();
01181 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01182 if (recurse) {
01183 DCAST(EggGroupNode, child)->apply_first_attribute(recurse);
01184 }
01185 }
01186 }
01187 }
01188
01189
01190
01191
01192
01193
01194
01195
01196
01197 void EggGroupNode::
01198 post_apply_flat_attribute(bool recurse) {
01199 Children::iterator ci;
01200 for (ci = _children.begin(); ci != _children.end(); ++ci) {
01201 EggNode *child = *ci;
01202
01203 if (child->is_of_type(EggPrimitive::get_class_type())) {
01204 EggPrimitive *prim = DCAST(EggPrimitive, child);
01205 prim->post_apply_flat_attribute();
01206 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01207 if (recurse) {
01208 DCAST(EggGroupNode, child)->post_apply_flat_attribute(recurse);
01209 }
01210 }
01211 }
01212 }
01213
01214
01215
01216
01217
01218
01219
01220
01221 bool EggGroupNode::
01222 has_primitives() const {
01223 Children::const_iterator ci;
01224 for (ci = _children.begin();
01225 ci != _children.end();
01226 ++ci) {
01227 if ((*ci)->has_primitives()) {
01228 return true;
01229 }
01230 }
01231
01232 return false;
01233 }
01234
01235
01236
01237
01238
01239
01240
01241
01242 bool EggGroupNode::
01243 joint_has_primitives() const {
01244 Children::const_iterator ci;
01245 for (ci = _children.begin();
01246 ci != _children.end();
01247 ++ci) {
01248 EggNode *child = (*ci);
01249
01250 if (!child->is_joint()) {
01251 if (child->joint_has_primitives()) {
01252 return true;
01253 }
01254 }
01255 }
01256
01257 return false;
01258 }
01259
01260
01261
01262
01263
01264
01265
01266
01267 bool EggGroupNode::
01268 has_normals() const {
01269 Children::const_iterator ci;
01270 for (ci = _children.begin();
01271 ci != _children.end();
01272 ++ci) {
01273 if ((*ci)->has_normals()) {
01274 return true;
01275 }
01276 }
01277
01278 return false;
01279 }
01280
01281
01282
01283
01284
01285
01286
01287
01288
01289
01290
01291
01292
01293
01294
01295 void EggGroupNode::
01296 rebuild_vertex_pools(EggVertexPools &vertex_pools, unsigned int max_vertices,
01297 bool recurse) {
01298 Children::iterator ci;
01299 for (ci = _children.begin(); ci != _children.end(); ++ci) {
01300 EggNode *child = *ci;
01301
01302 if (child->is_of_type(EggPrimitive::get_class_type())) {
01303 typedef pvector< PT(EggVertex) > Vertices;
01304 Vertices vertices;
01305 EggPrimitive *prim = DCAST(EggPrimitive, child);
01306
01307
01308 EggPrimitive::const_iterator pi;
01309 for (pi = prim->begin(); pi != prim->end(); ++pi) {
01310 vertices.push_back(*pi);
01311 }
01312
01313 typedef epvector<EggAttributes> Attributes;
01314 Attributes attributes;
01315
01316 if (prim->is_of_type(EggCompositePrimitive::get_class_type())) {
01317
01318
01319 EggCompositePrimitive *cprim = DCAST(EggCompositePrimitive, prim);
01320 int i;
01321 int num_components = cprim->get_num_components();
01322 for (i = 0; i < num_components; i++) {
01323 attributes.push_back(*cprim->get_component(i));
01324 }
01325 }
01326
01327 prim->clear();
01328
01329
01330
01331
01332 bool found_pool = false;
01333 EggVertexPool *best_pool = NULL;
01334 int best_new_vertices = 0;
01335
01336 Vertices new_vertices;
01337 EggVertexPools::iterator vpi;
01338 for (vpi = vertex_pools.begin();
01339 vpi != vertex_pools.end() && !found_pool;
01340 ++vpi) {
01341 EggVertexPool *vertex_pool = (*vpi);
01342 int num_new_vertices = 0;
01343
01344 new_vertices.clear();
01345 new_vertices.reserve(vertices.size());
01346
01347 Vertices::const_iterator vi;
01348 for (vi = vertices.begin();
01349 vi != vertices.end() && !found_pool;
01350 ++vi) {
01351 EggVertex *vertex = (*vi);
01352 EggVertex *new_vertex = vertex_pool->find_matching_vertex(*vertex);
01353 new_vertices.push_back(new_vertex);
01354 if (new_vertex == (EggVertex *)NULL) {
01355 ++num_new_vertices;
01356 }
01357 }
01358
01359 if (num_new_vertices == 0) {
01360
01361
01362 found_pool = true;
01363
01364 } else if (vertex_pool->size() + num_new_vertices <= max_vertices) {
01365
01366
01367
01368 if (best_pool == (EggVertexPool *)NULL ||
01369 num_new_vertices < best_new_vertices) {
01370
01371 best_pool = vertex_pool;
01372 best_new_vertices = num_new_vertices;
01373 }
01374 }
01375 }
01376
01377 if (!found_pool) {
01378 if (best_pool == (EggVertexPool *)NULL) {
01379
01380
01381 best_pool = new EggVertexPool("");
01382 vertex_pools.push_back(best_pool);
01383 }
01384
01385 new_vertices.clear();
01386 new_vertices.reserve(vertices.size());
01387
01388 Vertices::const_iterator vi;
01389 for (vi = vertices.begin(); vi != vertices.end(); ++vi) {
01390 EggVertex *vertex = (*vi);
01391 EggVertex *new_vertex = best_pool->create_unique_vertex(*vertex);
01392 new_vertex->copy_grefs_from(*vertex);
01393 new_vertices.push_back(new_vertex);
01394 }
01395 }
01396
01397 Vertices::const_iterator vi;
01398 nassertv(new_vertices.size() == vertices.size());
01399 for (vi = new_vertices.begin(); vi != new_vertices.end(); ++vi) {
01400 EggVertex *new_vertex = (*vi);
01401 nassertv(new_vertex != (EggVertex *)NULL);
01402 prim->add_vertex(new_vertex);
01403 }
01404
01405 if (prim->is_of_type(EggCompositePrimitive::get_class_type())) {
01406
01407 EggCompositePrimitive *cprim = DCAST(EggCompositePrimitive, prim);
01408 int i;
01409 int num_components = cprim->get_num_components();
01410 nassertv(num_components == (int)attributes.size());
01411 for (i = 0; i < num_components; i++) {
01412 cprim->set_component(i, &attributes[i]);
01413 }
01414 }
01415
01416 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01417 if (recurse) {
01418 DCAST(EggGroupNode, child)->rebuild_vertex_pools(vertex_pools, max_vertices, recurse);
01419 }
01420 }
01421 }
01422 }
01423
01424
01425
01426
01427
01428
01429
01430
01431
01432
01433
01434
01435
01436
01437 void EggGroupNode::
01438 update_under(int depth_offset) {
01439 EggNode::update_under(depth_offset);
01440
01441 Children::iterator ci;
01442 for (ci = _children.begin();
01443 ci != _children.end();
01444 ++ci) {
01445 nassertv((*ci)->get_parent() == this);
01446 (*ci)->update_under(depth_offset);
01447 }
01448 }
01449
01450
01451
01452
01453
01454
01455
01456
01457
01458
01459
01460
01461
01462
01463 void EggGroupNode::
01464 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
01465 CoordinateSystem to_cs) {
01466 Children::iterator ci;
01467 for (ci = _children.begin();
01468 ci != _children.end();
01469 ++ci) {
01470 (*ci)->r_transform(mat, inv, to_cs);
01471 }
01472 }
01473
01474
01475
01476
01477
01478
01479
01480
01481
01482
01483 void EggGroupNode::
01484 r_transform_vertices(const LMatrix4d &mat) {
01485 Children::iterator ci;
01486 for (ci = _children.begin();
01487 ci != _children.end();
01488 ++ci) {
01489 (*ci)->r_transform_vertices(mat);
01490 }
01491 }
01492
01493
01494
01495
01496
01497
01498
01499
01500
01501
01502 void EggGroupNode::
01503 r_mark_coordsys(CoordinateSystem cs) {
01504 Children::iterator ci;
01505 for (ci = _children.begin();
01506 ci != _children.end();
01507 ++ci) {
01508 (*ci)->r_mark_coordsys(cs);
01509 }
01510 }
01511
01512
01513
01514
01515
01516
01517 void EggGroupNode::
01518 r_flatten_transforms() {
01519 Children::iterator ci;
01520 for (ci = _children.begin();
01521 ci != _children.end();
01522 ++ci) {
01523 (*ci)->r_flatten_transforms();
01524 }
01525 }
01526
01527
01528
01529
01530
01531
01532 void EggGroupNode::
01533 r_apply_texmats(EggTextureCollection &textures) {
01534 Children::iterator ci;
01535 for (ci = _children.begin();
01536 ci != _children.end();
01537 ++ci) {
01538 (*ci)->r_apply_texmats(textures);
01539 }
01540 }
01541
01542
01543
01544
01545
01546
01547
01548
01549
01550 CoordinateSystem EggGroupNode::
01551 find_coordsys_entry() {
01552 CoordinateSystem coordsys = CS_default;
01553
01554
01555
01556
01557
01558
01559 Children::iterator ci, cnext;
01560 ci = _children.begin();
01561 while (ci != _children.end()) {
01562 cnext = ci;
01563 ++cnext;
01564 EggNode *child = *ci;
01565
01566 if (child->is_of_type(EggCoordinateSystem::get_class_type())) {
01567 CoordinateSystem new_cs =
01568 DCAST(EggCoordinateSystem, child)->get_value();
01569
01570
01571 prepare_remove_child(child);
01572 _children.erase(ci);
01573
01574 if (new_cs != CS_default) {
01575 if (coordsys != CS_default && coordsys != new_cs) {
01576 coordsys = CS_invalid;
01577 } else {
01578 coordsys = new_cs;
01579 }
01580 }
01581
01582 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01583 CoordinateSystem new_cs =
01584 DCAST(EggGroupNode, child)->find_coordsys_entry();
01585 if (new_cs != CS_default) {
01586 if (coordsys != CS_default && coordsys != new_cs) {
01587 coordsys = CS_invalid;
01588 } else {
01589 coordsys = new_cs;
01590 }
01591 }
01592 }
01593
01594 ci = cnext;
01595 }
01596
01597 return coordsys;
01598 }
01599
01600
01601
01602
01603
01604
01605
01606
01607
01608 int EggGroupNode::
01609 find_textures(EggTextureCollection *collection) {
01610 int num_found = 0;
01611
01612
01613
01614
01615
01616
01617 Children::iterator ci, cnext;
01618 ci = _children.begin();
01619 while (ci != _children.end()) {
01620 cnext = ci;
01621 ++cnext;
01622 EggNode *child = *ci;
01623
01624 if (child->is_of_type(EggTexture::get_class_type())) {
01625 PT_EggTexture tex = DCAST(EggTexture, child);
01626
01627
01628 prepare_remove_child(tex);
01629 _children.erase(ci);
01630
01631
01632 collection->add_texture(tex);
01633 num_found++;
01634
01635 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01636 num_found +=
01637 DCAST(EggGroupNode, child)->find_textures(collection);
01638 }
01639
01640 ci = cnext;
01641 }
01642
01643 return num_found;
01644 }
01645
01646
01647
01648
01649
01650
01651
01652
01653
01654 int EggGroupNode::
01655 find_materials(EggMaterialCollection *collection) {
01656 int num_found = 0;
01657
01658
01659
01660
01661
01662
01663 Children::iterator ci, cnext;
01664 ci = _children.begin();
01665 while (ci != _children.end()) {
01666 cnext = ci;
01667 ++cnext;
01668 EggNode *child = *ci;
01669
01670 if (child->is_of_type(EggMaterial::get_class_type())) {
01671 PT_EggMaterial tex = DCAST(EggMaterial, child);
01672
01673
01674 prepare_remove_child(tex);
01675 _children.erase(ci);
01676
01677
01678 collection->add_material(tex);
01679 num_found++;
01680
01681 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01682 num_found +=
01683 DCAST(EggGroupNode, child)->find_materials(collection);
01684 }
01685
01686 ci = cnext;
01687 }
01688
01689 return num_found;
01690 }
01691
01692
01693
01694
01695
01696
01697
01698
01699
01700
01701 bool EggGroupNode::
01702 r_load_externals(const DSearchPath &searchpath, CoordinateSystem coordsys,
01703 BamCacheRecord *record) {
01704 bool success = true;
01705
01706 Children::iterator ci;
01707 for (ci = _children.begin();
01708 ci != _children.end();
01709 ++ci) {
01710 EggNode *child = *ci;
01711 if (child->is_of_type(EggExternalReference::get_class_type())) {
01712 PT(EggExternalReference) ref = DCAST(EggExternalReference, child);
01713
01714
01715
01716 Filename filename = ref->get_filename();
01717 EggGroupNode *new_node =
01718 new EggGroupNode(filename.get_basename_wo_extension());
01719 replace(ci, new_node);
01720
01721 if (!EggData::resolve_egg_filename(filename, searchpath)) {
01722 egg_cat.error()
01723 << "Could not locate " << filename << " in "
01724 << searchpath << "\n";
01725 } else {
01726
01727
01728 EggData ext_data;
01729 ext_data.set_coordinate_system(coordsys);
01730 ext_data.set_auto_resolve_externals(true);
01731 if (ext_data.read(filename)) {
01732
01733
01734 if (record != (BamCacheRecord *)NULL) {
01735 record->add_dependent_file(filename);
01736 }
01737
01738 success =
01739 ext_data.load_externals(searchpath, record)
01740 && success;
01741 new_node->steal_children(ext_data);
01742 }
01743 }
01744
01745 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01746 EggGroupNode *group_child = DCAST(EggGroupNode, child);
01747 success =
01748 group_child->r_load_externals(searchpath, coordsys, record)
01749 && success;
01750 }
01751 }
01752 return success;
01753 }
01754
01755
01756
01757
01758
01759
01760
01761
01762
01763
01764
01765
01766
01767 void EggGroupNode::
01768 prepare_add_child(EggNode *node) {
01769 nassertv(node != (EggNode *)NULL);
01770 test_ref_count_integrity();
01771 node->test_ref_count_integrity();
01772
01773 nassertv(node->get_parent() == NULL);
01774 nassertv(node->get_depth() == 0);
01775 node->_parent = this;
01776
01777 node->update_under(get_depth() + 1);
01778 }
01779
01780
01781
01782
01783
01784
01785
01786
01787
01788
01789
01790
01791
01792 void EggGroupNode::
01793 prepare_remove_child(EggNode *node) {
01794 nassertv(node != (EggNode *)NULL);
01795
01796 nassertv(node->get_parent() == this);
01797 nassertv(node->get_depth() == get_depth() + 1);
01798 node->_parent = NULL;
01799
01800 node->update_under(-(get_depth() + 1));
01801 }
01802
01803
01804
01805
01806
01807
01808
01809
01810
01811
01812
01813 void EggGroupNode::
01814 r_collect_vertex_normals(EggGroupNode::NVertexCollection &collection,
01815 double threshold, CoordinateSystem cs) {
01816
01817
01818
01819
01820
01821 Children::iterator ci, cnext;
01822 ci = _children.begin();
01823 while (ci != _children.end()) {
01824 cnext = ci;
01825 ++cnext;
01826 EggNode *child = *ci;
01827
01828 if (child->is_of_type(EggPolygon::get_class_type())) {
01829 EggPolygon *polygon = DCAST(EggPolygon, child);
01830 polygon->clear_normal();
01831
01832 NVertexReference ref;
01833 ref._polygon = polygon;
01834 if (!polygon->calculate_normal(ref._normal, cs)) {
01835
01836
01837 prepare_remove_child(child);
01838 _children.erase(ci);
01839
01840 } else {
01841
01842
01843 size_t num_vertices = polygon->size();
01844 for (size_t i = 0; i < num_vertices; i++) {
01845 EggVertex *vertex = polygon->get_vertex(i);
01846 ref._vertex = i;
01847 collection[vertex->get_pos3()].push_back(ref);
01848 }
01849 }
01850
01851 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01852 EggGroupNode *group = DCAST(EggGroupNode, child);
01853
01854
01855
01856 if (group->is_under_instance()) {
01857 group->recompute_vertex_normals(threshold, cs);
01858 } else {
01859 group->r_collect_vertex_normals(collection, threshold, cs);
01860 }
01861 }
01862
01863 ci = cnext;
01864 }
01865 }
01866
01867
01868
01869
01870
01871
01872
01873
01874
01875 void EggGroupNode::
01876 do_compute_vertex_normals(const NVertexGroup &group) {
01877 nassertv(!group.empty());
01878
01879
01880
01881 LNormald normal(0.0, 0.0, 0.0);
01882 NVertexGroup::const_iterator gi;
01883 for (gi = group.begin(); gi != group.end(); ++gi) {
01884 const NVertexReference &ref = (*gi);
01885 normal += ref._normal;
01886 }
01887
01888 normal /= (double)group.size();
01889 normal.normalize();
01890
01891
01892
01893 for (gi = group.begin(); gi != group.end(); ++gi) {
01894 const NVertexReference &ref = (*gi);
01895 EggVertex *vertex = ref._polygon->get_vertex(ref._vertex);
01896 EggVertexPool *pool = vertex->get_pool();
01897
01898 EggVertex new_vertex(*vertex);
01899 new_vertex.set_normal(normal);
01900 EggVertex *unique = pool->create_unique_vertex(new_vertex);
01901 unique->copy_grefs_from(*vertex);
01902
01903 ref._polygon->set_vertex(ref._vertex, unique);
01904 }
01905 }
01906
01907
01908
01909
01910
01911
01912
01913
01914
01915 void EggGroupNode::
01916 r_collect_tangent_binormal(const GlobPattern &uv_name,
01917 EggGroupNode::TBNVertexCollection &collection) {
01918 Children::iterator ci;
01919 for (ci = _children.begin(); ci != _children.end(); ++ci) {
01920 EggNode *child = *ci;
01921
01922 if (child->is_of_type(EggPolygon::get_class_type())) {
01923 EggPolygon *polygon = DCAST(EggPolygon, child);
01924
01925 TBNVertexReference ref;
01926 ref._polygon = polygon;
01927
01928
01929
01930 size_t num_vertices = polygon->size();
01931 for (size_t i = 0; i < num_vertices; i++) {
01932
01933
01934
01935
01936 EggVertex *v1 = polygon->get_vertex(i);
01937 EggVertex *v2 = polygon->get_vertex((i + 1) % num_vertices);
01938 EggVertex *v3 = polygon->get_vertex((i + num_vertices - 1) % num_vertices);
01939 if (v1->has_normal() || polygon->has_normal()) {
01940
01941
01942 EggVertex::const_uv_iterator uvi;
01943 for (uvi = v1->uv_begin(); uvi != v1->uv_end(); ++uvi) {
01944 EggVertexUV *uv_obj = (*uvi);
01945 string name = uv_obj->get_name();
01946 if (uv_name.matches(name) &&
01947 v2->has_uv(name) && v3->has_uv(name)) {
01948 TBNVertexValue value;
01949 value._uv_name = name;
01950 value._pos = v1->get_pos3();
01951 if (v1->has_normal()) {
01952 value._normal = v1->get_normal();
01953 } else {
01954 value._normal = polygon->get_normal();
01955 }
01956 value._uv = v1->get_uv(name);
01957
01958
01959 LPoint3d p1 = v1->get_pos3();
01960 LPoint3d p2 = v2->get_pos3();
01961 LPoint3d p3 = v3->get_pos3();
01962
01963 LTexCoordd w1 = v1->get_uv(name);
01964 LTexCoordd w2 = v2->get_uv(name);
01965 LTexCoordd w3 = v3->get_uv(name);
01966
01967
01968
01969
01970
01971
01972
01973 value._facing = is_right(w1 - w2, w3 - w1);
01974
01975 double x1 = p2[0] - p1[0];
01976 double x2 = p3[0] - p1[0];
01977 double y1 = p2[1] - p1[1];
01978 double y2 = p3[1] - p1[1];
01979 double z1 = p2[2] - p1[2];
01980 double z2 = p3[2] - p1[2];
01981
01982 double s1 = w2[0] - w1[0];
01983 double s2 = w3[0] - w1[0];
01984 double t1 = w2[1] - w1[1];
01985 double t2 = w3[1] - w1[1];
01986
01987 double denom = (s1 * t2 - s2 * t1);
01988 if (denom == 0.0) {
01989 ref._sdir.set(0.0, 0.0, 0.0);
01990 ref._tdir.set(0.0, 0.0, 0.0);
01991 } else {
01992 double r = 1.0 / denom;
01993 ref._sdir.set((t2 * x1 - t1 * x2) * r, (t2 * y1 - t1 * y2) * r,
01994 (t2 * z1 - t1 * z2) * r);
01995 ref._tdir.set((s1 * x2 - s2 * x1) * r, (s1 * y2 - s2 * y1) * r,
01996 (s1 * z2 - s2 * z1) * r);
01997 }
01998
01999
02000 ref._vertex = i;
02001 collection[value].push_back(ref);
02002 }
02003 }
02004 }
02005 }
02006
02007 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
02008 EggGroupNode *group = DCAST(EggGroupNode, child);
02009
02010
02011
02012 if (group->is_under_instance()) {
02013 group->recompute_tangent_binormal(uv_name);
02014 } else {
02015 group->r_collect_tangent_binormal(uv_name, collection);
02016 }
02017 }
02018 }
02019 }
02020
02021
02022
02023
02024
02025
02026
02027
02028
02029
02030 void EggGroupNode::
02031 do_compute_tangent_binormal(const TBNVertexValue &value,
02032 const TBNVertexGroup &group) {
02033 nassertv(!group.empty());
02034
02035
02036
02037 LNormald sdir(0.0, 0.0, 0.0);
02038 LNormald tdir(0.0, 0.0, 0.0);
02039
02040 TBNVertexGroup::const_iterator gi;
02041 for (gi = group.begin(); gi != group.end(); ++gi) {
02042 const TBNVertexReference &ref = (*gi);
02043 sdir += ref._sdir;
02044 tdir += ref._tdir;
02045 }
02046
02047
02048
02049
02050
02051 if (!sdir.normalize()) {
02052 sdir.set(1.0, 0.0, 0.0);
02053 }
02054 if (!tdir.normalize()) {
02055 tdir = sdir.cross(LNormald(0.0, 0.0, -1.0));
02056 }
02057
02058 LNormald tangent = (sdir - value._normal * value._normal.dot(sdir));
02059 tangent.normalize();
02060
02061 LNormald binormal = cross(value._normal, tangent);
02062 if (dot(binormal, tdir) < 0.0f) {
02063 binormal = -binormal;
02064 }
02065
02066 binormal.normalize();
02067
02068
02069
02070
02071 for (gi = group.begin(); gi != group.end(); ++gi) {
02072 const TBNVertexReference &ref = (*gi);
02073 EggVertex *vertex = ref._polygon->get_vertex(ref._vertex);
02074 EggVertexPool *pool = vertex->get_pool();
02075
02076 EggVertex new_vertex(*vertex);
02077 EggVertexUV *uv_obj = new_vertex.modify_uv_obj(value._uv_name);
02078 nassertv(uv_obj != (EggVertexUV *)NULL);
02079 uv_obj->set_tangent(tangent);
02080 uv_obj->set_binormal(binormal);
02081
02082 EggVertex *unique = pool->create_unique_vertex(new_vertex);
02083 unique->copy_grefs_from(*vertex);
02084
02085 ref._polygon->set_vertex(ref._vertex, unique);
02086 }
02087 }