| | 482 | public: |
| | 483 | |
| | 484 | UpdateTextOperation(osg::Group* group): |
| | 485 | Operation("UpdateTextOperation", true), |
| | 486 | _group(group), |
| | 487 | _maxNumChildren(20), |
| | 488 | _maxNumTextPerGeode(100) |
| | 489 | { |
| | 490 | } |
| | 491 | |
| | 492 | virtual void operator () (osg::Object* callingObject) |
| | 493 | { |
| | 494 | // decided which method to call according to whole has called me. |
| | 495 | osgViewer::Viewer* viewer = dynamic_cast<osgViewer::Viewer*>(callingObject); |
| | 496 | |
| | 497 | if (viewer) update(); |
| | 498 | else load(); |
| | 499 | } |
| | 500 | |
| | 501 | void update() |
| | 502 | { |
| | 503 | // osg::notify(osg::NOTICE)<<"*** Doing update"<<std::endl; |
| | 504 | |
| | 505 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); |
| | 506 | |
| | 507 | if (_mergeSubgraph.valid()) |
| | 508 | { |
| | 509 | _group->addChild(_mergeSubgraph.get()); |
| | 510 | |
| | 511 | _mergeSubgraph = 0; |
| | 512 | |
| | 513 | if (_group->getNumChildren()>_maxNumChildren) |
| | 514 | { |
| | 515 | osg::Geode* geode = dynamic_cast<osg::Geode*>(_group->getChild(0)); |
| | 516 | if (geode) |
| | 517 | { |
| | 518 | _availableSubgraph.push_back(geode); |
| | 519 | geode->removeDrawables(0,geode->getNumDrawables()); |
| | 520 | } |
| | 521 | _group->removeChild(0,1); |
| | 522 | } |
| | 523 | |
| | 524 | _waitOnMergeBlock.release(); |
| | 525 | } |
| | 526 | } |
| | 527 | |
| | 528 | void load() |
| | 529 | { |
| | 530 | |
| | 531 | // osg::notify(osg::NOTICE)<<"Doing load"<<std::endl; |
| | 532 | |
| | 533 | osg::ref_ptr<osg::Geode> geode; |
| | 534 | { |
| | 535 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); |
| | 536 | if (!_availableSubgraph.empty()) |
| | 537 | { |
| | 538 | geode = _availableSubgraph.front(); |
| | 539 | _availableSubgraph.pop_front(); |
| | 540 | } |
| | 541 | } |
| | 542 | |
| | 543 | if (!geode) geode = new osg::Geode; |
| | 544 | |
| | 545 | for(unsigned int i=0; i<_maxNumTextPerGeode; ++i) |
| | 546 | { |
| | 547 | osg::Vec3 position(float(rand()) / float(RAND_MAX), float(rand()) / float(RAND_MAX), float(i)/float(_maxNumTextPerGeode)); |
| | 548 | |
| | 549 | std::string str; |
| | 550 | unsigned int _numCharacters = 5; |
| | 551 | for(unsigned int ni=0; ni<_numCharacters;++ni) |
| | 552 | { |
| | 553 | str.push_back(char(32.0 + (float(rand())/float(RAND_MAX))*128.0f)); |
| | 554 | } |
| | 555 | |
| | 556 | osgText::Text* text = new osgText::Text; |
| | 557 | text->setDataVariance(osg::Object::DYNAMIC); |
| | 558 | text->setPosition(position); |
| | 559 | text->setFont("times.ttf"); |
| | 560 | text->setText(str); |
| | 561 | text->setCharacterSize(0.025f); |
| | 562 | text->setAxisAlignment(osgText::Text::SCREEN); |
| | 563 | |
| | 564 | geode->addDrawable(text); |
| | 565 | } |
| | 566 | |
| | 567 | |
| | 568 | { |
| | 569 | OpenThreads::ScopedLock<OpenThreads::Mutex> lock(_mutex); |
| | 570 | _mergeSubgraph = geode; |
| | 571 | } |
| | 572 | |
| | 573 | // osg::notify(osg::NOTICE)<<"Waiting on merge"<<std::endl; |
| | 574 | |
| | 575 | _waitOnMergeBlock.block(); |
| | 576 | |
| | 577 | } |
| | 578 | |
| | 579 | virtual void release() |
| | 580 | { |
| | 581 | _waitOnMergeBlock.release(); |
| | 582 | } |
| | 583 | |
| | 584 | typedef std::list< osg::ref_ptr<osg::Geode> > AvailableList; |
| | 585 | |
| | 586 | unsigned int _maxNumChildren; |
| | 587 | unsigned int _maxNumTextPerGeode; |
| | 588 | |
| | 589 | OpenThreads::Mutex _mutex; |
| | 590 | osg::ref_ptr<osg::Group> _group; |
| | 591 | osg::ref_ptr<osg::Geode> _mergeSubgraph; |
| | 592 | AvailableList _availableSubgraph; |
| | 593 | OpenThreads::Block _waitOnMergeBlock; |
| | 594 | |
| | 595 | unsigned int _counter; |
| | 596 | |
| | 597 | }; |
| | 598 | |
| | 599 | |
| | 600 | int main(int argc, char** argv) |
| | 601 | { |
| | 602 | osg::ArgumentParser arguments(&argc, argv); |
| | 603 | |
| 480 | | osgViewer::Viewer viewer; |
| 481 | | |
| 482 | | // prepare scene. |
| 483 | | { |
| | 605 | osgViewer::Viewer viewer(arguments); |
| | 606 | |
| | 607 | osg::ref_ptr<osg::OperationThread> operationThread; |
| | 608 | osg::ref_ptr<UpdateTextOperation> updateOperation; |
| | 609 | |
| | 610 | if (arguments.read("--mt")) |
| | 611 | { |
| | 612 | // construct a multi-threaded text updating test. |
| | 613 | |
| | 614 | // create a group to add everything into. |
| | 615 | osg::Group* mainGroup = new osg::Group; |
| | 616 | |
| | 617 | osg::Group* textGroup = new osg::Group; |
| | 618 | mainGroup->addChild(textGroup); |
| | 619 | |
| | 620 | // create the background thread |
| | 621 | operationThread = new osg::OperationThread; |
| | 622 | |
| | 623 | // create the operation that will run in the background and |
| | 624 | // sync once per frame with the main viewer loop. |
| | 625 | updateOperation = new UpdateTextOperation(textGroup); |
| | 626 | |
| | 627 | // add the operation to the operation thread and start it. |
| | 628 | operationThread->add(updateOperation.get()); |
| | 629 | operationThread->startThread(); |
| | 630 | |
| | 631 | // add the operation to the viewer to sync once per frame. |
| | 632 | viewer.addUpdateOperation(updateOperation.get()); |
| | 633 | |
| | 634 | |
| | 635 | // add a unit cube for the text to appear within. |
| | 636 | osg::Geode* geode = new osg::Geode; |
| | 637 | geode->getOrCreateStateSet()->setAttribute(new osg::PolygonMode(osg::PolygonMode::FRONT_AND_BACK,osg::PolygonMode::LINE)); |
| | 638 | geode->addDrawable(new osg::ShapeDrawable(new osg::Box(osg::Vec3(0.5f,0.5f,0.5f),1.0))); |
| | 639 | |
| | 640 | mainGroup->addChild(geode); |
| | 641 | |
| | 642 | viewer.setSceneData(mainGroup); |
| | 643 | } |
| | 644 | else |
| | 645 | { |
| | 646 | // prepare scene. |