~saiarcot895/ubuntu/trusty/openscenegraph/armhf-support

« back to all changes in this revision

Viewing changes to OpenSceneGraph/src/osgUtil/Optimizer.cpp

  • Committer: Package Import Robot
  • Author(s): Dmitrijs Ledkovs
  • Date: 2013-11-12 02:21:14 UTC
  • mfrom: (31.1.3 trusty-proposed)
  • Revision ID: package-import@ubuntu.com-20131112022114-qaxfhdnhn88vnh10
Tags: 3.2.0~rc1-1ubuntu1
Fix deprecated url_feof.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2006 Robert Osfield
2
2
 *
3
 
 * This library is open source and may be redistributed and/or modified under  
4
 
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or 
 
3
 * This library is open source and may be redistributed and/or modified under
 
4
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
5
5
 * (at your option) any later version.  The full license is in LICENSE file
6
6
 * included with this distribution, and on the openscenegraph.org website.
7
 
 * 
 
7
 *
8
8
 * This library is distributed in the hope that it will be useful,
9
9
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10
 
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 
10
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11
11
 * OpenSceneGraph Public License for more details.
12
12
*/
13
13
#include <stdlib.h>
50
50
 
51
51
using namespace osgUtil;
52
52
 
 
53
// #define GEOMETRYDEPRECATED
53
54
 
54
55
void Optimizer::reset()
55
56
{
60
61
void Optimizer::optimize(osg::Node* node)
61
62
{
62
63
    unsigned int options = 0;
63
 
    
64
 
    
 
64
 
 
65
 
65
66
    const char* env = getenv("OSG_OPTIMIZER");
66
67
    if (env)
67
68
    {
116
117
 
117
118
        if(str.find("~MAKE_FAST_GEOMETRY")!=std::string::npos) options ^= MAKE_FAST_GEOMETRY;
118
119
        else if(str.find("MAKE_FAST_GEOMETRY")!=std::string::npos) options |= MAKE_FAST_GEOMETRY;
119
 
        
 
120
 
120
121
        if(str.find("~FLATTEN_BILLBOARDS")!=std::string::npos) options ^= FLATTEN_BILLBOARDS;
121
122
        else if(str.find("FLATTEN_BILLBOARDS")!=std::string::npos) options |= FLATTEN_BILLBOARDS;
122
 
        
 
123
 
123
124
        if(str.find("~TEXTURE_ATLAS_BUILDER")!=std::string::npos) options ^= TEXTURE_ATLAS_BUILDER;
124
125
        else if(str.find("TEXTURE_ATLAS_BUILDER")!=std::string::npos) options |= TEXTURE_ATLAS_BUILDER;
125
 
        
 
126
 
126
127
        if(str.find("~STATIC_OBJECT_DETECTION")!=std::string::npos) options ^= STATIC_OBJECT_DETECTION;
127
128
        else if(str.find("STATIC_OBJECT_DETECTION")!=std::string::npos) options |= STATIC_OBJECT_DETECTION;
128
129
 
148
149
void Optimizer::optimize(osg::Node* node, unsigned int options)
149
150
{
150
151
    StatsVisitor stats;
151
 
    
 
152
 
152
153
    if (osg::getNotifyLevel()>=osg::INFO)
153
154
    {
154
155
        node->accept(stats);
168
169
        OSG_INFO<<"Optimizer::optimize() doing TESSELLATE_GEOMETRY"<<std::endl;
169
170
 
170
171
        TessellateVisitor tsv;
171
 
        node->accept(tsv);        
 
172
        node->accept(tsv);
172
173
    }
173
 
    
 
174
 
174
175
    if (options & REMOVE_LOADED_PROXY_NODES)
175
176
    {
176
177
        OSG_INFO<<"Optimizer::optimize() doing REMOVE_LOADED_PROXY_NODES"<<std::endl;
186
187
        OSG_INFO<<"Optimizer::optimize() doing COMBINE_ADJACENT_LODS"<<std::endl;
187
188
 
188
189
        CombineLODsVisitor clv(this);
189
 
        node->accept(clv);        
 
190
        node->accept(clv);
190
191
        clv.combineLODs();
191
192
    }
192
 
    
 
193
 
193
194
    if (options & OPTIMIZE_TEXTURE_SETTINGS)
194
195
    {
195
196
        OSG_INFO<<"Optimizer::optimize() doing OPTIMIZE_TEXTURE_SETTINGS"<<std::endl;
196
197
 
197
 
        TextureVisitor tv(true,true, // unref image 
 
198
        TextureVisitor tv(true,true, // unref image
198
199
                          false,false, // client storage
199
200
                          false,1.0, // anisotropic filtering
200
201
                          this );
213
214
        node->accept(osv);
214
215
        osv.optimize();
215
216
    }
216
 
    
 
217
 
217
218
    if (options & TEXTURE_ATLAS_BUILDER)
218
219
    {
219
220
        OSG_INFO<<"Optimizer::optimize() doing TEXTURE_ATLAS_BUILDER"<<std::endl;
220
 
        
 
221
 
221
222
        // traverse the scene collecting textures into texture atlas.
222
223
        TextureAtlasVisitor tav(this);
223
224
        node->accept(tav);
232
233
        node->accept(osv);
233
234
        osv.optimize();
234
235
    }
235
 
    
 
236
 
236
237
    if (options & COPY_SHARED_NODES)
237
238
    {
238
239
        OSG_INFO<<"Optimizer::optimize() doing COPY_SHARED_NODES"<<std::endl;
241
242
        node->accept(cssv);
242
243
        cssv.copySharedNodes();
243
244
    }
244
 
    
 
245
 
245
246
    if (options & FLATTEN_STATIC_TRANSFORMS)
246
247
    {
247
248
        OSG_INFO<<"Optimizer::optimize() doing FLATTEN_STATIC_TRANSFORMS"<<std::endl;
257
258
            ++i;
258
259
        } while (result);
259
260
 
260
 
        // no combine any adjacent static transforms.
 
261
        // now combine any adjacent static transforms.
261
262
        CombineStaticTransformsVisitor cstv(this);
262
263
        node->accept(cstv);
263
264
        cstv.removeTransforms(node);
267
268
    {
268
269
        OSG_INFO<<"Optimizer::optimize() doing FLATTEN_STATIC_TRANSFORMS_DUPLICATING_SHARED_SUBGRAPHS"<<std::endl;
269
270
 
270
 
        // no combine any adjacent static transforms.
 
271
        // now combine any adjacent static transforms.
271
272
        FlattenStaticTransformsDuplicatingSharedSubgraphsVisitor fstdssv(this);
272
273
        node->accept(fstdssv);
273
274
 
283
284
        node->accept(visitor);
284
285
 
285
286
        osg::Timer_t endTick = osg::Timer::instance()->tick();
286
 
        
 
287
 
287
288
        OSG_INFO<<"MERGE_GEODES took "<<osg::Timer::instance()->delta_s(startTick,endTick)<<std::endl;
288
289
    }
289
290
 
317
318
 
318
319
        OSG_INFO<<"MERGE_GEOMETRY took "<<osg::Timer::instance()->delta_s(startTick,endTick)<<std::endl;
319
320
    }
320
 
    
 
321
 
321
322
    if (options & TRISTRIP_GEOMETRY)
322
323
    {
323
324
        OSG_INFO<<"Optimizer::optimize() doing TRISTRIP_GEOMETRY"<<std::endl;
340
341
        rrnv.removeRedundantNodes();
341
342
 
342
343
    }
343
 
    
 
344
 
344
345
    if (options & FLATTEN_BILLBOARDS)
345
346
    {
346
347
        FlattenBillboardVisitor fbv(this);
414
415
////////////////////////////////////////////////////////////////////////////
415
416
 
416
417
template<typename T>
417
 
struct LessDerefFunctor 
 
418
struct LessDerefFunctor
418
419
{
419
420
    bool operator () (const T* lhs,const T* rhs) const
420
421
    {
421
 
        return (*lhs<*rhs); 
 
422
        return (*lhs<*rhs);
422
423
    }
423
424
};
424
425
 
426
427
{
427
428
    bool operator () (const osg::StateSet* lhs,const osg::StateSet* rhs) const
428
429
    {
429
 
        return (*lhs<*rhs); 
 
430
        return (*lhs<*rhs);
430
431
    }
431
432
};
432
433
 
444
445
 
445
446
void Optimizer::StateVisitor::apply(osg::Node& node)
446
447
{
447
 
    
 
448
 
448
449
    osg::StateSet* ss = node.getStateSet();
449
 
    if (ss && ss->getDataVariance()==osg::Object::STATIC) 
 
450
    if (ss && ss->getDataVariance()==osg::Object::STATIC)
450
451
    {
451
452
        if (isOperationPermissibleForObject(&node) &&
452
453
            isOperationPermissibleForObject(ss))
463
464
    if (!isOperationPermissibleForObject(&geode)) return;
464
465
 
465
466
    osg::StateSet* ss = geode.getStateSet();
466
 
    
467
 
    
 
467
 
 
468
 
468
469
    if (ss && ss->getDataVariance()==osg::Object::STATIC)
469
470
    {
470
471
        if (isOperationPermissibleForObject(ss))
504
505
        // create map from uniforms to stateset when contain them.
505
506
        typedef std::set<osg::StateSet*>                    StateSetSet;
506
507
        typedef std::map<osg::Uniform*,StateSetSet>         UniformToStateSetMap;
507
 
        
 
508
 
508
509
        const unsigned int NON_TEXTURE_ATTRIBUTE = 0xffffffff;
509
 
        
 
510
 
510
511
        UniformToStateSetMap  uniformToStateSetMap;
511
512
 
512
513
        // NOTE - TODO will need to track state attribute override value too.
515
516
            sitr!=_statesets.end();
516
517
            ++sitr)
517
518
        {
518
 
            osg::StateSet::AttributeList& attributes = sitr->first->getAttributeList();
519
 
            for(osg::StateSet::AttributeList::iterator aitr= attributes.begin();
 
519
            const osg::StateSet::AttributeList& attributes = sitr->first->getAttributeList();
 
520
            for(osg::StateSet::AttributeList::const_iterator aitr= attributes.begin();
520
521
                aitr!=attributes.end();
521
522
                ++aitr)
522
523
            {
527
528
            }
528
529
 
529
530
 
530
 
            osg::StateSet::TextureAttributeList& texAttributes = sitr->first->getTextureAttributeList();
 
531
            const osg::StateSet::TextureAttributeList& texAttributes = sitr->first->getTextureAttributeList();
531
532
            for(unsigned int unit=0;unit<texAttributes.size();++unit)
532
533
            {
533
 
                osg::StateSet::AttributeList& attributes = texAttributes[unit];
534
 
                for(osg::StateSet::AttributeList::iterator aitr= attributes.begin();
 
534
                const osg::StateSet::AttributeList& attributes = texAttributes[unit];
 
535
                for(osg::StateSet::AttributeList::const_iterator aitr= attributes.begin();
535
536
                    aitr!=attributes.end();
536
537
                    ++aitr)
537
538
                {
543
544
            }
544
545
 
545
546
 
546
 
            osg::StateSet::UniformList& uniforms = sitr->first->getUniformList();
547
 
            for(osg::StateSet::UniformList::iterator uitr= uniforms.begin();
 
547
            const osg::StateSet::UniformList& uniforms = sitr->first->getUniformList();
 
548
            for(osg::StateSet::UniformList::const_iterator uitr= uniforms.begin();
548
549
                uitr!=uniforms.end();
549
550
                ++uitr)
550
551
            {
606
607
                else first_unique = current;
607
608
            }
608
609
        }
609
 
        
610
 
                
 
610
 
 
611
 
611
612
        if (uniformToStateSetMap.size()>=2)
612
613
        {
613
614
            // create unique set of uniform pointers.
636
637
            OSG_INFO << "searching for duplicate uniforms"<< std::endl;
637
638
            // find the duplicates.
638
639
            UniformList::iterator first_unique_uniform = uniformList.begin();
639
 
            UniformList::iterator current_uniform = first_unique_uniform; 
 
640
            UniformList::iterator current_uniform = first_unique_uniform;
640
641
            ++current_uniform;
641
642
            for(; current_uniform!=uniformList.end();++current_uniform)
642
643
            {
658
659
        }
659
660
 
660
661
    }
661
 
    
 
662
 
662
663
    // duplicate state attributes removed.
663
664
    // now need to look at duplicate state sets.
664
665
    if (_statesets.size()>=2)
699
700
                    {
700
701
                        drawable->setStateSet(*first_unique);
701
702
                    }
702
 
                    else 
 
703
                    else
703
704
                    {
704
705
                        osg::Node* node = dynamic_cast<osg::Node*>(obj);
705
706
                        if (node)
712
713
            else first_unique = current;
713
714
        }
714
715
    }
715
 
    
 
716
 
716
717
}
717
718
 
718
719
////////////////////////////////////////////////////////////////////////////
758
759
            // for all current objects associated this transform with them.
759
760
            registerWithCurrentObjects(&transform);
760
761
        }
761
 
        
 
762
 
762
763
        virtual void apply(osg::Geode& geode)
763
764
        {
764
765
            traverse(geode);
765
766
        }
766
 
        
 
767
 
767
768
        virtual void apply(osg::Billboard& geode)
768
769
        {
769
770
            traverse(geode);
770
771
        }
771
 
        
 
772
 
772
773
 
773
774
        void collectDataFor(osg::Node* node)
774
775
        {
775
776
            _currentObjectList.push_back(node);
776
 
            
 
777
 
777
778
            node->accept(*this);
778
 
            
 
779
 
779
780
            _currentObjectList.pop_back();
780
781
        }
781
782
 
782
783
        void collectDataFor(osg::Billboard* billboard)
783
784
        {
784
785
            _currentObjectList.push_back(billboard);
785
 
            
 
786
 
786
787
            billboard->accept(*this);
787
 
            
 
788
 
788
789
            _currentObjectList.pop_back();
789
790
        }
790
 
        
 
791
 
791
792
        void collectDataFor(osg::Drawable* drawable)
792
793
        {
793
794
            _currentObjectList.push_back(drawable);
811
812
        {
812
813
            const osg::Drawable* drawable = dynamic_cast<const osg::Drawable*>(object);
813
814
            if (drawable) return isOperationPermissibleForObject(drawable);
814
 
            
 
815
 
815
816
            const osg::Node* node = dynamic_cast<const osg::Node*>(object);
816
817
            if (node) return isOperationPermissibleForObject(node);
817
818
 
824
825
            if (drawable && !drawable->supports(_transformFunctor)) return false;
825
826
            return BaseOptimizerVisitor::isOperationPermissibleForObject(drawable);
826
827
        }
827
 
            
 
828
 
828
829
        inline bool isOperationPermissibleForObject(const osg::Node* node) const
829
830
        {
830
831
            // disable if object is a light point node.
834
835
            return BaseOptimizerVisitor::isOperationPermissibleForObject(node);
835
836
        }
836
837
 
837
 
    protected:        
 
838
    protected:
838
839
 
839
840
        struct TransformStruct
840
841
        {
876
877
                }
877
878
                else
878
879
                {
879
 
                    if (!_transformSet.empty()) 
 
880
                    if (!_transformSet.empty())
880
881
                    {
881
882
                        if (!_firstMatrix.isIdentity()) _moreThanOneMatrixRequired=true;
882
883
                    }
889
890
            bool            _moreThanOneMatrixRequired;
890
891
            osg::Matrix     _firstMatrix;
891
892
            TransformSet    _transformSet;
892
 
        };    
 
893
        };
893
894
 
894
895
 
895
896
        void registerWithCurrentObjects(osg::Transform* transform)
913
914
 
914
915
        void disableObject(ObjectMap::iterator itr);
915
916
        void doTransform(osg::Object* obj,osg::Matrix& matrix);
916
 
        
 
917
 
917
918
        osgUtil::TransformAttributeFunctor _transformFunctor;
918
919
        TransformMap    _transformMap;
919
920
        ObjectMap       _objectMap;
940
941
    {
941
942
        osg::Matrix matrix_no_trans = matrix;
942
943
        matrix_no_trans.setTrans(0.0f,0.0f,0.0f);
943
 
        
 
944
 
944
945
        osg::Vec3 v111(1.0f,1.0f,1.0f);
945
946
        osg::Vec3 new_v111 = v111*matrix_no_trans;
946
947
        float ratio = new_v111.length()/v111.length();
947
948
 
948
949
        // move center point.
949
950
        lod->setCenter(lod->getCenter()*matrix);
950
 
        
 
951
 
951
952
        // adjust ranges to new scale.
952
953
        for(unsigned int i=0;i<lod->getNumRanges();++i)
953
954
        {
954
955
            lod->setRange(i,lod->getMinRange(i)*ratio,lod->getMaxRange(i)*ratio);
955
956
        }
956
 
        
 
957
 
957
958
        lod->dirtyBound();
958
959
        return;
959
960
    }
963
964
    {
964
965
        osg::Matrix matrix_no_trans = matrix;
965
966
        matrix_no_trans.setTrans(0.0f,0.0f,0.0f);
966
 
  
 
967
 
967
968
        osgUtil::TransformAttributeFunctor tf(matrix_no_trans);
968
969
 
969
970
        osg::Vec3 axis = osg::Matrix::transform3x3(tf._im,billboard->getAxis());
981
982
            billboard->getDrawable(i)->accept(tf);
982
983
            billboard->getDrawable(i)->dirtyBound();
983
984
        }
984
 
        
 
985
 
985
986
        billboard->dirtyBound();
986
987
 
987
988
        return;
993
994
    if (itr==_objectMap.end())
994
995
    {
995
996
        return;
996
 
    }    
 
997
    }
997
998
 
998
999
    if (itr->second._canBeApplied)
999
1000
    {
1016
1017
    if (itr==_transformMap.end())
1017
1018
    {
1018
1019
        return;
1019
 
    }    
 
1020
    }
1020
1021
 
1021
1022
    if (itr->second._canBeApplied)
1022
1023
    {
1023
 
    
 
1024
 
1024
1025
        // we havn't been disabled yet so we need to disable,
1025
1026
        itr->second._canBeApplied = false;
1026
1027
        // and then inform everybody we have been disabled.
1043
1044
    {
1044
1045
        osg::Object* object = oitr->first;
1045
1046
        ObjectStruct& os = oitr->second;
1046
 
        
 
1047
 
1047
1048
        for(ObjectStruct::TransformSet::iterator titr = os._transformSet.begin();
1048
1049
            titr != os._transformSet.end();
1049
1050
            ++titr)
1052
1053
        }
1053
1054
    }
1054
1055
 
1055
 
    // disable all the objects which have more than one matrix associated 
1056
 
    // with them, and then disable all transforms which have an object associated 
 
1056
    // disable all the objects which have more than one matrix associated
 
1057
    // with them, and then disable all transforms which have an object associated
1057
1058
    // them that can't be applied, and then disable all objects which have
1058
 
    // disabled transforms associated, recursing until all disabled 
 
1059
    // disabled transforms associated, recursing until all disabled
1059
1060
    // associativity.
1060
1061
    // and disable all objects that the operation is not permisable for)
1061
1062
    for(oitr=_objectMap.begin();
1142
1143
                        OSG_WARN<<"          model will appear in the incorrect position."<<std::endl;
1143
1144
                    }
1144
1145
                }
1145
 
                
1146
 
            }                
 
1146
 
 
1147
            }
1147
1148
        }
1148
1149
    }
1149
1150
    _objectMap.clear();
1150
1151
    _transformMap.clear();
1151
 
    
 
1152
 
1152
1153
    return transformRemoved;
1153
1154
}
1154
1155
 
1246
1247
    {
1247
1248
        cltv.collectDataFor(*bitr);
1248
1249
    }
1249
 
    
 
1250
 
1250
1251
    cltv.setUpMaps();
1251
 
    
 
1252
 
1252
1253
    for(TransformSet::iterator titr=_transformSet.begin();
1253
1254
        titr!=_transformSet.end();
1254
1255
        ++titr)
1255
1256
    {
1256
1257
        cltv.disableTransform(*titr);
1257
1258
    }
1258
 
    
 
1259
 
1259
1260
 
1260
1261
    return cltv.removeTransforms(nodeWeCannotRemove);
1261
1262
}
1275
1276
    {
1276
1277
        _transformSet.insert(&transform);
1277
1278
    }
1278
 
    
 
1279
 
1279
1280
    traverse(transform);
1280
1281
}
1281
1282
 
1283
1284
{
1284
1285
    if (nodeWeCannotRemove && nodeWeCannotRemove->asTransform()!=0 && nodeWeCannotRemove->asTransform()->asMatrixTransform()!=0)
1285
1286
    {
1286
 
        // remove topmost node if it exists in the transform set.
 
1287
        // remove topmost node from transform set if it exists there.
1287
1288
        TransformSet::iterator itr = _transformSet.find(nodeWeCannotRemove->asTransform()->asMatrixTransform());
1288
1289
        if (itr!=_transformSet.end()) _transformSet.erase(itr);
1289
1290
    }
1290
 
    
 
1291
 
1291
1292
    bool transformRemoved = false;
1292
1293
 
1293
1294
    while (!_transformSet.empty())
1295
1296
        // get the first available transform to combine.
1296
1297
        osg::ref_ptr<osg::MatrixTransform> transform = *_transformSet.begin();
1297
1298
        _transformSet.erase(_transformSet.begin());
1298
 
        
 
1299
 
1299
1300
        if (transform->getNumChildren()==1 &&
1300
1301
            transform->getChild(0)->asTransform()!=0 &&
1301
1302
            transform->getChild(0)->asTransform()->asMatrixTransform()!=0 &&
1303
1304
        {
1304
1305
            // now combine with its child.
1305
1306
            osg::MatrixTransform* child = transform->getChild(0)->asTransform()->asMatrixTransform();
1306
 
            
 
1307
 
1307
1308
            osg::Matrix newMatrix = child->getMatrix()*transform->getMatrix();
1308
1309
            child->setMatrix(newMatrix);
1309
1310
            if (transform->getStateSet())
1311
1312
                if(child->getStateSet()) child->getStateSet()->merge(*transform->getStateSet());
1312
1313
                else child->setStateSet(transform->getStateSet());
1313
1314
            }
1314
 
            
 
1315
 
1315
1316
            transformRemoved = true;
1316
1317
 
1317
1318
            osg::Node::ParentList parents = transform->getParents();
1321
1322
            {
1322
1323
                (*pitr)->replaceChild(transform.get(),child);
1323
1324
            }
1324
 
            
 
1325
 
1325
1326
        }
1326
 
        
 
1327
 
1327
1328
    }
1328
1329
    return transformRemoved;
1329
1330
}
1354
1355
    if (group.getNumParents()>0)
1355
1356
    {
1356
1357
        // only remove empty groups, but not empty occluders.
1357
 
        if (group.getNumChildren()==0 && isOperationPermissibleForObject(&group) && 
1358
 
            (typeid(group)==typeid(osg::Group) || (dynamic_cast<osg::Transform*>(&group) && !dynamic_cast<osg::CameraView*>(&group))))
 
1358
        if (group.getNumChildren()==0 && isOperationPermissibleForObject(&group) &&
 
1359
            (typeid(group)==typeid(osg::Group) || (dynamic_cast<osg::Transform*>(&group) && !dynamic_cast<osg::CameraView*>(&group))) &&
 
1360
            (group.getNumChildrenRequiringUpdateTraversal()==0 && group.getNumChildrenRequiringEventTraversal()==0) )
1359
1361
        {
1360
1362
            _redundantNodeList.insert(&group);
1361
1363
        }
1375
1377
            itr!=_redundantNodeList.end();
1376
1378
            ++itr)
1377
1379
        {
1378
 
            
 
1380
 
1379
1381
            osg::ref_ptr<osg::Node> nodeToRemove = (*itr);
1380
 
            
 
1382
 
1381
1383
            // take a copy of parents list since subsequent removes will modify the original one.
1382
1384
            osg::Node::ParentList parents = nodeToRemove->getParents();
1383
1385
 
1387
1389
            {
1388
1390
                osg::Group* parent = *pitr;
1389
1391
                if (!dynamic_cast<osg::Sequence*>(parent) &&
1390
 
                    !dynamic_cast<osg::Switch*>(parent) && 
 
1392
                    !dynamic_cast<osg::Switch*>(parent) &&
1391
1393
                    strcmp(parent->className(),"MultiSwitch")!=0)
1392
1394
                {
1393
1395
                    parent->removeChild(nodeToRemove.get());
1394
1396
                    if (parent->getNumChildren()==0) newEmptyGroups.insert(*pitr);
1395
1397
                }
1396
 
            }                
 
1398
            }
1397
1399
        }
1398
1400
 
1399
1401
        _redundantNodeList.clear();
1410
1412
{
1411
1413
    return node.getNumParents()>0 &&
1412
1414
           !node.getStateSet() &&
1413
 
           !node.getUserData() &&
1414
 
           !node.getUpdateCallback() &&
 
1415
           node.getName().empty() &&
 
1416
           !node.getUserDataContainer() &&
 
1417
           !node.getCullCallback() &&
1415
1418
           !node.getEventCallback() &&
1416
1419
           !node.getUpdateCallback() &&
1417
 
           node.getDescriptions().empty() &&
1418
 
           isOperationPermissibleForObject(&node);    
 
1420
           isOperationPermissibleForObject(&node);
1419
1421
}
1420
1422
 
1421
1423
void Optimizer::RemoveRedundantNodesVisitor::apply(osg::Group& group)
1422
1424
{
1423
 
    if (group.getNumChildren()==1 && 
 
1425
    if (group.getNumChildren()==1 &&
1424
1426
        typeid(group)==typeid(osg::Group) &&
1425
1427
        isOperationPermissible(group))
1426
1428
    {
1477
1479
        else
1478
1480
        {
1479
1481
            OSG_WARN<<"Optimizer::RemoveRedundantNodesVisitor::removeRedundantNodes() - failed dynamic_cast"<<std::endl;
1480
 
        }                                
 
1482
        }
1481
1483
    }
1482
1484
    _redundantNodeList.clear();
1483
1485
}
1509
1511
        osg::ref_ptr<osg::Group> group = dynamic_cast<osg::Group*>(*itr);
1510
1512
        if (group.valid())
1511
1513
        {
1512
 
            
 
1514
 
1513
1515
            // first check to see if data was attached to the ProxyNode that we need to keep.
1514
1516
            bool keepData = false;
1515
1517
            if (!group->getName().empty()) keepData = true;
1523
1525
            {
1524
1526
                // create a group to store all proxy's children and data.
1525
1527
                osg::ref_ptr<osg::Group> newGroup = new osg::Group(*group,osg::CopyOp::SHALLOW_COPY);
1526
 
                
 
1528
 
1527
1529
 
1528
1530
                // take a copy of parents list since subsequent removes will modify the original one.
1529
1531
                osg::Node::ParentList parents = group->getParents();
1558
1560
        else
1559
1561
        {
1560
1562
            OSG_WARN<<"Optimizer::RemoveLoadedProxyNodesVisitor::removeRedundantNodes() - failed dynamic_cast"<<std::endl;
1561
 
        }                                
 
1563
        }
1562
1564
    }
1563
1565
    _redundantNodeList.clear();
1564
1566
}
1571
1573
void Optimizer::CombineLODsVisitor::apply(osg::LOD& lod)
1572
1574
{
1573
1575
    if (dynamic_cast<osg::PagedLOD*>(&lod)==0)
1574
 
    {    
 
1576
    {
1575
1577
        for(unsigned int i=0;i<lod.getNumParents();++i)
1576
1578
        {
1577
1579
            if (typeid(*lod.getParent(i))==typeid(osg::Group))
1676
1678
// code to merge geometry object which share, state, and attribute bindings.
1677
1679
////////////////////////////////////////////////////////////////////////////
1678
1680
 
 
1681
#define COMPARE_BINDING(lhs, rhs) \
 
1682
        if (osg::getBinding(lhs)<osg::getBinding(rhs)) return true; \
 
1683
        if (osg::getBinding(rhs)<osg::getBinding(lhs)) return false;
 
1684
 
 
1685
 
1679
1686
struct LessGeometry
1680
1687
{
1681
1688
    bool operator() (const osg::Geometry* lhs,const osg::Geometry* rhs) const
1682
1689
    {
1683
1690
        if (lhs->getStateSet()<rhs->getStateSet()) return true;
1684
1691
        if (rhs->getStateSet()<lhs->getStateSet()) return false;
1685
 
        
1686
 
        if (rhs->getVertexIndices()) { if (!lhs->getVertexIndices()) return true; }
1687
 
        else if (lhs->getVertexIndices()) return false;
1688
 
        
1689
 
        if (lhs->getNormalBinding()<rhs->getNormalBinding()) return true;
1690
 
        if (rhs->getNormalBinding()<lhs->getNormalBinding()) return false;
1691
 
 
1692
 
        if (rhs->getNormalIndices()) { if (!lhs->getNormalIndices()) return true; }
1693
 
        else if (lhs->getNormalIndices()) return false;
1694
 
 
1695
 
        if (lhs->getColorBinding()<rhs->getColorBinding()) return true;
1696
 
        if (rhs->getColorBinding()<lhs->getColorBinding()) return false;
1697
 
        
1698
 
        if (rhs->getColorIndices()) { if (!lhs->getColorIndices()) return true; }
1699
 
        else if (lhs->getColorIndices()) return false;
1700
 
 
1701
 
        if (lhs->getSecondaryColorBinding()<rhs->getSecondaryColorBinding()) return true;
1702
 
        if (rhs->getSecondaryColorBinding()<lhs->getSecondaryColorBinding()) return false;
1703
 
 
1704
 
        if (rhs->getSecondaryColorIndices()) { if (!lhs->getSecondaryColorIndices()) return true; }
1705
 
        else if (lhs->getSecondaryColorIndices()) return false;
1706
 
 
1707
 
        if (lhs->getFogCoordBinding()<rhs->getFogCoordBinding()) return true;
1708
 
        if (rhs->getFogCoordBinding()<lhs->getFogCoordBinding()) return false;
1709
 
 
1710
 
        if (rhs->getFogCoordIndices()) { if (!lhs->getFogCoordIndices()) return true; }
1711
 
        else if (lhs->getFogCoordIndices()) return false;
 
1692
 
 
1693
        COMPARE_BINDING(lhs->getNormalArray(), rhs->getNormalArray())
 
1694
        COMPARE_BINDING(lhs->getColorArray(), rhs->getColorArray())
 
1695
        COMPARE_BINDING(lhs->getSecondaryColorArray(), rhs->getSecondaryColorArray())
 
1696
        COMPARE_BINDING(lhs->getFogCoordArray(), rhs->getFogCoordArray())
 
1697
 
1712
1698
 
1713
1699
        if (lhs->getNumTexCoordArrays()<rhs->getNumTexCoordArrays()) return true;
1714
1700
        if (rhs->getNumTexCoordArrays()<lhs->getNumTexCoordArrays()) return false;
1715
 
    
 
1701
 
1716
1702
        // therefore lhs->getNumTexCoordArrays()==rhs->getNumTexCoordArrays()
1717
 
        
 
1703
 
1718
1704
        unsigned int i;
1719
1705
        for(i=0;i<lhs->getNumTexCoordArrays();++i)
1720
1706
        {
1721
 
            if (rhs->getTexCoordArray(i)) 
 
1707
            if (rhs->getTexCoordArray(i))
1722
1708
            {
1723
1709
                if (!lhs->getTexCoordArray(i)) return true;
1724
1710
            }
1725
1711
            else if (lhs->getTexCoordArray(i)) return false;
 
1712
        }
1726
1713
 
1727
 
            if (rhs->getTexCoordIndices(i)) { if (!lhs->getTexCoordIndices(i)) return true; }
1728
 
            else if (lhs->getTexCoordIndices(i)) return false;
1729
 
        }
1730
 
        
1731
1714
        for(i=0;i<lhs->getNumVertexAttribArrays();++i)
1732
1715
        {
1733
 
            if (rhs->getVertexAttribArray(i)) 
 
1716
            if (rhs->getVertexAttribArray(i))
1734
1717
            {
1735
1718
                if (!lhs->getVertexAttribArray(i)) return true;
1736
1719
            }
1737
1720
            else if (lhs->getVertexAttribArray(i)) return false;
1738
 
 
1739
 
            if (rhs->getVertexAttribIndices(i)) { if (!lhs->getVertexAttribIndices(i)) return true; }
1740
 
            else if (lhs->getVertexAttribIndices(i)) return false;
1741
1721
        }
1742
 
        
1743
 
        
1744
 
        if (lhs->getNormalBinding()==osg::Geometry::BIND_OVERALL)
 
1722
 
 
1723
 
 
1724
        if (osg::getBinding(lhs->getNormalArray())==osg::Array::BIND_OVERALL)
1745
1725
        {
1746
1726
            // assumes that the bindings and arrays are set up correctly, this
1747
1727
            // should be the case after running computeCorrectBindingsAndArraySizes();
1767
1747
                break;
1768
1748
            }
1769
1749
        }
1770
 
        
1771
 
        if (lhs->getColorBinding()==osg::Geometry::BIND_OVERALL)
 
1750
 
 
1751
        if (osg::getBinding(lhs->getColorArray())==osg::Array::BIND_OVERALL)
1772
1752
        {
1773
1753
            const osg::Array* lhs_colorArray = lhs->getColorArray();
1774
1754
            const osg::Array* rhs_colorArray = rhs->getColorArray();
1791
1771
                default:
1792
1772
                    break;
1793
1773
            }
1794
 
            
 
1774
 
1795
1775
        }
1796
1776
 
1797
1777
        return false;
1827
1807
            osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
1828
1808
            if (geom && isOperationPermissibleForObject(geom))
1829
1809
            {
1830
 
                geom->computeCorrectBindingsAndArraySizes();
 
1810
#ifdef GEOMETRYDEPRECATED
 
1811
                geom1829
 
1812
                ->computeCorrectBindingsAndArraySizes();
 
1813
#endif
1831
1814
            }
1832
1815
        }
1833
1816
    }
1835
1818
 
1836
1819
void Optimizer::MakeFastGeometryVisitor::checkGeode(osg::Geode& geode)
1837
1820
{
 
1821
    // GeometryDeprecated CAN REMOVED
1838
1822
    if (isOperationPermissibleForObject(&geode))
1839
1823
    {
1840
1824
        for(unsigned int i=0;i<geode.getNumDrawables();++i)
1842
1826
            osg::Geometry* geom = geode.getDrawable(i)->asGeometry();
1843
1827
            if (geom && isOperationPermissibleForObject(geom))
1844
1828
            {
1845
 
                if (!geom->areFastPathsUsed() && !geom->getInternalOptimizedGeometry())
 
1829
                if (geom->checkForDeprecatedData())
1846
1830
                {
1847
 
                    geom->computeInternalOptimizedGeometry();
 
1831
                    geom->fixDeprecatedData();
1848
1832
                }
1849
1833
            }
1850
1834
        }
1900
1884
 
1901
1885
    if (geode.getNumDrawables()>=2)
1902
1886
    {
1903
 
    
 
1887
 
1904
1888
        // OSG_NOTICE<<"Before "<<geode.getNumDrawables()<<std::endl;
1905
 
    
 
1889
 
1906
1890
        typedef std::vector<osg::Geometry*>                         DuplicateList;
1907
1891
        typedef std::map<osg::Geometry*,DuplicateList,LessGeometry> GeometryDuplicateMap;
1908
1892
 
1931
1915
                }
1932
1916
            }
1933
1917
            else
1934
 
            {            
 
1918
            {
1935
1919
                standardDrawables.push_back(geode.getDrawable(i));
1936
1920
            }
1937
1921
        }
2018
2002
 
2019
2003
            unsigned int numVertices(duplicateList.front()->getVertexArray() ? duplicateList.front()->getVertexArray()->getNumElements() : 0);
2020
2004
            DuplicateList::iterator eachGeom(duplicateList.begin()+1);
2021
 
            // until all geometries have been checked or _targetMaximumNumberOfVertices is reached 
 
2005
            // until all geometries have been checked or _targetMaximumNumberOfVertices is reached
2022
2006
            for (;eachGeom!=duplicateList.end(); ++eachGeom)
2023
2007
            {
2024
2008
                unsigned int numAddVertices((*eachGeom)->getVertexArray() ? (*eachGeom)->getVertexArray()->getNumElements() : 0);
2049
2033
                if (duplicateListResult->size()>1) needToDoMerge = true;
2050
2034
            }
2051
2035
        }
2052
 
        
 
2036
 
2053
2037
        if (needToDoMerge)
2054
2038
        {
2055
2039
            // first take a reference to all the drawables to prevent them being deleted prematurely
2059
2043
            {
2060
2044
                keepDrawables[i] = geode.getDrawable(i);
2061
2045
            }
2062
 
            
 
2046
 
2063
2047
            // now clear the drawable list of the Geode so we don't have to remove items one by one (which is slow)
2064
2048
            geode.removeDrawables(0, geode.getNumDrawables());
2065
 
            
 
2049
 
2066
2050
            // add back in the standard drawables which arn't possible to merge.
2067
2051
            for(osg::Geode::DrawableList::iterator sitr = standardDrawables.begin();
2068
2052
                sitr != standardDrawables.end();
2070
2054
            {
2071
2055
                geode.addDrawable(sitr->get());
2072
2056
            }
2073
 
                
 
2057
 
2074
2058
            // now do the merging of geometries
2075
2059
            for(MergeList::iterator mitr = mergeList.begin();
2076
2060
                mitr != mergeList.end();
2109
2093
                    dupItr!=itr->second.end();
2110
2094
                    ++dupItr)
2111
2095
                {
2112
 
                
 
2096
 
2113
2097
                    osg::Geometry* rhs = *dupItr;
2114
 
                    
 
2098
 
2115
2099
                    if (lhs->getVertexArray() && lhs->getVertexArray()->getNumElements()>=_targetMaximumNumberOfVertices)
2116
2100
                    {
2117
2101
                        lhs = rhs;
2122
2106
                    {
2123
2107
                        continue;
2124
2108
                    }
2125
 
                    
2126
 
                    if (lhs->getVertexArray() && rhs->getVertexArray() && 
 
2109
 
 
2110
                    if (lhs->getVertexArray() && rhs->getVertexArray() &&
2127
2111
                        (lhs->getVertexArray()->getNumElements()+rhs->getVertexArray()->getNumElements())>=_targetMaximumNumberOfVertices)
2128
2112
                    {
2129
2113
                        continue;
2130
2114
                    }
2131
 
                    
 
2115
 
2132
2116
                    if (mergeGeometry(*lhs,*rhs))
2133
2117
                    {
2134
2118
                        geode.removeDrawable(rhs);
2181
2165
        if (geom)
2182
2166
        {
2183
2167
            if (geom->getNumPrimitiveSets()>0 &&
2184
 
                geom->getNormalBinding()!=osg::Geometry::BIND_PER_PRIMITIVE_SET &&
2185
 
                geom->getColorBinding()!=osg::Geometry::BIND_PER_PRIMITIVE_SET &&
2186
 
                geom->getSecondaryColorBinding()!=osg::Geometry::BIND_PER_PRIMITIVE_SET &&
2187
 
                geom->getFogCoordBinding()!=osg::Geometry::BIND_PER_PRIMITIVE_SET)
 
2168
                osg::getBinding(geom->getNormalArray())!=osg::Array::BIND_PER_PRIMITIVE_SET &&
 
2169
                osg::getBinding(geom->getColorArray())!=osg::Array::BIND_PER_PRIMITIVE_SET &&
 
2170
                osg::getBinding(geom->getSecondaryColorArray())!=osg::Array::BIND_PER_PRIMITIVE_SET &&
 
2171
                osg::getBinding(geom->getFogCoordArray())!=osg::Array::BIND_PER_PRIMITIVE_SET)
2188
2172
            {
2189
 
            
 
2173
 
2190
2174
#if 1
2191
2175
                bool doneCombine = false;
2192
2176
 
2197
2181
                {
2198
2182
                    osg::PrimitiveSet* lhs = primitives[lhsNo].get();
2199
2183
                    osg::PrimitiveSet* rhs = primitives[rhsNo].get();
2200
 
 
 
2184
 
2201
2185
                    bool combine = false;
2202
2186
 
2203
2187
                    if (lhs->getType()==rhs->getType() &&
2210
2194
                        case(osg::PrimitiveSet::LINES):
2211
2195
                        case(osg::PrimitiveSet::TRIANGLES):
2212
2196
                        case(osg::PrimitiveSet::QUADS):
2213
 
                            combine = true;       
 
2197
                            combine = true;
2214
2198
                            break;
2215
2199
                        }
2216
 
                        
 
2200
 
2217
2201
                    }
2218
2202
 
2219
2203
                    if (combine)
2220
2204
                    {
2221
 
                    
 
2205
 
2222
2206
                        switch(lhs->getType())
2223
2207
                        {
2224
2208
                        case(osg::PrimitiveSet::DrawArraysPrimitiveType):
2256
2240
                    }
2257
2241
                }
2258
2242
 
2259
 
    #if 1                
 
2243
    #if 1
2260
2244
                if (doneCombine)
2261
2245
                {
2262
2246
                    // now need to clean up primitiveset so it no longer contains the rhs combined primitives.
2264
2248
                    // first swap with a empty primitiveSet to empty it completely.
2265
2249
                    osg::Geometry::PrimitiveSetList oldPrimitives;
2266
2250
                    primitives.swap(oldPrimitives);
2267
 
                    
 
2251
 
2268
2252
                    // now add the active primitive sets
2269
2253
                    for(osg::Geometry::PrimitiveSetList::iterator pitr = oldPrimitives.begin();
2270
2254
                        pitr != oldPrimitives.end();
2275
2259
                }
2276
2260
    #endif
2277
2261
 
2278
 
#else            
 
2262
#else
2279
2263
 
2280
2264
                osg::Geometry::PrimitiveSetList& primitives = geom->getPrimitiveSetList();
2281
2265
                unsigned int primNo=0;
2283
2267
                {
2284
2268
                    osg::PrimitiveSet* lhs = primitives[primNo].get();
2285
2269
                    osg::PrimitiveSet* rhs = primitives[primNo+1].get();
2286
 
 
 
2270
 
2287
2271
                    bool combine = false;
2288
2272
 
2289
2273
                    if (lhs->getType()==rhs->getType() &&
2296
2280
                        case(osg::PrimitiveSet::LINES):
2297
2281
                        case(osg::PrimitiveSet::TRIANGLES):
2298
2282
                        case(osg::PrimitiveSet::QUADS):
2299
 
                            combine = true;       
 
2283
                            combine = true;
2300
2284
                            break;
2301
2285
                        }
2302
 
                        
 
2286
 
2303
2287
                    }
2304
2288
 
2305
2289
                    if (combine)
2306
2290
                    {
2307
 
                    
 
2291
 
2308
2292
                        switch(lhs->getType())
2309
2293
                        {
2310
2294
                        case(osg::PrimitiveSet::DrawArraysPrimitiveType):
2356
2340
    if (geom.getColorArray() && geom.getColorArray()->referenceCount()>1) return true;
2357
2341
    if (geom.getSecondaryColorArray() && geom.getSecondaryColorArray()->referenceCount()>1) return true;
2358
2342
    if (geom.getFogCoordArray() && geom.getFogCoordArray()->referenceCount()>1) return true;
2359
 
    
 
2343
 
2360
2344
 
2361
2345
    for(unsigned int unit=0;unit<geom.getNumTexCoordArrays();++unit)
2362
2346
    {
2363
2347
        osg::Array* tex = geom.getTexCoordArray(unit);
2364
2348
        if (tex && tex->referenceCount()>1) return true;
2365
2349
    }
2366
 
    
 
2350
 
2367
2351
    // shift the indices of the incoming primitives to account for the pre existing geometry.
2368
2352
    for(osg::Geometry::PrimitiveSetList::iterator primItr=geom.getPrimitiveSetList().begin();
2369
2353
        primItr!=geom.getPrimitiveSetList().end();
2371
2355
    {
2372
2356
        if ((*primItr)->referenceCount()>1) return true;
2373
2357
    }
2374
 
    
2375
 
    
 
2358
 
 
2359
 
2376
2360
    return false;
2377
2361
}
2378
2362
 
2386
2370
        MergeArrayVisitor() :
2387
2371
            _lhs(0),
2388
2372
            _offset(0) {}
2389
 
            
2390
 
            
 
2373
 
 
2374
 
2391
2375
        /// try to merge the content of two arrays.
2392
2376
        bool merge(osg::Array* lhs,osg::Array* rhs, int offset=0)
2393
2377
        {
2394
2378
            if (lhs==0 || rhs==0) return true;
2395
2379
            if (lhs->getType()!=rhs->getType()) return false;
2396
 
            
 
2380
 
2397
2381
            _lhs = lhs;
2398
2382
            _offset = offset;
2399
 
            
 
2383
 
2400
2384
            rhs->accept(*this);
2401
2385
            return true;
2402
2386
        }
2403
 
        
 
2387
 
2404
2388
        template<typename T>
2405
2389
        void _merge(T& rhs)
2406
2390
        {
2407
 
            T* lhs = static_cast<T*>(_lhs); 
 
2391
            T* lhs = static_cast<T*>(_lhs);
2408
2392
            lhs->insert(lhs->end(),rhs.begin(),rhs.end());
2409
2393
        }
2410
 
        
 
2394
 
2411
2395
        template<typename T>
2412
2396
        void _mergeAndOffset(T& rhs)
2413
2397
        {
2414
 
            T* lhs = static_cast<T*>(_lhs); 
 
2398
            T* lhs = static_cast<T*>(_lhs);
2415
2399
 
2416
2400
            typename T::iterator itr;
2417
2401
            for(itr = rhs.begin();
2421
2405
                lhs->push_back(*itr + _offset);
2422
2406
            }
2423
2407
        }
2424
 
            
 
2408
 
2425
2409
        virtual void apply(osg::Array&) { OSG_WARN << "Warning: Optimizer's MergeArrayVisitor cannot merge Array type." << std::endl; }
2426
2410
 
2427
2411
        virtual void apply(osg::ByteArray& rhs) { if (_offset) _mergeAndOffset(rhs); else  _merge(rhs); }
2436
2420
        virtual void apply(osg::Vec2Array& rhs) { _merge(rhs); }
2437
2421
        virtual void apply(osg::Vec3Array& rhs) { _merge(rhs); }
2438
2422
        virtual void apply(osg::Vec4Array& rhs) { _merge(rhs); }
2439
 
        
 
2423
 
2440
2424
        virtual void apply(osg::DoubleArray& rhs) { _merge(rhs); }
2441
2425
        virtual void apply(osg::Vec2dArray& rhs) { _merge(rhs); }
2442
2426
        virtual void apply(osg::Vec3dArray& rhs) { _merge(rhs); }
2443
2427
        virtual void apply(osg::Vec4dArray& rhs) { _merge(rhs); }
2444
 
        
 
2428
 
2445
2429
        virtual void apply(osg::Vec2bArray&  rhs) { _merge(rhs); }
2446
2430
        virtual void apply(osg::Vec3bArray&  rhs) { _merge(rhs); }
2447
 
        virtual void apply(osg::Vec4bArray&  rhs) { _merge(rhs); }        
 
2431
        virtual void apply(osg::Vec4bArray&  rhs) { _merge(rhs); }
2448
2432
        virtual void apply(osg::Vec2sArray& rhs) { _merge(rhs); }
2449
2433
        virtual void apply(osg::Vec3sArray& rhs) { _merge(rhs); }
2450
2434
        virtual void apply(osg::Vec4sArray& rhs) { _merge(rhs); }
2454
2438
{
2455
2439
 
2456
2440
    MergeArrayVisitor merger;
2457
 
 
 
2441
 
2458
2442
    unsigned int base = 0;
2459
 
    unsigned int vbase = lhs.getVertexArray() ? lhs.getVertexArray()->getNumElements() : 0; 
2460
2443
    if (lhs.getVertexArray() && rhs.getVertexArray())
2461
2444
    {
2462
2445
 
2471
2454
        base = 0;
2472
2455
        lhs.setVertexArray(rhs.getVertexArray());
2473
2456
    }
2474
 
    
2475
 
    if (lhs.getVertexIndices() && rhs.getVertexIndices())
2476
 
    {
2477
 
 
2478
 
        base = lhs.getVertexIndices()->getNumElements();
2479
 
        if (!merger.merge(lhs.getVertexIndices(),rhs.getVertexIndices(),vbase))
2480
 
        {
2481
 
            OSG_DEBUG << "MergeGeometry: vertex indices not merged. Some data may be lost." <<std::endl;
2482
 
        }
2483
 
    }
2484
 
    else if (rhs.getVertexIndices())
2485
 
    {
2486
 
        base = 0;
2487
 
        lhs.setVertexIndices(rhs.getVertexIndices());
2488
 
    }
2489
 
    
2490
 
 
2491
 
    unsigned int nbase = lhs.getNormalArray() ? lhs.getNormalArray()->getNumElements() : 0; 
2492
 
    if (lhs.getNormalArray() && rhs.getNormalArray() && lhs.getNormalBinding()!=osg::Geometry::BIND_OVERALL)
 
2457
 
 
2458
 
 
2459
    if (lhs.getNormalArray() && rhs.getNormalArray() && lhs.getNormalArray()->getBinding()!=osg::Array::BIND_OVERALL)
2493
2460
    {
2494
2461
        if (!merger.merge(lhs.getNormalArray(),rhs.getNormalArray()))
2495
2462
        {
2501
2468
        lhs.setNormalArray(rhs.getNormalArray());
2502
2469
    }
2503
2470
 
2504
 
    if (lhs.getNormalIndices() && rhs.getNormalIndices() && lhs.getNormalBinding()!=osg::Geometry::BIND_OVERALL)
2505
 
    {
2506
 
        if (!merger.merge(lhs.getNormalIndices(),rhs.getNormalIndices(),nbase))
2507
 
        {
2508
 
            OSG_DEBUG << "MergeGeometry: Vertex Array not merged. Some data may be lost." <<std::endl;
2509
 
        }
2510
 
    }
2511
 
    else if (rhs.getNormalIndices())
2512
 
    {
2513
 
        // this assignment makes the assumption that lhs.NormalArray is empty as well and NormalIndices
2514
 
        lhs.setNormalIndices(rhs.getNormalIndices());
2515
 
    }
2516
 
 
2517
 
 
2518
 
    unsigned int cbase = lhs.getColorArray() ? lhs.getColorArray()->getNumElements() : 0; 
2519
 
    if (lhs.getColorArray() && rhs.getColorArray() && lhs.getColorBinding()!=osg::Geometry::BIND_OVERALL)
 
2471
 
 
2472
    if (lhs.getColorArray() && rhs.getColorArray() && lhs.getColorArray()->getBinding()!=osg::Array::BIND_OVERALL)
2520
2473
    {
2521
2474
        if (!merger.merge(lhs.getColorArray(),rhs.getColorArray()))
2522
2475
        {
2527
2480
    {
2528
2481
        lhs.setColorArray(rhs.getColorArray());
2529
2482
    }
2530
 
    
2531
 
    if (lhs.getColorIndices() && rhs.getColorIndices() && lhs.getColorBinding()!=osg::Geometry::BIND_OVERALL)
2532
 
    {
2533
 
        if (!merger.merge(lhs.getColorIndices(),rhs.getColorIndices(),cbase))
2534
 
        {
2535
 
            OSG_DEBUG << "MergeGeometry: color indices not merged. Some data may be lost." <<std::endl;
2536
 
        }
2537
 
    }
2538
 
    else if (rhs.getColorIndices())
2539
 
    {
2540
 
        // this assignment makes the assumption that lhs.ColorArray is empty as well and ColorIndices
2541
 
        lhs.setColorIndices(rhs.getColorIndices());
2542
 
    }
2543
2483
 
2544
 
    unsigned int scbase = lhs.getSecondaryColorArray() ? lhs.getSecondaryColorArray()->getNumElements() : 0; 
2545
 
    if (lhs.getSecondaryColorArray() && rhs.getSecondaryColorArray() && lhs.getSecondaryColorBinding()!=osg::Geometry::BIND_OVERALL)
 
2484
    if (lhs.getSecondaryColorArray() && rhs.getSecondaryColorArray() && lhs.getSecondaryColorArray()->getBinding()!=osg::Array::BIND_OVERALL)
2546
2485
    {
2547
2486
        if (!merger.merge(lhs.getSecondaryColorArray(),rhs.getSecondaryColorArray()))
2548
2487
        {
2553
2492
    {
2554
2493
        lhs.setSecondaryColorArray(rhs.getSecondaryColorArray());
2555
2494
    }
2556
 
    
2557
 
    if (lhs.getSecondaryColorIndices() && rhs.getSecondaryColorIndices() && lhs.getSecondaryColorBinding()!=osg::Geometry::BIND_OVERALL)
2558
 
    {
2559
 
        if (!merger.merge(lhs.getSecondaryColorIndices(),rhs.getSecondaryColorIndices(),scbase))
2560
 
        {
2561
 
            OSG_DEBUG << "MergeGeometry: secondary color indices not merged. Some data may be lost." <<std::endl;
2562
 
        }
2563
 
    }
2564
 
    else if (rhs.getSecondaryColorIndices())
2565
 
    {
2566
 
        // this assignment makes the assumption that lhs.SecondaryColorArray is empty as well and SecondaryColorIndices
2567
 
        lhs.setSecondaryColorIndices(rhs.getSecondaryColorIndices());
2568
 
    }
2569
2495
 
2570
 
    unsigned int fcbase = lhs.getFogCoordArray() ? lhs.getFogCoordArray()->getNumElements() : 0; 
2571
 
    if (lhs.getFogCoordArray() && rhs.getFogCoordArray() && lhs.getFogCoordBinding()!=osg::Geometry::BIND_OVERALL)
 
2496
    if (lhs.getFogCoordArray() && rhs.getFogCoordArray() && lhs.getFogCoordArray()->getBinding()!=osg::Array::BIND_OVERALL)
2572
2497
    {
2573
2498
        if (!merger.merge(lhs.getFogCoordArray(),rhs.getFogCoordArray()))
2574
2499
        {
2580
2505
        lhs.setFogCoordArray(rhs.getFogCoordArray());
2581
2506
    }
2582
2507
 
2583
 
    if (lhs.getFogCoordIndices() && rhs.getFogCoordIndices() && lhs.getFogCoordBinding()!=osg::Geometry::BIND_OVERALL)
2584
 
    {
2585
 
        if (!merger.merge(lhs.getFogCoordIndices(),rhs.getFogCoordIndices(),fcbase))
2586
 
        {
2587
 
            OSG_DEBUG << "MergeGeometry: fog coord indices not merged. Some data may be lost." <<std::endl;
2588
 
        }
2589
 
    }
2590
 
    else if (rhs.getFogCoordIndices())
2591
 
    {
2592
 
        // this assignment makes the assumption that lhs.FogCoordArray is empty as well and FogCoordIndices
2593
 
        lhs.setFogCoordIndices(rhs.getFogCoordIndices());
2594
 
    }
2595
 
 
2596
2508
 
2597
2509
    unsigned int unit;
2598
2510
    for(unit=0;unit<lhs.getNumTexCoordArrays();++unit)
2599
2511
    {
2600
 
        unsigned int tcbase = lhs.getTexCoordArray(unit) ? lhs.getTexCoordArray(unit)->getNumElements() : 0; 
2601
2512
        if (!merger.merge(lhs.getTexCoordArray(unit),rhs.getTexCoordArray(unit)))
2602
2513
        {
2603
2514
            OSG_DEBUG << "MergeGeometry: tex coord array not merged. Some data may be lost." <<std::endl;
2604
2515
        }
 
2516
    }
2605
2517
 
2606
 
        if (lhs.getTexCoordIndices(unit) && rhs.getTexCoordIndices(unit))
2607
 
        {
2608
 
            if (!merger.merge(lhs.getTexCoordIndices(unit),rhs.getTexCoordIndices(unit),tcbase))
2609
 
            {
2610
 
                OSG_DEBUG << "MergeGeometry: tex coord indices not merged. Some data may be lost." <<std::endl;
2611
 
            }
2612
 
        }
2613
 
    }
2614
 
    
2615
2518
    for(unit=0;unit<lhs.getNumVertexAttribArrays();++unit)
2616
2519
    {
2617
 
        unsigned int vabase = lhs.getVertexAttribArray(unit) ? lhs.getVertexAttribArray(unit)->getNumElements() : 0; 
2618
2520
        if (!merger.merge(lhs.getVertexAttribArray(unit),rhs.getVertexAttribArray(unit)))
2619
2521
        {
2620
2522
            OSG_DEBUG << "MergeGeometry: vertex attrib array not merged. Some data may be lost." <<std::endl;
2621
2523
        }
2622
 
        
2623
 
        if (lhs.getVertexAttribIndices(unit) && rhs.getVertexAttribIndices(unit))
2624
 
        {
2625
 
            if (!merger.merge(lhs.getVertexAttribIndices(unit),rhs.getVertexAttribIndices(unit),vabase))
2626
 
            {
2627
 
                OSG_DEBUG << "MergeGeometry: vertex attrib indices not merged. Some data may be lost." <<std::endl;
2628
 
            }
2629
 
        }
2630
2524
    }
2631
2525
 
2632
2526
 
2635
2529
    for(primItr=rhs.getPrimitiveSetList().begin(); primItr!=rhs.getPrimitiveSetList().end(); ++primItr)
2636
2530
    {
2637
2531
        osg::PrimitiveSet* primitive = primItr->get();
2638
 
        
 
2532
 
2639
2533
        switch(primitive->getType())
2640
2534
        {
2641
2535
        case(osg::PrimitiveSet::DrawElementsUBytePrimitiveType):
2703
2597
            break;
2704
2598
        }
2705
2599
    }
2706
 
    
 
2600
 
2707
2601
    for(primItr=rhs.getPrimitiveSetList().begin(); primItr!=rhs.getPrimitiveSetList().end(); ++primItr)
2708
2602
    {
2709
2603
        lhs.addPrimitiveSet(primItr->get());
2711
2605
 
2712
2606
    lhs.dirtyBound();
2713
2607
    lhs.dirtyDisplayList();
2714
 
    
 
2608
 
2715
2609
    return true;
2716
2610
}
2717
2611
 
2794
2688
    {
2795
2689
        if (divide(*itr,maxNumTreesPerCell)) divided = true;
2796
2690
    }
2797
 
    
 
2691
 
2798
2692
    for(GeodesToDivideList::iterator geode_itr=_geodesToDivideList.begin();
2799
2693
        geode_itr!=_geodesToDivideList.end();
2800
2694
        ++geode_itr)
2801
2695
    {
2802
2696
        if (divide(*geode_itr,maxNumTreesPerCell)) divided = true;
2803
2697
    }
2804
 
    
 
2698
 
2805
2699
    return divided;
2806
2700
}
2807
2701
 
2808
2702
bool Optimizer::SpatializeGroupsVisitor::divide(osg::Group* group, unsigned int maxNumTreesPerCell)
2809
2703
{
2810
2704
    if (group->getNumChildren()<=maxNumTreesPerCell) return false;
2811
 
    
 
2705
 
2812
2706
    // create the original box.
2813
2707
    osg::BoundingBox bb;
2814
2708
    unsigned int i;
2816
2710
    {
2817
2711
        bb.expandBy(group->getChild(i)->getBound().center());
2818
2712
    }
2819
 
    
 
2713
 
2820
2714
    float radius = bb.radius();
2821
2715
    float divide_distance = radius*0.7f;
2822
2716
    bool xAxis = (bb.xMax()-bb.xMin())>divide_distance;
2824
2718
    bool zAxis = (bb.zMax()-bb.zMin())>divide_distance;
2825
2719
 
2826
2720
    OSG_INFO<<"Dividing "<<group->className()<<"  num children = "<<group->getNumChildren()<<"  xAxis="<<xAxis<<"  yAxis="<<yAxis<<"   zAxis="<<zAxis<<std::endl;
2827
 
    
 
2721
 
2828
2722
    if (!xAxis && !yAxis && !zAxis)
2829
2723
    {
2830
2724
        OSG_INFO<<"  No axis to divide, stopping division."<<std::endl;
2831
2725
        return false;
2832
2726
    }
2833
 
    
 
2727
 
2834
2728
    unsigned int numChildrenOnEntry = group->getNumChildren();
2835
 
    
 
2729
 
2836
2730
    typedef std::pair< osg::BoundingBox, osg::ref_ptr<osg::Group> > BoxGroupPair;
2837
2731
    typedef std::vector< BoxGroupPair > Boxes;
2838
2732
    Boxes boxes;
2839
2733
    boxes.push_back( BoxGroupPair(bb,new osg::Group) );
2840
2734
 
2841
 
    // divide up on each axis    
 
2735
    // divide up on each axis
2842
2736
    if (xAxis)
2843
2737
    {
2844
2738
        unsigned int numCellsToDivide=boxes.size();
2889
2783
 
2890
2784
 
2891
2785
    // create the groups to drop the children into
2892
 
    
 
2786
 
2893
2787
 
2894
2788
    // bin each child into associated bb group
2895
2789
    typedef std::vector< osg::ref_ptr<osg::Node> > NodeList;
2920
2814
    //      first removing from the original group,
2921
2815
    //      add in the bb groups
2922
2816
    //      add then the unassigned children.
2923
 
    
2924
 
    
 
2817
 
 
2818
 
2925
2819
    // first removing from the original group,
2926
2820
    group->removeChildren(0,group->getNumChildren());
2927
 
    
 
2821
 
2928
2822
    // add in the bb groups
2929
2823
    typedef std::vector< osg::ref_ptr<osg::Group> > GroupList;
2930
2824
    GroupList groupsToDivideList;
2950
2844
            }
2951
2845
        }
2952
2846
    }
2953
 
    
2954
 
    
 
2847
 
 
2848
 
2955
2849
    // add then the unassigned children.
2956
2850
    for(NodeList::iterator nitr=unassignedList.begin();
2957
2851
        nitr!=unassignedList.end();
2969
2863
    }
2970
2864
 
2971
2865
    return (numChildrenOnEntry<group->getNumChildren());
2972
 
    
 
2866
 
2973
2867
}
2974
2868
 
2975
2869
bool Optimizer::SpatializeGroupsVisitor::divide(osg::Geode* geode, unsigned int maxNumTreesPerCell)
2976
2870
{
2977
2871
 
2978
2872
    if (geode->getNumDrawables()<=maxNumTreesPerCell) return false;
2979
 
    
 
2873
 
2980
2874
    // create the original box.
2981
2875
    osg::BoundingBox bb;
2982
2876
    unsigned int i;
2984
2878
    {
2985
2879
        bb.expandBy(geode->getDrawable(i)->getBound().center());
2986
2880
    }
2987
 
    
 
2881
 
2988
2882
    float radius = bb.radius();
2989
2883
    float divide_distance = radius*0.7f;
2990
2884
    bool xAxis = (bb.xMax()-bb.xMin())>divide_distance;
2992
2886
    bool zAxis = (bb.zMax()-bb.zMin())>divide_distance;
2993
2887
 
2994
2888
    OSG_INFO<<"INFO "<<geode->className()<<"  num drawables = "<<geode->getNumDrawables()<<"  xAxis="<<xAxis<<"  yAxis="<<yAxis<<"   zAxis="<<zAxis<<std::endl;
2995
 
    
 
2889
 
2996
2890
    if (!xAxis && !yAxis && !zAxis)
2997
2891
    {
2998
2892
        OSG_INFO<<"  No axis to divide, stopping division."<<std::endl;
2999
2893
        return false;
3000
2894
    }
3001
 
    
 
2895
 
3002
2896
    osg::Node::ParentList parents = geode->getParents();
3003
 
    if (parents.empty()) 
 
2897
    if (parents.empty())
3004
2898
    {
3005
2899
        OSG_INFO<<"  Cannot perform spatialize on root Geode, add a Group above it to allow subdivision."<<std::endl;
3006
2900
        return false;
3015
2909
        newGeode->addDrawable(geode->getDrawable(i));
3016
2910
        group->addChild(newGeode);
3017
2911
    }
3018
 
    
 
2912
 
3019
2913
    divide(group.get(), maxNumTreesPerCell);
3020
 
    
 
2914
 
3021
2915
    // keep reference around to prevent it being deleted.
3022
2916
    osg::ref_ptr<osg::Geode> keepRefGeode = geode;
3023
 
    
 
2917
 
3024
2918
    for(osg::Node::ParentList::iterator itr = parents.begin();
3025
2919
        itr != parents.end();
3026
2920
        ++itr)
3027
2921
    {
3028
2922
        (*itr)->replaceChild(geode, group.get());
3029
2923
    }
3030
 
    
 
2924
 
3031
2925
    return true;
3032
2926
}
3033
2927
 
3059
2953
            // create a clone.
3060
2954
            osg::ref_ptr<osg::Object> new_object = node->clone(osg::CopyOp::DEEP_COPY_NODES |
3061
2955
                                                          osg::CopyOp::DEEP_COPY_DRAWABLES);
3062
 
            // cast it to node.                                              
 
2956
            // cast it to node.
3063
2957
            osg::Node* new_node = dynamic_cast<osg::Node*>(new_object.get());
3064
2958
 
3065
 
            // replace the node by new_new 
 
2959
            // replace the node by new_new
3066
2960
            if (new_node) node->getParent(i)->replaceChild(node,new_node);
3067
2961
        }
3068
2962
    }
3077
2971
 
3078
2972
void Optimizer::TextureVisitor::apply(osg::Node& node)
3079
2973
{
3080
 
    
 
2974
 
3081
2975
    osg::StateSet* ss = node.getStateSet();
3082
 
    if (ss && 
 
2976
    if (ss &&
3083
2977
        isOperationPermissibleForObject(&node) &&
3084
2978
        isOperationPermissibleForObject(ss))
3085
2979
    {
3094
2988
    if (!isOperationPermissibleForObject(&geode)) return;
3095
2989
 
3096
2990
    osg::StateSet* ss = geode.getStateSet();
3097
 
    
 
2991
 
3098
2992
    if (ss && isOperationPermissibleForObject(ss))
3099
2993
    {
3100
2994
        apply(*ss);
3139
3033
            osg::ImageStream* is = dynamic_cast<osg::ImageStream*>(texture.getImage(i));
3140
3034
            if (is) ++numImageStreams;
3141
3035
        }
3142
 
        
 
3036
 
3143
3037
        if (numImageStreams==0)
3144
3038
        {
3145
3039
            texture.setUnRefImageDataAfterApply(_valueAutoUnRef);
3146
3040
        }
3147
3041
    }
3148
 
    
 
3042
 
3149
3043
    if (_changeClientImageStorage)
3150
3044
    {
3151
3045
        texture.setClientStorageHint(_valueClientImageStorage);
3152
3046
    }
3153
 
    
 
3047
 
3154
3048
    if (_changeAnisotropy)
3155
3049
    {
3156
3050
        texture.setMaxAnisotropy(_valueAnisotropy);
3195
3089
        // this is done so we don't have to do a search and remove from the list later on.
3196
3090
        children[i] = group.getChild(i);
3197
3091
    }
3198
 
    
 
3092
 
3199
3093
    // remove all children
3200
3094
    group.removeChildren(0,group.getNumChildren());
3201
3095
 
3204
3098
    {
3205
3099
        osg::Node* child = children[i].get();
3206
3100
 
3207
 
        if (typeid(*child)==typeid(osg::Geode)) 
 
3101
        if (typeid(*child)==typeid(osg::Geode))
3208
3102
        {
3209
3103
            osg::Geode* geode = static_cast<osg::Geode*>(child);
3210
3104
            geodeDuplicateMap[geode].push_back(geode);
3218
3112
 
3219
3113
    // if no geodes then just return.
3220
3114
    if (geodeDuplicateMap.empty()) return false;
3221
 
    
 
3115
 
3222
3116
    OSG_INFO<<"mergeGeodes in group '"<<group.getName()<<"' "<<geodeDuplicateMap.size()<<std::endl;
3223
 
    
 
3117
 
3224
3118
    // merge
3225
3119
    for(GeodeDuplicateMap::iterator itr=geodeDuplicateMap.begin();
3226
3120
        itr!=geodeDuplicateMap.end();
3232
3126
 
3233
3127
            // add geode back into group
3234
3128
            group.addChild(lhs);
3235
 
            
 
3129
 
3236
3130
            for(DuplicateList::iterator dupItr=itr->second.begin()+1;
3237
3131
                dupItr!=itr->second.end();
3238
3132
                ++dupItr)
3284
3178
        itr != _billboards.end();
3285
3179
        ++itr)
3286
3180
    {
3287
 
        bool mergeAcceptable = true;    
 
3181
        bool mergeAcceptable = true;
3288
3182
 
3289
3183
        osg::ref_ptr<osg::Billboard> billboard = itr->first;
3290
3184
 
3291
3185
        NodePathList& npl = itr->second;
3292
3186
        osg::Group* mainGroup = 0;
3293
3187
        if (npl.size()>1)
3294
 
        {        
 
3188
        {
3295
3189
            for(NodePathList::iterator nitr = npl.begin();
3296
3190
                nitr != npl.end();
3297
3191
                ++nitr)
3305
3199
                    osg::MatrixTransform* mt = dynamic_cast<osg::MatrixTransform*>(np[np.size()-2]);
3306
3200
 
3307
3201
                    if (group == mainGroup &&
3308
 
                        np[np.size()-1]==billboard.get() && 
 
3202
                        np[np.size()-1]==billboard.get() &&
3309
3203
                        mt && mt->getDataVariance()==osg::Object::STATIC &&
3310
3204
                        mt->getNumChildren()==1)
3311
3205
                    {
3337
3231
            new_billboard->setMode(billboard->getMode());
3338
3232
            new_billboard->setAxis(billboard->getAxis());
3339
3233
            new_billboard->setStateSet(billboard->getStateSet());
3340
 
            new_billboard->setName(billboard->getName());                
 
3234
            new_billboard->setName(billboard->getName());
3341
3235
 
3342
3236
            mainGroup->addChild(new_billboard);
3343
3237
 
3432
3326
            if (y_min >= y_max || x_min >= x_max) continue;
3433
3327
 
3434
3328
            Source * source = sitr3->get();
3435
 
            if (source->_atlas || atlas->_image->getPixelFormat() != source->_image->getPixelFormat() || 
 
3329
            if (source->_atlas || atlas->_image->getPixelFormat() != source->_image->getPixelFormat() ||
3436
3330
                atlas->_image->getDataType() != source->_image->getDataType())
3437
3331
            {
3438
3332
                continue;
3470
3364
            for(SourceList::iterator sitr2 = _sourceList.begin(); sitr2 != _sourceList.end(); ++sitr2)
3471
3365
            {
3472
3366
                Source * source = sitr2->get();
3473
 
                if (source->_atlas || atlas->_image->getPixelFormat() != source->_image->getPixelFormat() || 
 
3367
                if (source->_atlas || atlas->_image->getPixelFormat() != source->_image->getPixelFormat() ||
3474
3368
                    atlas->_image->getDataType() != source->_image->getDataType())
3475
3369
                {
3476
3370
                    continue;
3519
3413
                aitr != _atlasList.end() && !addedSourceToAtlas;
3520
3414
                ++aitr)
3521
3415
            {
3522
 
                if(!(*aitr)->_image || 
 
3416
                if(!(*aitr)->_image ||
3523
3417
                    ((*aitr)->_image->getPixelFormat() == (*sitr)->_image->getPixelFormat() &&
3524
3418
                    (*aitr)->_image->getPacking() == (*sitr)->_image->getPacking()))
3525
3419
                {
3553
3447
            }
3554
3448
        }
3555
3449
    }
3556
 
    
 
3450
 
3557
3451
    // build the atlas which are suitable for use, and discard the rest.
3558
3452
    AtlasList activeAtlasList;
3559
3453
    for(AtlasList::iterator aitr = _atlasList.begin();
3570
3464
            source->_atlas = 0;
3571
3465
            atlas->_sourceList.clear();
3572
3466
        }
3573
 
        
 
3467
 
3574
3468
        if (!(atlas->_sourceList.empty()))
3575
3469
        {
3576
3470
            std::stringstream ostr;
3671
3565
bool Optimizer::TextureAtlasBuilder::Source::suitableForAtlas(int maximumAtlasWidth, int maximumAtlasHeight, int margin)
3672
3566
{
3673
3567
    if (!_image) return false;
3674
 
    
 
3568
 
3675
3569
    // size too big?
3676
3570
    if (_image->s()+margin*2 > maximumAtlasWidth) return false;
3677
3571
    if (_image->t()+margin*2 > maximumAtlasHeight) return false;
3678
 
    
 
3572
 
3679
3573
    switch(_image->getPixelFormat())
3680
3574
    {
3681
3575
        case(GL_COMPRESSED_ALPHA_ARB):
3694
3588
            break;
3695
3589
    }
3696
3590
 
3697
 
    if ((_image->getPixelSizeInBits() % 8) != 0) 
 
3591
    if ((_image->getPixelSizeInBits() % 8) != 0)
3698
3592
    {
3699
3593
        // pixel size not byte aligned so report as not suitable to prevent other atlas code from having problems with byte boundaries.
3700
3594
        return false;
3722
3616
            return false;
3723
3617
        }
3724
3618
    }
3725
 
    
 
3619
 
3726
3620
    return true;
3727
3621
}
3728
3622
 
3742
3636
    // does the source have a valid image?
3743
3637
    const osg::Image* sourceImage = source->_image.get();
3744
3638
    if (!sourceImage) return DOES_NOT_FIT_IN_ANY_ROW;
3745
 
    
 
3639
 
3746
3640
    // does pixel format match?
3747
3641
    if (_image.valid())
3748
3642
    {
3749
3643
        if (_image->getPixelFormat() != sourceImage->getPixelFormat()) return DOES_NOT_FIT_IN_ANY_ROW;
3750
3644
        if (_image->getDataType() != sourceImage->getDataType()) return DOES_NOT_FIT_IN_ANY_ROW;
3751
3645
    }
3752
 
    
 
3646
 
3753
3647
    const osg::Texture2D* sourceTexture = source->_texture.get();
3754
3648
    if (sourceTexture)
3755
3649
    {
3776
3670
        if (_texture.valid())
3777
3671
        {
3778
3672
 
3779
 
            bool sourceUsesBorder = sourceTexture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::CLAMP_TO_BORDER || 
 
3673
            bool sourceUsesBorder = sourceTexture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::CLAMP_TO_BORDER ||
3780
3674
                                    sourceTexture->getWrap(osg::Texture2D::WRAP_T)==osg::Texture2D::CLAMP_TO_BORDER;
3781
3675
 
3782
 
            bool atlasUsesBorder = sourceTexture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::CLAMP_TO_BORDER || 
 
3676
            bool atlasUsesBorder = sourceTexture->getWrap(osg::Texture2D::WRAP_S)==osg::Texture2D::CLAMP_TO_BORDER ||
3783
3677
                                   sourceTexture->getWrap(osg::Texture2D::WRAP_T)==osg::Texture2D::CLAMP_TO_BORDER;
3784
3678
 
3785
3679
            if (sourceUsesBorder!=atlasUsesBorder)
3793
3687
                // border colours don't match
3794
3688
                if (_texture->getBorderColor() != sourceTexture->getBorderColor()) return DOES_NOT_FIT_IN_ANY_ROW;
3795
3689
            }
3796
 
            
 
3690
 
3797
3691
            if (_texture->getFilter(osg::Texture2D::MIN_FILTER) != sourceTexture->getFilter(osg::Texture2D::MIN_FILTER))
3798
3692
            {
3799
3693
                // inconsitent min filters
3800
3694
                return DOES_NOT_FIT_IN_ANY_ROW;
3801
3695
            }
3802
 
 
 
3696
 
3803
3697
            if (_texture->getFilter(osg::Texture2D::MAG_FILTER) != sourceTexture->getFilter(osg::Texture2D::MAG_FILTER))
3804
3698
            {
3805
3699
                // inconsitent mag filters
3806
3700
                return DOES_NOT_FIT_IN_ANY_ROW;
3807
3701
            }
3808
 
            
 
3702
 
3809
3703
            if (_texture->getMaxAnisotropy() != sourceTexture->getMaxAnisotropy())
3810
3704
            {
3811
3705
                // anisotropy different.
3812
3706
                return DOES_NOT_FIT_IN_ANY_ROW;
3813
3707
            }
3814
 
            
 
3708
 
3815
3709
            if (_texture->getInternalFormat() != sourceTexture->getInternalFormat())
3816
3710
            {
3817
3711
                // internal formats inconistent
3818
3712
                return DOES_NOT_FIT_IN_ANY_ROW;
3819
3713
            }
3820
 
            
 
3714
 
3821
3715
            if (_texture->getShadowCompareFunc() != sourceTexture->getShadowCompareFunc())
3822
3716
            {
3823
3717
                // shadow functions inconsitent
3824
3718
                return DOES_NOT_FIT_IN_ANY_ROW;
3825
3719
            }
3826
 
                
 
3720
 
3827
3721
            if (_texture->getShadowTextureMode() != sourceTexture->getShadowTextureMode())
3828
3722
            {
3829
3723
                // shadow texture mode inconsitent
3837
3731
            }
3838
3732
        }
3839
3733
    }
3840
 
    
 
3734
 
3841
3735
    if (sourceImage->s() + 2*_margin > _maximumAtlasWidth)
3842
3736
    {
3843
3737
        // image too big for Atlas
3844
3738
        return DOES_NOT_FIT_IN_ANY_ROW;
3845
3739
    }
3846
 
    
 
3740
 
3847
3741
    if (sourceImage->t() + 2*_margin > _maximumAtlasHeight)
3848
3742
    {
3849
3743
        // image too big for Atlas
3871
3765
        OSG_INFO<<"Fits in next row"<<std::endl;
3872
3766
        return IN_NEXT_ROW;
3873
3767
    }
3874
 
    
 
3768
 
3875
3769
    // no space for the texture
3876
3770
    return DOES_NOT_FIT_IN_ANY_ROW;
3877
3771
}
3902
3796
 
3903
3797
        _texture->setWrap(osg::Texture2D::WRAP_S, sourceTexture->getWrap(osg::Texture2D::WRAP_S));
3904
3798
        _texture->setWrap(osg::Texture2D::WRAP_T, sourceTexture->getWrap(osg::Texture2D::WRAP_T));
3905
 
        
 
3799
 
3906
3800
        _texture->setBorderColor(sourceTexture->getBorderColor());
3907
3801
        _texture->setBorderWidth(0);
3908
 
            
 
3802
 
3909
3803
        _texture->setFilter(osg::Texture2D::MIN_FILTER, sourceTexture->getFilter(osg::Texture2D::MIN_FILTER));
3910
3804
        _texture->setFilter(osg::Texture2D::MAG_FILTER, sourceTexture->getFilter(osg::Texture2D::MAG_FILTER));
3911
3805
 
3931
3825
        source->_x = _x + _margin;
3932
3826
        source->_y = _y + _margin;
3933
3827
        source->_atlas = this;
3934
 
        
 
3828
 
3935
3829
        // move the atlas' cursor along to the right
3936
3830
        _x += sourceImage->s() + 2*_margin;
3937
 
        
 
3831
 
3938
3832
        if (_x > _width) _width = _x;
3939
 
        
 
3833
 
3940
3834
        int localTop = _y + sourceImage->t() + 2*_margin;
3941
3835
        if ( localTop > _height) _height = localTop;
3942
3836
 
3959
3853
        source->_x = _x + _margin;
3960
3854
        source->_y = _y + _margin;
3961
3855
        source->_atlas = this;
3962
 
        
 
3856
 
3963
3857
        // move the atlas' cursor along to the right
3964
3858
        _x += sourceImage->s() + 2*_margin;
3965
3859
 
3985
3879
 
3986
3880
    int h = 1;
3987
3881
    while (h<_height) h *= 2;
3988
 
    
 
3882
 
3989
3883
    OSG_INFO<<"Clamping "<<_width<<", "<<_height<<" to "<<w<<","<<h<<std::endl;
3990
 
    
 
3884
 
3991
3885
    _width = w;
3992
3886
    _height = h;
3993
3887
}
4002
3896
    _image->allocateImage(_width,_height,1,
4003
3897
                          pixelFormat, dataType,
4004
3898
                          packing);
4005
 
                          
 
3899
 
4006
3900
    {
4007
3901
        // clear memory
4008
3902
        unsigned int size = _image->getTotalSizeInBytes();
4009
3903
        unsigned char* str = _image->data();
4010
3904
        for(unsigned int i=0; i<size; ++i) *(str++) = 0;
4011
 
    }        
 
3905
    }
4012
3906
 
4013
3907
    OSG_INFO<<"Atlas::copySources() "<<std::endl;
4014
3908
 
4051
3945
                    *(destPtr++) = *(sourcePtr++);
4052
3946
                }
4053
3947
            }
4054
 
            
 
3948
 
4055
3949
            // copy top row margin
4056
3950
            y = source->_y + sourceImage->t();
4057
3951
            int m;
4063
3957
                {
4064
3958
                    *(destPtr++) = *(sourcePtr++);
4065
3959
                }
4066
 
                
 
3960
 
4067
3961
            }
4068
 
            
 
3962
 
4069
3963
 
4070
3964
 
4071
3965
            // copy bottom row margin
4078
3972
                {
4079
3973
                    *(destPtr++) = *(sourcePtr++);
4080
3974
                }
4081
 
                
 
3975
 
4082
3976
            }
4083
3977
 
4084
3978
            // copy left column margin
4095
3989
                        *(destPtr++) = *(sourcePtr++);
4096
3990
                    }
4097
3991
                }
4098
 
            }            
 
3992
            }
4099
3993
 
4100
3994
            // copy right column margin
4101
3995
            y = source->_y;
4111
4005
                        *(destPtr++) = *(sourcePtr++);
4112
4006
                    }
4113
4007
                }
4114
 
            }            
 
4008
            }
4115
4009
 
4116
4010
            // copy top left corner margin
4117
4011
            y = source->_y + sourceImage->t();
4176
4070
 
4177
4071
bool Optimizer::TextureAtlasVisitor::pushStateSet(osg::StateSet* stateset)
4178
4072
{
4179
 
    osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
4180
 
    
 
4073
    const osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
 
4074
 
4181
4075
    // if no textures ignore
4182
4076
    if (tal.empty()) return false;
4183
 
    
 
4077
 
4184
4078
    bool pushStateState = false;
4185
4079
 
4186
4080
    // if already in stateset list ignore
4187
 
    if (_statesetMap.count(stateset)>0) 
 
4081
    if (_statesetMap.count(stateset)>0)
4188
4082
    {
4189
4083
        pushStateState = true;
4190
4084
    }
4207
4101
            pushStateState = true;
4208
4102
        }
4209
4103
    }
4210
 
    
 
4104
 
4211
4105
    if (pushStateState)
4212
4106
    {
4213
4107
        _statesetStack.push_back(stateset);
4214
4108
    }
4215
4109
 
4216
 
    
4217
 
    return pushStateState;  
 
4110
 
 
4111
    return pushStateState;
4218
4112
}
4219
4113
 
4220
4114
void Optimizer::TextureAtlasVisitor::popStateSet()
4225
4119
void Optimizer::TextureAtlasVisitor::apply(osg::Node& node)
4226
4120
{
4227
4121
    bool pushedStateState = false;
4228
 
    
 
4122
 
4229
4123
    osg::StateSet* ss = node.getStateSet();
4230
 
    if (ss && ss->getDataVariance()==osg::Object::STATIC) 
 
4124
    if (ss && ss->getDataVariance()==osg::Object::STATIC)
4231
4125
    {
4232
4126
        if (isOperationPermissibleForObject(&node) &&
4233
4127
            isOperationPermissibleForObject(ss))
4237
4131
    }
4238
4132
 
4239
4133
    traverse(node);
4240
 
    
 
4134
 
4241
4135
    if (pushedStateState) popStateSet();
4242
4136
}
4243
4137
 
4246
4140
    if (!isOperationPermissibleForObject(&geode)) return;
4247
4141
 
4248
4142
    osg::StateSet* ss = geode.getStateSet();
4249
 
    
4250
 
    
 
4143
 
 
4144
 
4251
4145
    bool pushedGeodeStateState = false;
4252
4146
 
4253
4147
    if (ss && ss->getDataVariance()==osg::Object::STATIC)
4274
4168
                    pushedDrawableStateState = pushStateSet(ss);
4275
4169
                }
4276
4170
            }
4277
 
            
 
4171
 
4278
4172
            if (!_statesetStack.empty())
4279
4173
            {
4280
4174
                for(StateSetStack::iterator ssitr = _statesetStack.begin();
4281
 
                    ssitr != _statesetStack.end(); 
 
4175
                    ssitr != _statesetStack.end();
4282
4176
                    ++ssitr)
4283
4177
                {
4284
4178
                    _statesetMap[*ssitr].insert(drawable);
4287
4181
 
4288
4182
            if (pushedDrawableStateState) popStateSet();
4289
4183
        }
4290
 
        
 
4184
 
4291
4185
    }
4292
 
    
 
4186
 
4293
4187
    if (pushedGeodeStateState) popStateSet();
4294
4188
}
4295
4189
 
4296
4190
void Optimizer::TextureAtlasVisitor::optimize()
4297
4191
{
4298
4192
    _builder.reset();
4299
 
    
 
4193
 
4300
4194
    if (_textures.size()<2)
4301
4195
    {
4302
4196
        // nothing to optimize
4314
4208
        osg::StateSet* stateset = sitr->first;
4315
4209
        Drawables& drawables = sitr->second;
4316
4210
 
4317
 
        osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
 
4211
        const osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
4318
4212
        for(unsigned int unit=0; unit<tal.size(); ++unit)
4319
4213
        {
4320
4214
            osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(stateset->getTextureAttribute(unit,osg::StateAttribute::TEXTURE));
4325
4219
 
4326
4220
                bool t_repeat = texture->getWrap(osg::Texture2D::WRAP_T)==osg::Texture2D::REPEAT ||
4327
4221
                                texture->getWrap(osg::Texture2D::WRAP_T)==osg::Texture2D::MIRROR;
4328
 
                               
 
4222
 
4329
4223
                if (s_repeat || t_repeat)
4330
4224
                {
4331
4225
                    texturesThatRepeat.insert(texture);
4332
 
                
 
4226
 
4333
4227
                    bool s_outOfRange = false;
4334
4228
                    bool t_outOfRange = false;
4335
 
  
 
4229
 
4336
4230
                    float s_min = -0.001;
4337
4231
                    float s_max = 1.001;
4338
4232
 
4339
4233
                    float t_min = -0.001;
4340
4234
                    float t_max = 1.001;
4341
 
                    
 
4235
 
4342
4236
                    for(Drawables::iterator ditr = drawables.begin();
4343
4237
                        ditr != drawables.end();
4344
4238
                        ++ditr)
4364
4258
                            // if no texcoords then texgen must be being used, therefore must assume that texture is truely repeating
4365
4259
                            s_outOfRange = true;
4366
4260
                            t_outOfRange = true;
4367
 
                        }                        
 
4261
                        }
4368
4262
                    }
4369
4263
 
4370
 
                    if (s_outOfRange || t_outOfRange) 
4371
 
                    {                    
 
4264
                    if (s_outOfRange || t_outOfRange)
 
4265
                    {
4372
4266
                        texturesThatRepeatAndAreOutOfRange.insert(texture);
4373
4267
                    }
4374
4268
 
4377
4271
        }
4378
4272
    }
4379
4273
 
4380
 
    // now change any texture that repeat but all texcoords to them 
 
4274
    // now change any texture that repeat but all texcoords to them
4381
4275
    // are in 0 to 1 range than converting the to CLAMP mode, to allow them
4382
4276
    // to be used in an atlas.
4383
4277
    Textures::iterator titr;
4390
4284
        {
4391
4285
            // safe to convert into CLAMP wrap mode.
4392
4286
            OSG_INFO<<"Changing wrap mode to CLAMP"<<std::endl;
4393
 
            texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture::CLAMP);
4394
 
            texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture::CLAMP);
 
4287
            texture->setWrap(osg::Texture2D::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
 
4288
            texture->setWrap(osg::Texture2D::WRAP_T, osg::Texture::CLAMP_TO_EDGE);
4395
4289
        }
4396
4290
    }
4397
4291
    //typedef std::list<osg::Texture2D *> SourceListTmp;
4409
4303
        bool t_repeat = texture->getWrap(osg::Texture2D::WRAP_T)==osg::Texture2D::REPEAT ||
4410
4304
                        texture->getWrap(osg::Texture2D::WRAP_T)==osg::Texture2D::MIRROR;
4411
4305
 
4412
 
        if (!s_repeat && !t_repeat)
 
4306
        if (texture->getImage() && !s_repeat && !t_repeat)
4413
4307
        {
4414
4308
            _builder.addSource(*titr);
4415
4309
        }
4433
4327
            dssm[(*ditr)->asGeometry()].insert(sitr->first);
4434
4328
        }
4435
4329
    }
4436
 
    
 
4330
 
4437
4331
    Drawables drawablesThatHaveMultipleTexturesOnOneUnit;
4438
4332
    for(DrawableStateSetMap::iterator ditr = dssm.begin();
4439
4333
        ditr != dssm.end();
4474
4368
 
4475
4369
        }
4476
4370
    }
4477
 
        
4478
 
    // remap the textures in the StateSet's 
 
4371
 
 
4372
    // remap the textures in the StateSet's
4479
4373
    for(sitr = _statesetMap.begin();
4480
4374
        sitr != _statesetMap.end();
4481
4375
        ++sitr)
4482
4376
    {
4483
4377
        osg::StateSet* stateset = sitr->first;
4484
 
        osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
 
4378
        const osg::StateSet::TextureAttributeList& tal = stateset->getTextureAttributeList();
4485
4379
        for(unsigned int unit=0; unit<tal.size(); ++unit)
4486
4380
        {
4487
4381
            osg::Texture2D* texture = dynamic_cast<osg::Texture2D*>(stateset->getTextureAttribute(unit,osg::StateAttribute::TEXTURE));
4502
4396
                    }
4503
4397
 
4504
4398
                    stateset->setTextureAttribute(unit, newTexture);
4505
 
                    
 
4399
 
4506
4400
                    Drawables& drawables = sitr->second;
4507
 
                    
 
4401
 
4508
4402
                    osg::Matrix matrix = _builder.getTextureMatrix(texture);
4509
 
                    
 
4403
 
4510
4404
                    // first check to see if all drawables are ok for applying texturematrix to.
4511
4405
                    bool canTexMatBeFlattenedToAllDrawables = true;
4512
4406
                    for(Drawables::iterator ditr = drawables.begin();
4516
4410
                        osg::Geometry* geom = (*ditr)->asGeometry();
4517
4411
                        osg::Vec2Array* texcoords = geom ? dynamic_cast<osg::Vec2Array*>(geom->getTexCoordArray(unit)) : 0;
4518
4412
 
4519
 
                        if (!texcoords) 
 
4413
                        if (!texcoords)
4520
4414
                        {
4521
4415
                            canTexMatBeFlattenedToAllDrawables = false;
4522
4416
                        }
4523
 
                        
 
4417
 
4524
4418
                        if (drawablesThatHaveMultipleTexturesOnOneUnit.count(*ditr)!=0)
4525
4419
                        {
4526
4420
                            canTexMatBeFlattenedToAllDrawables = false;
4550
4444
                            else
4551
4445
                            {
4552
4446
                                OSG_NOTICE<<"Error, Optimizer::TextureAtlasVisitor::optimize() shouldn't ever get here..."<<std::endl;
4553
 
                            }                        
 
4447
                            }
4554
4448
                        }
4555
4449
                    }
4556
4450
                    else
4596
4490
 
4597
4491
 
4598
4492
void Optimizer::StaticObjectDetectionVisitor::applyDrawable(osg::Drawable& drawable)
4599
 
{   
4600
 
    
 
4493
{
 
4494
 
4601
4495
    if (drawable.getStateSet()) applyStateSet(*drawable.getStateSet());
4602
 
    
 
4496
 
4603
4497
    drawable.computeDataVariance();
4604
4498
}
4605
4499
 
4630
4524
        if(parent_group)
4631
4525
        {
4632
4526
            parent_group->replaceChild(&group, new_group);
 
4527
            // also replace the node in the nodepath
 
4528
            _nodePath[nodepathsize-1] = new_group;
4633
4529
            // traverse the new Group
4634
4530
            traverse(*(new_group));
4635
4531
        }
4660
4556
        transform.computeLocalToWorldMatrix(matrix, this);
4661
4557
        _matrixStack.push_back(matrix);
4662
4558
        pushed = true;
4663
 
    
 
4559
 
4664
4560
        // convert this Transform to a Group
4665
4561
        osg::ref_ptr<osg::Group> group = new osg::Group(dynamic_cast<osg::Group&>(transform),
4666
4562
            osg::CopyOp::DEEP_COPY_NODES | osg::CopyOp::DEEP_COPY_DRAWABLES | osg::CopyOp::DEEP_COPY_ARRAYS);
4671
4567
        if(parent_group)
4672
4568
        {
4673
4569
            parent_group->replaceChild(&transform, group.get());
 
4570
            // also replace the node in the nodepath
 
4571
            _nodePath[nodepathsize-1] = group.get();
4674
4572
            // traverse the new Group
4675
4573
            traverse(*(group.get()));
4676
4574
        }
4705
4603
        if(parent_group)
4706
4604
        {
4707
4605
            parent_group->replaceChild(&lod, new_lod.get());
4708
 
 
 
4606
            // also replace the node in the nodepath
 
4607
            _nodePath[nodepathsize-1] = new_lod.get();
4709
4608
            // move center point
4710
4609
            if(!_matrixStack.empty())
4711
4610
                new_lod->setCenter(new_lod->getCenter() * _matrixStack.back());
4735
4634
        if(geode.getNumParents() == 1)
4736
4635
        {
4737
4636
            transformGeode(geode);
4738
 
        }    
 
4637
        }
4739
4638
        else
4740
4639
        {
4741
4640
            // Else make a copy and then transform