From Ulrich Hertlien, improved osgsequence example
This commit is contained in:
@@ -1,6 +1,19 @@
|
||||
// -*-c++-*-
|
||||
|
||||
/*
|
||||
* This application is open source and may be redistributed and/or modified
|
||||
* freely and without restriction, both in commericial and non commericial
|
||||
* applications,as long as this copyright notice is maintained.
|
||||
*
|
||||
* This application is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*/
|
||||
|
||||
#include <osgText/Text>
|
||||
#include <osg/Geode>
|
||||
#include <osg/Group>
|
||||
#include <osg/Projection>
|
||||
#include <osg/Sequence>
|
||||
#include <osg/MatrixTransform>
|
||||
|
||||
@@ -9,86 +22,182 @@
|
||||
#include <osgProducer/Viewer>
|
||||
|
||||
|
||||
//
|
||||
// A simple demo demonstrating usage of osg::Sequence.
|
||||
//
|
||||
// create text drawable at 'pos'
|
||||
osg::Geode* createText(const std::string& str, const osg::Vec3& pos)
|
||||
{
|
||||
// text drawable
|
||||
osgText::Text* text = new osgText::Text;
|
||||
text->setFont(std::string("fonts/arial.ttf"));
|
||||
text->setPosition(pos);
|
||||
text->setText(str);
|
||||
|
||||
// simple event handler to start/stop sequences
|
||||
class MyEventHandler : public osgGA::GUIEventHandler {
|
||||
// geode
|
||||
osg::Geode* geode = new osg::Geode;
|
||||
geode->addDrawable(text);
|
||||
|
||||
return geode;
|
||||
}
|
||||
|
||||
osg::Node* createTextGroup(const char** text)
|
||||
{
|
||||
osg::Group* group = new osg::Group;
|
||||
|
||||
osg::Vec3 pos(120.0f, 800.0f, 0.0f);
|
||||
const osg::Vec3 delta(0.0f, -60.0f, 0.0f);
|
||||
|
||||
// header
|
||||
const char** t = text;
|
||||
group->addChild(createText(*t++, pos));
|
||||
pos += delta;
|
||||
|
||||
// remainder of text under sequence
|
||||
osg::Sequence* seq = new osg::Sequence;
|
||||
group->addChild(seq);
|
||||
while (*t) {
|
||||
seq->addChild(createText(*t++, pos));
|
||||
seq->setTime(seq->getNumChildren()-1, 2.0f);
|
||||
pos += delta;
|
||||
}
|
||||
|
||||
// loop through all children
|
||||
seq->setInterval(osg::Sequence::LOOP, 0,-1);
|
||||
|
||||
// real-time playback, repeat indefinitively
|
||||
seq->setDuration(1.0f, -1);
|
||||
|
||||
// must be started explicitly
|
||||
seq->setMode(osg::Sequence::START);
|
||||
|
||||
return group;
|
||||
}
|
||||
|
||||
osg::Node* createHUD(osg::Node* node)
|
||||
{
|
||||
// absolute transform
|
||||
osg::MatrixTransform* modelview_abs = new osg::MatrixTransform;
|
||||
modelview_abs->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
|
||||
modelview_abs->setMatrix(osg::Matrix::identity());
|
||||
modelview_abs->addChild(node);
|
||||
|
||||
// 2D projection node
|
||||
osg::Projection* projection = new osg::Projection;
|
||||
projection->setMatrix(osg::Matrix::ortho2D(0,1280,0,1024));
|
||||
projection->addChild(modelview_abs);
|
||||
|
||||
// turn off lighting and depth test
|
||||
osg::StateSet* state = modelview_abs->getOrCreateStateSet();
|
||||
state->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
|
||||
state->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
||||
|
||||
return projection;
|
||||
}
|
||||
|
||||
osg::Node* createScaledNode(osg::Node* node, float targetScale)
|
||||
{
|
||||
// create scale matrix
|
||||
osg::MatrixTransform* transform = new osg::MatrixTransform;
|
||||
|
||||
const osg::BoundingSphere& bsphere = node->getBound();
|
||||
float scale = targetScale / bsphere._radius;
|
||||
transform->setMatrix(osg::Matrix::scale(scale,scale,scale));
|
||||
transform->setDataVariance(osg::Object::STATIC);
|
||||
transform->addChild(node);
|
||||
|
||||
// rescale normals
|
||||
osg::StateSet* state = transform->getOrCreateStateSet();
|
||||
state->setMode(GL_NORMALIZE, osg::StateAttribute::ON);
|
||||
|
||||
return transform;
|
||||
}
|
||||
|
||||
osg::Sequence* createSequence(osg::ArgumentParser& arguments)
|
||||
{
|
||||
// assumes any remaining parameters are models
|
||||
osg::Sequence* seq = new osg::Sequence;
|
||||
for (int i = 1; i < arguments.argc(); ++i)
|
||||
{
|
||||
// load model
|
||||
osg::Node* node = osgDB::readNodeFile(arguments[i]);
|
||||
if (!node) {
|
||||
continue;
|
||||
}
|
||||
seq->addChild(createScaledNode(node, 100.0f));
|
||||
seq->setTime(seq->getNumChildren()-1, 1.0f);
|
||||
}
|
||||
|
||||
// loop through all children
|
||||
seq->setInterval(osg::Sequence::LOOP, 0,-1);
|
||||
|
||||
// real-time playback, repeat indefinitively
|
||||
seq->setDuration(1.0f, -1);
|
||||
|
||||
return seq;
|
||||
}
|
||||
|
||||
// event handler to control sequence
|
||||
class SequenceEventHandler : public osgGA::GUIEventHandler
|
||||
{
|
||||
public:
|
||||
/// Constructor.
|
||||
MyEventHandler(std::vector<osg::Sequence*>* seq)
|
||||
SequenceEventHandler(osg::Sequence* seq)
|
||||
{
|
||||
_seq = seq;
|
||||
}
|
||||
|
||||
/// Handle events.
|
||||
// handle keydown events
|
||||
virtual bool handle(const osgGA::GUIEventAdapter& ea,
|
||||
osgGA::GUIActionAdapter&)
|
||||
{
|
||||
bool handled = false;
|
||||
|
||||
if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN)
|
||||
{
|
||||
const char keys[] = "!@#$%^&*()";
|
||||
for (unsigned int i = 0; i < (sizeof(keys) / sizeof(keys[0])); i++) {
|
||||
if (i < _seq->size() && ea.getKey() == keys[i])
|
||||
if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) {
|
||||
switch (ea.getKey()) {
|
||||
case 'S':
|
||||
{
|
||||
// toggle sequence
|
||||
osg::Sequence* seq = (*_seq)[i];
|
||||
osg::Sequence::SequenceMode mode = seq->getMode();
|
||||
switch (mode) {
|
||||
case osg::Sequence::START:
|
||||
seq->setMode(osg::Sequence::PAUSE);
|
||||
break;
|
||||
case osg::Sequence::STOP:
|
||||
seq->setMode(osg::Sequence::START);
|
||||
break;
|
||||
case osg::Sequence::PAUSE:
|
||||
seq->setMode(osg::Sequence::RESUME);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
osg::Sequence::SequenceMode mode = _seq->getMode();
|
||||
if (mode == osg::Sequence::STOP) {
|
||||
mode = osg::Sequence::START;
|
||||
std::cerr << "Start" << std::endl;
|
||||
}
|
||||
std::cerr << "Toggled sequence " << i << std::endl;
|
||||
handled = true;
|
||||
else if (mode == osg::Sequence::PAUSE) {
|
||||
mode = osg::Sequence::RESUME;
|
||||
std::cerr << "Resume" << std::endl;
|
||||
}
|
||||
else {
|
||||
mode = osg::Sequence::PAUSE;
|
||||
std::cerr << "Pause" << std::endl;
|
||||
}
|
||||
_seq->setMode(mode);
|
||||
}
|
||||
break;
|
||||
case 'L':
|
||||
{
|
||||
osg::Sequence::LoopMode mode;
|
||||
int begin, end;
|
||||
_seq->getInterval(mode, begin, end);
|
||||
if (mode == osg::Sequence::LOOP) {
|
||||
mode = osg::Sequence::SWING;
|
||||
std::cerr << "Swing" << std::endl;
|
||||
}
|
||||
else {
|
||||
mode = osg::Sequence::LOOP;
|
||||
std::cerr << "Loop" << std::endl;
|
||||
}
|
||||
_seq->setInterval(mode, begin, end);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// accept visits.
|
||||
// accept visits
|
||||
virtual void accept(osgGA::GUIEventHandlerVisitor&) {}
|
||||
|
||||
private:
|
||||
std::vector<osg::Sequence*>* _seq;
|
||||
osg::ref_ptr<osg::Sequence> _seq;
|
||||
};
|
||||
|
||||
osg::Sequence* generateSeq(osg::Sequence::LoopMode mode,
|
||||
float speed, int nreps,
|
||||
std::vector<osg::Node*>& model)
|
||||
{
|
||||
osg::Sequence* seqNode = new osg::Sequence;
|
||||
|
||||
// add children, show each child for 1.0 seconds
|
||||
for (unsigned int i = 0; i < model.size(); i++) {
|
||||
seqNode->addChild(model[i]);
|
||||
seqNode->setTime(i, 1.0f);
|
||||
}
|
||||
|
||||
// interval
|
||||
seqNode->setInterval(mode, 0, -1);
|
||||
|
||||
// speed-up factor and number of repeats for entire sequence
|
||||
seqNode->setDuration(speed, nreps);
|
||||
|
||||
// stopped
|
||||
seqNode->setMode(osg::Sequence::STOP);
|
||||
|
||||
return seqNode;
|
||||
}
|
||||
|
||||
int main( int argc, char **argv )
|
||||
{
|
||||
@@ -132,58 +241,32 @@ int main( int argc, char **argv )
|
||||
return 1;
|
||||
}
|
||||
|
||||
// assumes any remaining parameters are models
|
||||
std::vector<osg::Node*> model;
|
||||
for (int i = 1; i < arguments.argc(); i++)
|
||||
{
|
||||
std::cerr << "Loading " << arguments[i] << std::endl;
|
||||
osg::Node* node = osgDB::readNodeFile(arguments[i]);
|
||||
if (node)
|
||||
model.push_back(node);
|
||||
}
|
||||
if (model.empty()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// root
|
||||
osg::Group* rootNode = new osg::Group;
|
||||
|
||||
// create sequences
|
||||
std::vector<osg::Sequence*> seq;
|
||||
|
||||
const osg::Sequence::LoopMode mode[] = { osg::Sequence::LOOP,
|
||||
osg::Sequence::SWING,
|
||||
osg::Sequence::LOOP };
|
||||
const float speed[] = { 0.5f, 1.0f, 1.5f };
|
||||
const int nreps[] = { -1, 5, 1 };
|
||||
|
||||
float x = 0.0f;
|
||||
for (unsigned int j = 0; j < (sizeof(speed) / sizeof(speed[0])); j++) {
|
||||
osg::Sequence* seqNode = generateSeq(mode[j], speed[j], nreps[j],
|
||||
model);
|
||||
if (!seqNode)
|
||||
continue;
|
||||
seq.push_back(seqNode);
|
||||
|
||||
// position sequence
|
||||
osg::Matrix matrix;
|
||||
matrix.makeTranslate(x, 0.0, 0.0);
|
||||
|
||||
osg::MatrixTransform* xform = new osg::MatrixTransform;
|
||||
xform->setMatrix(matrix);
|
||||
xform->addChild(seqNode);
|
||||
|
||||
rootNode->addChild(xform);
|
||||
|
||||
x += seqNode->getBound()._radius * 1.5f;
|
||||
}
|
||||
// create info display
|
||||
const char* text[] = {
|
||||
"osg::Sequence Mini-Howto",
|
||||
"- can be used for simple flip-book-style animation",
|
||||
"- is subclassed from osg::Switch",
|
||||
"- assigns a display duration to each child",
|
||||
"- can loop or swing through an interval of it's children",
|
||||
"- can repeat the interval a number of times or indefinitively",
|
||||
"- press 'Shift-S' to start/pause/resume",
|
||||
"- press 'Shift-L' to toggle loop/swing mode",
|
||||
NULL
|
||||
};
|
||||
rootNode->addChild(createHUD(createTextGroup(text)));
|
||||
|
||||
// add sequence of models from command line
|
||||
osg::Sequence* seq = createSequence(arguments);
|
||||
rootNode->addChild(seq);
|
||||
|
||||
// add model to viewer.
|
||||
viewer.setSceneData(rootNode);
|
||||
|
||||
// register additional event handler
|
||||
viewer.getEventHandlerList().push_front(new MyEventHandler(&seq));
|
||||
// add event handler to control sequence
|
||||
viewer.getEventHandlerList().push_front(new SequenceEventHandler(seq));
|
||||
|
||||
// create the windows and run the threads.
|
||||
viewer.realize();
|
||||
|
||||
Reference in New Issue
Block a user