00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "eggGroupNode.h"
00020 #include "eggCoordinateSystem.h"
00021 #include "eggData.h"
00022 #include "eggFilenameNode.h"
00023 #include "eggExternalReference.h"
00024 #include "eggPrimitive.h"
00025 #include "eggPolygon.h"
00026 #include "eggVertexPool.h"
00027 #include "eggVertex.h"
00028 #include "eggTextureCollection.h"
00029 #include "eggMaterialCollection.h"
00030 #include "pt_EggTexture.h"
00031 #include "pt_EggMaterial.h"
00032 #include "config_egg.h"
00033
00034 #include "dSearchPath.h"
00035 #include "deg_2_rad.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 for (i = begin(); i != end(); ++i) {
00090 (*i)->write(out, indent_level);
00091 }
00092 }
00093
00094
00095
00096
00097
00098
00099 EggGroupNode::iterator EggGroupNode::
00100 begin() const {
00101 return _children.begin();
00102 }
00103
00104
00105
00106
00107
00108
00109 EggGroupNode::iterator EggGroupNode::
00110 end() const {
00111 return _children.end();
00112 }
00113
00114
00115
00116
00117
00118
00119 EggGroupNode::reverse_iterator EggGroupNode::
00120 rbegin() const {
00121 return _children.rbegin();
00122 }
00123
00124
00125
00126
00127
00128
00129 EggGroupNode::reverse_iterator EggGroupNode::
00130 rend() const {
00131 return _children.rend();
00132 }
00133
00134
00135
00136
00137
00138
00139 bool EggGroupNode::
00140 empty() const {
00141 return _children.empty();
00142 }
00143
00144
00145
00146
00147
00148
00149 EggGroupNode::size_type EggGroupNode::
00150 size() const {
00151 return _children.size();
00152 }
00153
00154
00155
00156
00157
00158
00159 EggGroupNode::iterator EggGroupNode::
00160 insert(iterator position, PT(EggNode) x) {
00161 prepare_add_child(x);
00162 return _children.insert((Children::iterator &)position, x);
00163 }
00164
00165
00166
00167
00168
00169
00170 EggGroupNode::iterator EggGroupNode::
00171 erase(iterator position) {
00172 prepare_remove_child(*position);
00173 return _children.erase((Children::iterator &)position);
00174 }
00175
00176
00177
00178
00179
00180
00181 EggGroupNode::iterator EggGroupNode::
00182 erase(iterator first, iterator last) {
00183 iterator i;
00184 for (i = first; i != last; ++i) {
00185 prepare_remove_child(*i);
00186 }
00187 return _children.erase((Children::iterator &)first,
00188 (Children::iterator &)last);
00189 }
00190
00191
00192
00193
00194
00195
00196
00197
00198 void EggGroupNode::
00199 replace(iterator position, PT(EggNode) x) {
00200 nassertv(position != end());
00201
00202 prepare_remove_child(*position);
00203 prepare_add_child(x);
00204 *(Children::iterator &)position = x;
00205 }
00206
00207
00208
00209
00210
00211
00212 void EggGroupNode::
00213 clear() {
00214 erase(begin(), end());
00215 }
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225 PT(EggNode) EggGroupNode::
00226 add_child(PT(EggNode) node) {
00227 if (node->_parent != NULL) {
00228 node->_parent->remove_child(node);
00229 }
00230 prepare_add_child(node);
00231 _children.push_back(node);
00232 return node;
00233 }
00234
00235
00236
00237
00238
00239
00240
00241
00242 PT(EggNode) EggGroupNode::
00243 remove_child(PT(EggNode) node) {
00244 iterator i = find(begin(), end(), node);
00245 if (i == end()) {
00246 return PT(EggNode)();
00247 } else {
00248
00249 erase(i);
00250 return node;
00251 }
00252 }
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262 void EggGroupNode::
00263 steal_children(EggGroupNode &other) {
00264 Children::iterator ci;
00265 for (ci = other._children.begin();
00266 ci != other._children.end();
00267 ++ci) {
00268 other.prepare_remove_child(*ci);
00269 prepare_add_child(*ci);
00270 }
00271
00272 _children.splice(_children.end(), other._children);
00273 }
00274
00275
00276
00277
00278
00279
00280
00281
00282
00283
00284 void EggGroupNode::
00285 resolve_filenames(const DSearchPath &searchpath) {
00286 Children::iterator ci;
00287 for (ci = _children.begin();
00288 ci != _children.end();
00289 ++ci) {
00290 EggNode *child = *ci;
00291 if (child->is_of_type(EggTexture::get_class_type())) {
00292 EggTexture *tex = DCAST(EggTexture, child);
00293 Filename tex_filename = tex->get_filename();
00294 tex_filename.resolve_filename(searchpath);
00295 tex->set_filename(tex_filename);
00296
00297 if (tex->has_alpha_filename()) {
00298 Filename alpha_filename = tex->get_alpha_filename();
00299 alpha_filename.resolve_filename(searchpath);
00300 tex->set_alpha_filename(alpha_filename);
00301 }
00302
00303 } else if (child->is_of_type(EggFilenameNode::get_class_type())) {
00304 EggFilenameNode *fnode = DCAST(EggFilenameNode, child);
00305 Filename filename = fnode->get_filename();
00306 filename.resolve_filename(searchpath, fnode->get_default_extension());
00307 fnode->set_filename(filename);
00308
00309 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00310 DCAST(EggGroupNode, child)->resolve_filenames(searchpath);
00311 }
00312 }
00313 }
00314
00315
00316
00317
00318
00319
00320
00321
00322 void EggGroupNode::
00323 reverse_vertex_ordering() {
00324 Children::iterator ci;
00325 for (ci = _children.begin();
00326 ci != _children.end();
00327 ++ci) {
00328 EggNode *child = *ci;
00329 if (child->is_of_type(EggPrimitive::get_class_type())) {
00330 EggPrimitive *prim = DCAST(EggPrimitive, child);
00331 prim->reverse_vertex_ordering();
00332
00333 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00334 DCAST(EggGroupNode, child)->reverse_vertex_ordering();
00335 }
00336 }
00337 }
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359 void EggGroupNode::
00360 recompute_vertex_normals(double threshold, CoordinateSystem cs) {
00361
00362
00363 NVertexCollection collection;
00364 r_collect_vertex_normals(collection, threshold, cs);
00365
00366
00367
00368
00369
00370
00371 double cos_angle = cos(deg_2_rad(threshold));
00372
00373 NVertexCollection::iterator ci;
00374 for (ci = collection.begin(); ci != collection.end(); ++ci) {
00375 NVertexGroup &group = (*ci).second;
00376
00377
00378
00379
00380 NVertexGroup::iterator gi;
00381 gi = group.begin();
00382 while (gi != group.end()) {
00383 const NVertexReference &base_ref = (*gi);
00384 NVertexGroup new_group;
00385 NVertexGroup leftover_group;
00386 new_group.push_back(base_ref);
00387 ++gi;
00388
00389 while (gi != group.end()) {
00390 const NVertexReference &ref = (*gi);
00391 double dot = base_ref._normal.dot(ref._normal);
00392 if (dot > cos_angle) {
00393
00394 new_group.push_back(ref);
00395 } else {
00396
00397 leftover_group.push_back(ref);
00398 }
00399 ++gi;
00400 }
00401
00402
00403
00404 do_compute_vertex_normals(new_group);
00405
00406
00407 group.swap(leftover_group);
00408 gi = group.begin();
00409 }
00410 }
00411 }
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 void EggGroupNode::
00433 recompute_polygon_normals(CoordinateSystem cs) {
00434 Children::iterator ci, cnext;
00435 ci = _children.begin();
00436 while (ci != _children.end()) {
00437 cnext = ci;
00438 ++cnext;
00439 EggNode *child = *ci;
00440
00441 if (child->is_of_type(EggPolygon::get_class_type())) {
00442 EggPolygon *polygon = DCAST(EggPolygon, child);
00443
00444 if (!polygon->recompute_polygon_normal(cs)) {
00445
00446 prepare_remove_child(child);
00447 _children.erase(ci);
00448
00449 } else {
00450
00451 size_t num_vertices = polygon->size();
00452 for (size_t i = 0; i < num_vertices; i++) {
00453 EggVertex *vertex = polygon->get_vertex(i);
00454 EggVertexPool *pool = vertex->get_pool();
00455
00456 if (vertex->has_normal()) {
00457 EggVertex new_vertex(*vertex);
00458 new_vertex.clear_normal();
00459 EggVertex *unique = pool->create_unique_vertex(new_vertex);
00460 unique->copy_grefs_from(*vertex);
00461
00462 polygon->set_vertex(i, unique);
00463 }
00464 }
00465 }
00466
00467 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00468 DCAST(EggGroupNode, child)->recompute_polygon_normals(cs);
00469 }
00470
00471 ci = cnext;
00472 }
00473 }
00474
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486 void EggGroupNode::
00487 strip_normals() {
00488 Children::iterator ci;
00489 for (ci = _children.begin(); ci != _children.end(); ++ci) {
00490 EggNode *child = *ci;
00491
00492 if (child->is_of_type(EggPrimitive::get_class_type())) {
00493 EggPrimitive *prim = DCAST(EggPrimitive, child);
00494 prim->clear_normal();
00495
00496
00497 size_t num_vertices = prim->size();
00498 for (size_t i = 0; i < num_vertices; i++) {
00499 EggVertex *vertex = prim->get_vertex(i);
00500 EggVertexPool *pool = vertex->get_pool();
00501
00502 if (vertex->has_normal()) {
00503 EggVertex new_vertex(*vertex);
00504 new_vertex.clear_normal();
00505 EggVertex *unique = pool->create_unique_vertex(new_vertex);
00506 unique->copy_grefs_from(*vertex);
00507
00508 prim->set_vertex(i, unique);
00509 }
00510 }
00511
00512 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00513 DCAST(EggGroupNode, child)->strip_normals();
00514 }
00515 }
00516 }
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531 int EggGroupNode::
00532 triangulate_polygons(bool convex_also) {
00533 int num_produced = 0;
00534
00535 Children children_copy = _children;
00536
00537 Children::iterator ci;
00538 for (ci = children_copy.begin();
00539 ci != children_copy.end();
00540 ++ci) {
00541 EggNode *child = (*ci);
00542
00543 if (child->is_of_type(EggPolygon::get_class_type())) {
00544 EggPolygon *poly = DCAST(EggPolygon, child);
00545 poly->triangulate_in_place(convex_also);
00546
00547 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00548 num_produced += DCAST(EggGroupNode, child)->triangulate_polygons(convex_also);
00549 }
00550 }
00551
00552 num_produced += max(0, (int)(_children.size() - children_copy.size()));
00553 return num_produced;
00554 }
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574 int EggGroupNode::
00575 remove_unused_vertices() {
00576 int num_removed = 0;
00577
00578 Children::iterator ci, cnext;
00579 ci = _children.begin();
00580 while (ci != _children.end()) {
00581 cnext = ci;
00582 ++cnext;
00583 EggNode *child = *ci;
00584
00585 if (child->is_of_type(EggVertexPool::get_class_type())) {
00586 EggVertexPool *vpool = DCAST(EggVertexPool, child);
00587 num_removed += vpool->remove_unused_vertices();
00588
00589 if (vpool->empty()) {
00590
00591
00592 _children.erase(ci);
00593 }
00594
00595 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00596 num_removed += DCAST(EggGroupNode, child)->remove_unused_vertices();
00597 }
00598
00599 ci = cnext;
00600 }
00601
00602 return num_removed;
00603 }
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613 int EggGroupNode::
00614 remove_invalid_primitives() {
00615 int num_removed = 0;
00616
00617 Children::iterator ci, cnext;
00618 ci = _children.begin();
00619 while (ci != _children.end()) {
00620 cnext = ci;
00621 ++cnext;
00622 EggNode *child = *ci;
00623
00624 if (child->is_of_type(EggPrimitive::get_class_type())) {
00625 EggPrimitive *prim = DCAST(EggPrimitive, child);
00626 if (!prim->cleanup()) {
00627 _children.erase(ci);
00628 num_removed++;
00629 }
00630
00631 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00632 num_removed += DCAST(EggGroupNode, child)->remove_invalid_primitives();
00633 }
00634
00635 ci = cnext;
00636 }
00637
00638 return num_removed;
00639 }
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 void EggGroupNode::
00655 update_under(int depth_offset) {
00656 EggNode::update_under(depth_offset);
00657
00658 Children::iterator ci;
00659 for (ci = _children.begin();
00660 ci != _children.end();
00661 ++ci) {
00662 nassertv((*ci)->get_parent() == this);
00663 (*ci)->update_under(depth_offset);
00664 }
00665 }
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680 void EggGroupNode::
00681 r_transform(const LMatrix4d &mat, const LMatrix4d &inv,
00682 CoordinateSystem to_cs) {
00683 Children::iterator ci;
00684 for (ci = _children.begin();
00685 ci != _children.end();
00686 ++ci) {
00687 (*ci)->r_transform(mat, inv, to_cs);
00688 }
00689 }
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700 void EggGroupNode::
00701 r_transform_vertices(const LMatrix4d &mat) {
00702 Children::iterator ci;
00703 for (ci = _children.begin();
00704 ci != _children.end();
00705 ++ci) {
00706 (*ci)->r_transform_vertices(mat);
00707 }
00708 }
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719 void EggGroupNode::
00720 r_mark_coordsys(CoordinateSystem cs) {
00721 Children::iterator ci;
00722 for (ci = _children.begin();
00723 ci != _children.end();
00724 ++ci) {
00725 (*ci)->r_mark_coordsys(cs);
00726 }
00727 }
00728
00729
00730
00731
00732
00733
00734 void EggGroupNode::
00735 r_flatten_transforms() {
00736 Children::iterator ci;
00737 for (ci = _children.begin();
00738 ci != _children.end();
00739 ++ci) {
00740 (*ci)->r_flatten_transforms();
00741 }
00742 }
00743
00744
00745
00746
00747
00748
00749 void EggGroupNode::
00750 r_apply_texmats(EggTextureCollection &textures) {
00751 Children::iterator ci;
00752 for (ci = _children.begin();
00753 ci != _children.end();
00754 ++ci) {
00755 (*ci)->r_apply_texmats(textures);
00756 }
00757 }
00758
00759
00760
00761
00762
00763
00764
00765
00766
00767 CoordinateSystem EggGroupNode::
00768 find_coordsys_entry() {
00769 CoordinateSystem coordsys = CS_default;
00770
00771
00772
00773
00774
00775
00776 Children::iterator ci, cnext;
00777 ci = _children.begin();
00778 while (ci != _children.end()) {
00779 cnext = ci;
00780 ++cnext;
00781 EggNode *child = *ci;
00782
00783 if (child->is_of_type(EggCoordinateSystem::get_class_type())) {
00784 CoordinateSystem new_cs =
00785 DCAST(EggCoordinateSystem, child)->get_value();
00786
00787
00788 prepare_remove_child(child);
00789 _children.erase(ci);
00790
00791 if (new_cs != CS_default) {
00792 if (coordsys != CS_default && coordsys != new_cs) {
00793 coordsys = CS_invalid;
00794 } else {
00795 coordsys = new_cs;
00796 }
00797 }
00798
00799 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00800 CoordinateSystem new_cs =
00801 DCAST(EggGroupNode, child)->find_coordsys_entry();
00802 if (new_cs != CS_default) {
00803 if (coordsys != CS_default && coordsys != new_cs) {
00804 coordsys = CS_invalid;
00805 } else {
00806 coordsys = new_cs;
00807 }
00808 }
00809 }
00810
00811 ci = cnext;
00812 }
00813
00814 return coordsys;
00815 }
00816
00817
00818
00819
00820
00821
00822
00823
00824
00825 int EggGroupNode::
00826 find_textures(EggTextureCollection *collection) {
00827 int num_found = 0;
00828
00829
00830
00831
00832
00833
00834 Children::iterator ci, cnext;
00835 ci = _children.begin();
00836 while (ci != _children.end()) {
00837 cnext = ci;
00838 ++cnext;
00839 EggNode *child = *ci;
00840
00841 if (child->is_of_type(EggTexture::get_class_type())) {
00842 PT_EggTexture tex = DCAST(EggTexture, child);
00843
00844
00845 prepare_remove_child(tex);
00846 _children.erase(ci);
00847
00848
00849 collection->add_texture(tex);
00850 num_found++;
00851
00852 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00853 num_found +=
00854 DCAST(EggGroupNode, child)->find_textures(collection);
00855 }
00856
00857 ci = cnext;
00858 }
00859
00860 return num_found;
00861 }
00862
00863
00864
00865
00866
00867
00868
00869
00870
00871 int EggGroupNode::
00872 find_materials(EggMaterialCollection *collection) {
00873 int num_found = 0;
00874
00875
00876
00877
00878
00879
00880 Children::iterator ci, cnext;
00881 ci = _children.begin();
00882 while (ci != _children.end()) {
00883 cnext = ci;
00884 ++cnext;
00885 EggNode *child = *ci;
00886
00887 if (child->is_of_type(EggMaterial::get_class_type())) {
00888 PT_EggMaterial tex = DCAST(EggMaterial, child);
00889
00890
00891 prepare_remove_child(tex);
00892 _children.erase(ci);
00893
00894
00895 collection->add_material(tex);
00896 num_found++;
00897
00898 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00899 num_found +=
00900 DCAST(EggGroupNode, child)->find_materials(collection);
00901 }
00902
00903 ci = cnext;
00904 }
00905
00906 return num_found;
00907 }
00908
00909
00910
00911
00912
00913
00914
00915
00916
00917
00918 bool EggGroupNode::
00919 r_load_externals(const DSearchPath &searchpath, CoordinateSystem coordsys) {
00920 bool success = true;
00921
00922 Children::iterator ci;
00923 for (ci = _children.begin();
00924 ci != _children.end();
00925 ++ci) {
00926 EggNode *child = *ci;
00927 if (child->is_of_type(EggExternalReference::get_class_type())) {
00928 PT(EggExternalReference) ref = DCAST(EggExternalReference, child);
00929
00930
00931
00932 Filename filename = ref->get_filename();
00933 EggGroupNode *new_node =
00934 new EggGroupNode(filename.get_basename_wo_extension());
00935 replace(ci, new_node);
00936
00937 if (!EggData::resolve_egg_filename(filename, searchpath)) {
00938 egg_cat.error()
00939 << "Could not locate " << filename << " in "
00940 << searchpath << "\n";
00941 } else {
00942
00943
00944 EggData ext_data;
00945 ext_data.set_coordinate_system(coordsys);
00946 ext_data.set_auto_resolve_externals(true);
00947 if (ext_data.read(filename)) {
00948
00949
00950 success =
00951 ext_data.load_externals(searchpath)
00952 && success;
00953 new_node->steal_children(ext_data);
00954 }
00955 }
00956
00957 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
00958 EggGroupNode *group_child = DCAST(EggGroupNode, child);
00959 success =
00960 group_child->r_load_externals(searchpath, coordsys)
00961 && success;
00962 }
00963 }
00964 return success;
00965 }
00966
00967
00968
00969
00970
00971
00972
00973
00974
00975
00976
00977
00978
00979 void EggGroupNode::
00980 prepare_add_child(EggNode *node) {
00981 nassertv(node != (EggNode *)NULL);
00982
00983 nassertv(node->get_parent() == NULL);
00984 nassertv(node->get_depth() == 0);
00985 node->_parent = this;
00986
00987 node->update_under(get_depth() + 1);
00988 }
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002 void EggGroupNode::
01003 prepare_remove_child(EggNode *node) {
01004 nassertv(node != (EggNode *)NULL);
01005
01006 nassertv(node->get_parent() == this);
01007 nassertv(node->get_depth() == get_depth() + 1);
01008 node->_parent = NULL;
01009
01010 node->update_under(-(get_depth() + 1));
01011 }
01012
01013
01014
01015
01016
01017
01018
01019
01020
01021
01022
01023 void EggGroupNode::
01024 r_collect_vertex_normals(EggGroupNode::NVertexCollection &collection,
01025 double threshold, CoordinateSystem cs) {
01026
01027
01028
01029
01030
01031 Children::iterator ci, cnext;
01032 ci = _children.begin();
01033 while (ci != _children.end()) {
01034 cnext = ci;
01035 ++cnext;
01036 EggNode *child = *ci;
01037
01038 if (child->is_of_type(EggPolygon::get_class_type())) {
01039 EggPolygon *polygon = DCAST(EggPolygon, child);
01040 polygon->clear_normal();
01041
01042 NVertexReference ref;
01043 ref._polygon = polygon;
01044 if (!polygon->calculate_normal(ref._normal, cs)) {
01045
01046
01047 prepare_remove_child(child);
01048 _children.erase(ci);
01049
01050 } else {
01051
01052
01053 size_t num_vertices = polygon->size();
01054 for (size_t i = 0; i < num_vertices; i++) {
01055 EggVertex *vertex = polygon->get_vertex(i);
01056 ref._vertex = i;
01057 collection[vertex->get_pos3()].push_back(ref);
01058 }
01059 }
01060
01061 } else if (child->is_of_type(EggGroupNode::get_class_type())) {
01062 EggGroupNode *group = DCAST(EggGroupNode, child);
01063
01064
01065
01066 if (group->is_under_instance()) {
01067 group->recompute_vertex_normals(threshold, cs);
01068 } else {
01069 group->r_collect_vertex_normals(collection, threshold, cs);
01070 }
01071 }
01072
01073 ci = cnext;
01074 }
01075 }
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085 void EggGroupNode::
01086 do_compute_vertex_normals(const NVertexGroup &group) {
01087 nassertv(!group.empty());
01088
01089
01090
01091 Normald normal(0.0, 0.0, 0.0);
01092 NVertexGroup::const_iterator gi;
01093 for (gi = group.begin(); gi != group.end(); ++gi) {
01094 const NVertexReference &ref = (*gi);
01095 normal += ref._normal;
01096 }
01097
01098 normal /= (double)group.size();
01099 normal.normalize();
01100
01101
01102
01103 for (gi = group.begin(); gi != group.end(); ++gi) {
01104 const NVertexReference &ref = (*gi);
01105 EggVertex *vertex = ref._polygon->get_vertex(ref._vertex);
01106 EggVertexPool *pool = vertex->get_pool();
01107
01108 EggVertex new_vertex(*vertex);
01109 new_vertex.set_normal(normal);
01110 EggVertex *unique = pool->create_unique_vertex(new_vertex);
01111 unique->copy_grefs_from(*vertex);
01112
01113 ref._polygon->set_vertex(ref._vertex, unique);
01114 }
01115 }
01116