| 12 | | // |
| 13 | | // A simple demo demonstrating usage of osg::Sequence. |
| 14 | | // |
| 15 | | |
| 16 | | // simple event handler to start/stop sequences |
| 17 | | class MyEventHandler : public osgGA::GUIEventHandler { |
| | 25 | // create text drawable at 'pos' |
| | 26 | osg::Geode* createText(const std::string& str, const osg::Vec3& pos) |
| | 27 | { |
| | 28 | // text drawable |
| | 29 | osgText::Text* text = new osgText::Text; |
| | 30 | text->setFont(std::string("fonts/arial.ttf")); |
| | 31 | text->setPosition(pos); |
| | 32 | text->setText(str); |
| | 33 | |
| | 34 | // geode |
| | 35 | osg::Geode* geode = new osg::Geode; |
| | 36 | geode->addDrawable(text); |
| | 37 | |
| | 38 | return geode; |
| | 39 | } |
| | 40 | |
| | 41 | osg::Node* createTextGroup(const char** text) |
| | 42 | { |
| | 43 | osg::Group* group = new osg::Group; |
| | 44 | |
| | 45 | osg::Vec3 pos(120.0f, 800.0f, 0.0f); |
| | 46 | const osg::Vec3 delta(0.0f, -60.0f, 0.0f); |
| | 47 | |
| | 48 | // header |
| | 49 | const char** t = text; |
| | 50 | group->addChild(createText(*t++, pos)); |
| | 51 | pos += delta; |
| | 52 | |
| | 53 | // remainder of text under sequence |
| | 54 | osg::Sequence* seq = new osg::Sequence; |
| | 55 | group->addChild(seq); |
| | 56 | while (*t) { |
| | 57 | seq->addChild(createText(*t++, pos)); |
| | 58 | seq->setTime(seq->getNumChildren()-1, 2.0f); |
| | 59 | pos += delta; |
| | 60 | } |
| | 61 | |
| | 62 | // loop through all children |
| | 63 | seq->setInterval(osg::Sequence::LOOP, 0,-1); |
| | 64 | |
| | 65 | // real-time playback, repeat indefinitively |
| | 66 | seq->setDuration(1.0f, -1); |
| | 67 | |
| | 68 | // must be started explicitly |
| | 69 | seq->setMode(osg::Sequence::START); |
| | 70 | |
| | 71 | return group; |
| | 72 | } |
| | 73 | |
| | 74 | osg::Node* createHUD(osg::Node* node) |
| | 75 | { |
| | 76 | // absolute transform |
| | 77 | osg::MatrixTransform* modelview_abs = new osg::MatrixTransform; |
| | 78 | modelview_abs->setReferenceFrame(osg::Transform::ABSOLUTE_RF); |
| | 79 | modelview_abs->setMatrix(osg::Matrix::identity()); |
| | 80 | modelview_abs->addChild(node); |
| | 81 | |
| | 82 | // 2D projection node |
| | 83 | osg::Projection* projection = new osg::Projection; |
| | 84 | projection->setMatrix(osg::Matrix::ortho2D(0,1280,0,1024)); |
| | 85 | projection->addChild(modelview_abs); |
| | 86 | |
| | 87 | // turn off lighting and depth test |
| | 88 | osg::StateSet* state = modelview_abs->getOrCreateStateSet(); |
| | 89 | state->setMode(GL_LIGHTING, osg::StateAttribute::OFF); |
| | 90 | state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF); |
| | 91 | |
| | 92 | return projection; |
| | 93 | } |
| | 94 | |
| | 95 | osg::Node* createScaledNode(osg::Node* node, float targetScale) |
| | 96 | { |
| | 97 | // create scale matrix |
| | 98 | osg::MatrixTransform* transform = new osg::MatrixTransform; |
| | 99 | |
| | 100 | const osg::BoundingSphere& bsphere = node->getBound(); |
| | 101 | float scale = targetScale / bsphere._radius; |
| | 102 | transform->setMatrix(osg::Matrix::scale(scale,scale,scale)); |
| | 103 | transform->setDataVariance(osg::Object::STATIC); |
| | 104 | transform->addChild(node); |
| | 105 | |
| | 106 | // rescale normals |
| | 107 | osg::StateSet* state = transform->getOrCreateStateSet(); |
| | 108 | state->setMode(GL_NORMALIZE, osg::StateAttribute::ON); |
| | 109 | |
| | 110 | return transform; |
| | 111 | } |
| | 112 | |
| | 113 | osg::Sequence* createSequence(osg::ArgumentParser& arguments) |
| | 114 | { |
| | 115 | // assumes any remaining parameters are models |
| | 116 | osg::Sequence* seq = new osg::Sequence; |
| | 117 | for (int i = 1; i < arguments.argc(); ++i) |
| | 118 | { |
| | 119 | // load model |
| | 120 | osg::Node* node = osgDB::readNodeFile(arguments[i]); |
| | 121 | if (!node) { |
| | 122 | continue; |
| | 123 | } |
| | 124 | seq->addChild(createScaledNode(node, 100.0f)); |
| | 125 | seq->setTime(seq->getNumChildren()-1, 1.0f); |
| | 126 | } |
| | 127 | |
| | 128 | // loop through all children |
| | 129 | seq->setInterval(osg::Sequence::LOOP, 0,-1); |
| | 130 | |
| | 131 | // real-time playback, repeat indefinitively |
| | 132 | seq->setDuration(1.0f, -1); |
| | 133 | |
| | 134 | return seq; |
| | 135 | } |
| | 136 | |
| | 137 | // event handler to control sequence |
| | 138 | class SequenceEventHandler : public osgGA::GUIEventHandler |
| | 139 | { |
| 37 | | // toggle sequence |
| 38 | | osg::Sequence* seq = (*_seq)[i]; |
| 39 | | osg::Sequence::SequenceMode mode = seq->getMode(); |
| 40 | | switch (mode) { |
| 41 | | case osg::Sequence::START: |
| 42 | | seq->setMode(osg::Sequence::PAUSE); |
| 43 | | break; |
| 44 | | case osg::Sequence::STOP: |
| 45 | | seq->setMode(osg::Sequence::START); |
| 46 | | break; |
| 47 | | case osg::Sequence::PAUSE: |
| 48 | | seq->setMode(osg::Sequence::RESUME); |
| 49 | | break; |
| 50 | | default: |
| 51 | | break; |
| 52 | | } |
| 53 | | std::cerr << "Toggled sequence " << i << std::endl; |
| 54 | | handled = true; |
| | 154 | osg::Sequence::SequenceMode mode = _seq->getMode(); |
| | 155 | if (mode == osg::Sequence::STOP) { |
| | 156 | mode = osg::Sequence::START; |
| | 157 | std::cerr << "Start" << std::endl; |
| | 158 | } |
| | 159 | else if (mode == osg::Sequence::PAUSE) { |
| | 160 | mode = osg::Sequence::RESUME; |
| | 161 | std::cerr << "Resume" << std::endl; |
| | 162 | } |
| | 163 | else { |
| | 164 | mode = osg::Sequence::PAUSE; |
| | 165 | std::cerr << "Pause" << std::endl; |
| | 166 | } |
| | 167 | _seq->setMode(mode); |
| 151 | | // create sequences |
| 152 | | std::vector<osg::Sequence*> seq; |
| 153 | | |
| 154 | | const osg::Sequence::LoopMode mode[] = { osg::Sequence::LOOP, |
| 155 | | osg::Sequence::SWING, |
| 156 | | osg::Sequence::LOOP }; |
| 157 | | const float speed[] = { 0.5f, 1.0f, 1.5f }; |
| 158 | | const int nreps[] = { -1, 5, 1 }; |
| 159 | | |
| 160 | | float x = 0.0f; |
| 161 | | for (unsigned int j = 0; j < (sizeof(speed) / sizeof(speed[0])); j++) { |
| 162 | | osg::Sequence* seqNode = generateSeq(mode[j], speed[j], nreps[j], |
| 163 | | model); |
| 164 | | if (!seqNode) |
| 165 | | continue; |
| 166 | | seq.push_back(seqNode); |
| 167 | | |
| 168 | | // position sequence |
| 169 | | osg::Matrix matrix; |
| 170 | | matrix.makeTranslate(x, 0.0, 0.0); |
| 171 | | |
| 172 | | osg::MatrixTransform* xform = new osg::MatrixTransform; |
| 173 | | xform->setMatrix(matrix); |
| 174 | | xform->addChild(seqNode); |
| 175 | | |
| 176 | | rootNode->addChild(xform); |
| 177 | | |
| 178 | | x += seqNode->getBound()._radius * 1.5f; |
| 179 | | } |
| 180 | | |
| | 247 | // create info display |
| | 248 | const char* text[] = { |
| | 249 | "osg::Sequence Mini-Howto", |
| | 250 | "- can be used for simple flip-book-style animation", |
| | 251 | "- is subclassed from osg::Switch", |
| | 252 | "- assigns a display duration to each child", |
| | 253 | "- can loop or swing through an interval of it's children", |
| | 254 | "- can repeat the interval a number of times or indefinitively", |
| | 255 | "- press 'Shift-S' to start/pause/resume", |
| | 256 | "- press 'Shift-L' to toggle loop/swing mode", |
| | 257 | NULL |
| | 258 | }; |
| | 259 | rootNode->addChild(createHUD(createTextGroup(text))); |
| | 260 | |
| | 261 | // add sequence of models from command line |
| | 262 | osg::Sequence* seq = createSequence(arguments); |
| | 263 | rootNode->addChild(seq); |