root/OpenSceneGraph/trunk/examples/osgfxbrowser/osgfxbrowser.cpp @ 5122

Revision 5122, 13.4 kB (checked in by robert, 9 years ago)

Reorganised the Group::removeChild and Geode::removeDrawable methods so
that removeChild(Node*), removeChild(uint) and equivilant Geode methods are
now inline methods, not designed to be overriden, and seperated out the
multiple remove method to be called removeChildren(uint, uint) which is
now the only virtual method. There removeChildren is now the method to
override in subclasses.

This reorganisation requires some call code to be rename removeChild usage
to removeChildren.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1#include <osg/Group>
2#include <osg/Geometry>
3#include <osg/Geode>
4#include <osg/Projection>
5#include <osg/MatrixTransform>
6#include <osg/BlendFunc>
7#include <osg/LightSource>
8
9#include <osgProducer/Viewer>
10
11#include <osgDB/ReadFile>
12#include <osgDB/WriteFile>
13
14#include <osgText/Text>
15
16#include <osgUtil/Optimizer>
17
18#include <osgGA/GUIEventAdapter>
19#include <osgGA/GUIActionAdapter>
20
21#include <osgFX/Registry>
22#include <osgFX/Effect>
23
24#include "Frame.h"
25
26#include <vector>
27#include <string>
28
29class RotateCallback: public osg::NodeCallback {
30public:
31    RotateCallback(): osg::NodeCallback(), enabled_(true) {}
32    void operator()(osg::Node* node, osg::NodeVisitor *nv)
33    {
34        osg::MatrixTransform *xform = dynamic_cast<osg::MatrixTransform *>(node);
35        if (xform && enabled_) {
36            double t = nv->getFrameStamp()->getReferenceTime();
37            xform->setMatrix(osg::Matrix::rotate(t, osg::Vec3(0, 0, 1)));
38        }
39        traverse(node, nv);
40    }
41
42    bool enabled_;
43};
44
45
46// yes, I know global variables are not good things in C++
47// but in this case it is useful... :-P
48RotateCallback *rotate_cb;
49
50
51class EffectPanel: public osgfxbrowser::Frame {
52public:
53
54    class KeyboardHandler: public osgGA::GUIEventHandler {
55    public:
56        KeyboardHandler(EffectPanel* ep): ep_(ep) {}
57
58        bool handle(const osgGA::GUIEventAdapter &ea, osgGA::GUIActionAdapter &)
59        {
60            if (ea.getEventType() == osgGA::GUIEventAdapter::KEYDOWN) {
61                if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Right) {
62                    ep_->setEffectIndex(ep_->getEffectIndex()+1);
63                    return true;
64                }
65                if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Left) {
66                    ep_->setEffectIndex(ep_->getEffectIndex()-1);
67                    return true;
68                }
69                if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Return) {
70                    ep_->setNodeMask(0xffffffff - ep_->getNodeMask());
71                    return true;
72                }
73                if (ea.getKey() == osgGA::GUIEventAdapter::KEY_Delete) {
74                    ep_->setEffectsEnabled(!ep_->getEffectsEnabled());
75                    return true;
76                }
77                if (ea.getKey() == 'x') {
78                    osgDB::writeNodeFile(*ep_->getRoot(), "osgfx_model.osg");
79                    std::cout << "written nodes to \"osgfx_model.osg\"\n";
80                    return true;
81                }
82                if (ea.getKey() == 'r') {
83                    rotate_cb->enabled_ = !rotate_cb->enabled_;
84                    return true;
85                }
86            }
87
88            return false;
89        }
90
91    private:
92        osg::ref_ptr<EffectPanel> ep_;
93    };
94
95    EffectPanel()
96    :    osgfxbrowser::Frame(),
97        _selected_fx(-1),
98        _fxen(true),
99        _root(new osg::Group),
100        _hints_color(0.75f, 0.75f, 0.75f, 1.0f),
101        _name_color(1, 1, 1, 1),
102        _desc_color(1, 1, 0.7f, 1)
103    {
104        setBackgroundColor(osg::Vec4(0.3f, 0.1f, 0.15f, 0.75f));
105
106        std::cout << "INFO: available osgFX effects:\n";
107        osgFX::Registry::EffectMap emap = osgFX::Registry::instance()->getEffectMap();
108        for (osgFX::Registry::EffectMap::const_iterator i=emap.begin(); i!=emap.end(); ++i) {
109            std::cout << "INFO: \t" << i->first << "\n";
110            osg::ref_ptr<osgFX::Effect> effect = static_cast<osgFX::Effect *>(i->second->cloneType());
111            _effects.push_back(effect.get());           
112        }
113
114        std::cout << "INFO: " << emap.size() << " effect(s) ready.\n";
115
116        if (!_effects.empty()) {
117            _selected_fx = 0;
118        }
119    }
120
121    inline osg::Group* getRoot() { return _root.get(); }
122    inline void setRoot(osg::Group* node) { _root = node; }
123
124    inline osg::Node* getScene() { return _scene.get(); }
125    inline void setScene(osg::Node* node) { _scene = node; }
126
127    inline bool getEffectsEnabled() const { return _fxen; }
128    inline void setEffectsEnabled(bool v)
129    {
130        _fxen = v;
131        if (getSelectedEffect()) {
132            getSelectedEffect()->setEnabled(_fxen);
133        }
134    }
135
136    inline int getEffectIndex() const { return _selected_fx; }
137    inline void setEffectIndex(int i)
138    {
139        if (i >= static_cast<int>(_effects.size())) i = 0;
140        if (i < 0) i = static_cast<int>(_effects.size()-1);       
141        _selected_fx = i;
142        rebuild();
143    }
144
145    inline osgFX::Effect *getSelectedEffect()
146    {
147        if (_selected_fx >= 0 && _selected_fx < static_cast<int>(_effects.size())) {
148            return _effects[_selected_fx].get();
149        }
150        return 0;
151    }
152
153protected:
154    void rebuild_client_area(const osgfxbrowser::Rect &client_rect)
155    {
156                float zPos = -0.1; // note from Robert, was 0.1f, but now must be -0.1f to keep text visible??#!? due
157                                   // to some other change in the OSG not tracked down yet...
158       
159        osg::ref_ptr<osgText::Font> arial = osgText::readFontFile("fonts/arial.ttf");
160
161        osg::ref_ptr<osgText::Text> hints = new osgText::Text;
162        hints->setFont(arial.get());
163        hints->setColor(_hints_color);
164        hints->setAlignment(osgText::Text::CENTER_BOTTOM);
165        hints->setCharacterSize(13);
166        hints->setFontResolution(13, 13);
167        hints->setPosition(osg::Vec3((client_rect.x0+client_rect.x1)/2, client_rect.y0 + 4, zPos));
168        hints->setText("<RETURN> show/hide this panel      <LEFT> previous effect      <RIGHT> next effect      <DEL> enable/disable effects      'x' save to file      'r' rotate/stop");
169        addDrawable(hints.get());
170
171        std::string effect_name = "No Effect Selected";
172        std::string effect_description = "";
173
174        if (_selected_fx >= 0 && _selected_fx < static_cast<int>(_effects.size())) {
175            effect_name = _effects[_selected_fx]->effectName();
176            std::string author_name = _effects[_selected_fx]->effectAuthor();
177            if (!author_name.empty()) {
178                effect_description = author_name = "AUTHOR: " + std::string(_effects[_selected_fx]->effectAuthor()) + std::string("\n\n");
179            }
180            effect_description += "DESCRIPTION:\n" + std::string(_effects[_selected_fx]->effectDescription());           
181
182            if (_scene.valid() && _root.valid()) {
183                _root->removeChildren(0, _root->getNumChildren());
184                osg::ref_ptr<osgFX::Effect> effect = _effects[_selected_fx].get();
185                effect->setEnabled(_fxen);
186                effect->removeChildren(0, effect->getNumChildren());
187                effect->addChild(_scene.get());
188                effect->setUpDemo();
189                _root->addChild(effect.get());
190            }
191        }
192
193        osg::ref_ptr<osgText::Text> ename = new osgText::Text;
194        ename->setFont(arial.get());
195        ename->setColor(_name_color);
196        ename->setAlignment(osgText::Text::CENTER_TOP);
197        ename->setCharacterSize(32);
198        ename->setFontResolution(32, 32);
199        ename->setPosition(osg::Vec3((client_rect.x0 + client_rect.x1) / 2, client_rect.y1 - 22, zPos));
200        ename->setText(effect_name);
201        addDrawable(ename.get());
202
203        osg::ref_ptr<osgText::Text> edesc = new osgText::Text;
204        edesc->setMaximumWidth(client_rect.width() - 16);
205        edesc->setFont(arial.get());
206        edesc->setColor(_desc_color);
207        edesc->setAlignment(osgText::Text::LEFT_TOP);
208        edesc->setCharacterSize(16);
209        edesc->setFontResolution(16, 16);
210        edesc->setPosition(osg::Vec3(client_rect.x0 + 8, client_rect.y1 - 60, zPos));
211        edesc->setText(effect_description);
212        addDrawable(edesc.get());
213    }
214
215private:
216    int _selected_fx;
217    typedef std::vector<osg::ref_ptr<osgFX::Effect> > Effect_list;
218    Effect_list _effects;
219    bool _fxen;
220    osg::ref_ptr<osg::Group> _root;
221    osg::ref_ptr<osg::Node> _scene;
222    osg::Vec4 _hints_color;
223    osg::Vec4 _name_color;
224    osg::Vec4 _desc_color;
225};
226
227
228osg::Group* build_hud_base(osg::Group* root)
229{
230    osg::ref_ptr<osg::Projection> proj = new osg::Projection(osg::Matrix::ortho2D(0, 1024, 0, 768));
231    proj->setCullingActive(false);
232    root->addChild(proj.get());
233
234    osg::ref_ptr<osg::MatrixTransform> xform = new osg::MatrixTransform(osg::Matrix::identity());
235    xform->setReferenceFrame(osg::Transform::ABSOLUTE_RF);
236    proj->addChild(xform.get());
237
238    osg::StateSet *ss = xform->getOrCreateStateSet();
239    ss->setRenderBinDetails(100, "RenderBin");
240    ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
241    ss->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
242
243    osg::ref_ptr<osg::BlendFunc> bf = new osg::BlendFunc;
244    ss->setAttributeAndModes(bf.get());
245
246    return xform.take();
247}
248
249EffectPanel* build_gui(osg::Group* root)
250{
251    osg::ref_ptr<osg::Group> hud = build_hud_base(root);
252
253    osg::ref_ptr<EffectPanel> effect_panel = new EffectPanel;
254    effect_panel->setCaption("osgFX Effect Browser");
255    effect_panel->setRect(osgfxbrowser::Rect(20, 20, 1000, 280));   
256
257    hud->addChild(effect_panel.get());
258
259    return effect_panel.take();
260}
261
262void build_world(osg::Group* root, osg::Node* scene, osgProducer::Viewer& viewer)
263{
264    osg::ref_ptr<EffectPanel> effect_panel = build_gui(root);
265    effect_panel->setScene(scene);
266    effect_panel->rebuild();
267
268    viewer.getEventHandlerList().push_front(new EffectPanel::KeyboardHandler(effect_panel.get()));
269
270    root->addChild(effect_panel->getRoot());
271}
272
273int main(int argc, char *argv[])
274{
275    // use an ArgumentParser object to manage the program arguments.
276    osg::ArgumentParser arguments(&argc, argv);
277
278    // set up the usage document, in case we need to print out how to use this program.
279    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
280    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is a simple browser that allows you to apply osgFX effects to models interactively.");
281    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName() + " [options] filename ...");
282    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information");
283    arguments.getApplicationUsage()->addKeyboardMouseBinding("Left", "Apply previous effect");
284    arguments.getApplicationUsage()->addKeyboardMouseBinding("Right", "Apply next effect");
285    arguments.getApplicationUsage()->addKeyboardMouseBinding("Del", "Enable or disable osgFX");
286    arguments.getApplicationUsage()->addKeyboardMouseBinding("Return", "Show or hide the effect information panel");
287    arguments.getApplicationUsage()->addKeyboardMouseBinding("x", "Save the scene graph with current effect applied");
288
289
290    // construct the viewer.
291    osgProducer::Viewer viewer(arguments);
292
293    // set up the value with sensible default event handlers.
294    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
295
296    // get details on keyboard and mouse bindings used by the viewer.
297    viewer.getUsage(*arguments.getApplicationUsage());
298
299    // if user request help write it out to cout.
300    if (arguments.read("-h") || arguments.read("--help")) {
301        arguments.getApplicationUsage()->write(std::cout);
302        return 1;
303    }
304
305    // any option left unread are converted into errors to write out later.
306    arguments.reportRemainingOptionsAsUnrecognized();
307
308    // report any errors if they have occured when parsing the program aguments.
309    if (arguments.errors()) {
310        arguments.writeErrorMessages(std::cout);
311        return 1;
312    }
313
314    if (arguments.argc() <= 1) {
315        arguments.getApplicationUsage()->write(std::cout, osg::ApplicationUsage::COMMAND_LINE_OPTION);
316        return 1;
317    }
318
319    osg::Timer timer;
320    osg::Timer_t start_tick = timer.tick();
321
322    // read the scene from the list of file specified commandline args.
323    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
324
325    // if no model has been successfully loaded report failure.
326    if (!loadedModel) {
327        std::cout << arguments.getApplicationName() << ": No data loaded" << std::endl;
328        return 1;
329    }
330
331    osg::Timer_t end_tick = timer.tick();
332
333    std::cout << "Time to load = " << timer.delta_s(start_tick,end_tick) << std::endl;
334
335    // optimize the scene graph, remove rendundent nodes and state etc.
336    osgUtil::Optimizer optimizer;
337    optimizer.optimize(loadedModel.get());
338
339    // set up a transform to rotate the model
340    osg::ref_ptr<osg::MatrixTransform> xform = new osg::MatrixTransform;
341    rotate_cb = new RotateCallback;
342    xform->setUpdateCallback(rotate_cb);
343    xform->addChild(loadedModel.get());
344
345    osg::ref_ptr<osg::Light> light = new osg::Light;
346    light->setLightNum(0);
347    light->setDiffuse(osg::Vec4(1, 1, 1, 1));
348    light->setSpecular(osg::Vec4(1, 1, 0.8f, 1));
349    light->setAmbient(osg::Vec4(0.2f, 0.2f, 0.2f, 0.2f));
350    light->setPosition(osg::Vec4(1, -1, 1, 0));
351
352    osg::ref_ptr<osg::LightSource> root = new osg::LightSource;
353    root->setLight(light.get());
354    root->setLocalStateSetModes();
355
356    build_world(root.get(), xform.get(), viewer);
357
358    // set the scene to render
359    viewer.setSceneData(root.get());
360
361    // create the windows and run the threads.
362    viewer.realize();
363
364    while(!viewer.done())
365    {
366        // wait for all cull and draw threads to complete.
367        viewer.sync();
368
369        // update the scene by traversing it with the the update visitor which will
370        // call all node update callbacks and animations.
371        viewer.update();
372
373        // fire off the cull and draw traversals of the scene.
374        viewer.frame();
375
376    }
377
378    // wait for all cull and draw threads to complete before exit.
379    viewer.sync();
380
381    return 0;
382}
Note: See TracBrowser for help on using the browser.