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

Revision 2244, 11.9 kB (checked in by robert, 11 years ago)

Updates to osgFX, from Marco Jez, to map Effect across to being derived
from osg::Group rather than from osg::Node.

  • 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 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        :       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::Effect_map emap = osgFX::Registry::instance()->getEffectMap();
108                for (osgFX::Registry::Effect_map::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 Rect &client_rect)
155        {
156                osg::ref_ptr<osgText::Font> arial = osgText::readFontFile("fonts/arial.ttf");
157
158                osg::ref_ptr<osgText::Text> hints = new osgText::Text;
159                hints->setFont(arial.get());
160                hints->setColor(hints_color_);
161                hints->setAlignment(osgText::Text::CENTER_BOTTOM);
162                hints->setCharacterSize(13);
163                hints->setFontResolution(13, 13);
164                hints->setPosition(osg::Vec3((client_rect.x0+client_rect.x1)/2, client_rect.y0 + 4, 0.1f));
165                hints->setText("<RETURN> show/hide this panel      <LEFT> previous effect      <RIGHT> next effect      <DEL> enable/disable effects      'x' save to file      'r' rotate/stop");
166                addDrawable(hints.get());
167
168                std::string effect_name = "No Effect Selected";
169                std::string effect_description = "";
170
171                if (selected_fx_ >= 0 && selected_fx_ < static_cast<int>(effects_.size())) {
172                        effect_name = effects_[selected_fx_]->effectName();
173                        std::string author_name = effects_[selected_fx_]->effectAuthor();
174                        if (!author_name.empty()) {
175                                effect_description = author_name = "AUTHOR: " + std::string(effects_[selected_fx_]->effectAuthor()) + std::string("\n\n");
176                        }
177                        effect_description += "DESCRIPTION:\n" + std::string(effects_[selected_fx_]->effectDescription());                     
178
179                        if (scene_.valid() && root_.valid()) {
180                                root_->removeChild(0, root_->getNumChildren());
181                                osg::ref_ptr<osgFX::Effect> effect = effects_[selected_fx_].get();
182                                effect->setEnabled(fxen_);
183                                effect->removeChild(0, effect->getNumChildren());
184                                effect->addChild(scene_.get());
185                                effect->setUpDemo();
186                                root_->addChild(effect.get());
187                        }
188                }
189
190                osg::ref_ptr<osgText::Text> ename = new osgText::Text;
191                ename->setFont(arial.get());
192                ename->setColor(name_color_);
193                ename->setAlignment(osgText::Text::CENTER_TOP);
194                ename->setCharacterSize(32);
195                ename->setFontResolution(32, 32);
196                ename->setPosition(osg::Vec3((client_rect.x0 + client_rect.x1) / 2, client_rect.y1 - 22, 0.1f));
197                ename->setText(effect_name);
198                addDrawable(ename.get());
199
200                osg::ref_ptr<osgText::Text> edesc = new osgText::Text;
201                edesc->setMaximumWidth(client_rect.width() - 16);
202                edesc->setFont(arial.get());
203                edesc->setColor(desc_color_);
204                edesc->setAlignment(osgText::Text::LEFT_TOP);
205                edesc->setCharacterSize(16);
206                edesc->setFontResolution(16, 16);
207                edesc->setPosition(osg::Vec3(client_rect.x0 + 8, client_rect.y1 - 60, 0.1f));
208                edesc->setText(effect_description);
209                addDrawable(edesc.get());
210        }
211
212private:
213        int selected_fx_;
214        typedef std::vector<osg::ref_ptr<osgFX::Effect> > Effect_list;
215        Effect_list effects_;
216        bool fxen_;
217        osg::ref_ptr<osg::Group> root_;
218        osg::ref_ptr<osg::Node> scene_;
219        osg::Vec4 hints_color_;
220        osg::Vec4 name_color_;
221        osg::Vec4 desc_color_;
222};
223
224
225osg::Group *build_hud_base(osg::Group *root)
226{
227        osg::ref_ptr<osg::Projection> proj = new osg::Projection(osg::Matrix::ortho2D(0, 1024, 0, 768));
228        proj->setCullingActive(false);
229        root->addChild(proj.get());
230
231        osg::ref_ptr<osg::MatrixTransform> xform = new osg::MatrixTransform(osg::Matrix::identity());
232        xform->setReferenceFrame(osg::Transform::RELATIVE_TO_ABSOLUTE);
233        proj->addChild(xform.get());
234
235        osg::StateSet *ss = xform->getOrCreateStateSet();
236        ss->setRenderBinDetails(100, "RenderBin");
237        ss->setMode(GL_LIGHTING, osg::StateAttribute::OFF);
238        ss->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
239
240        osg::ref_ptr<osg::BlendFunc> bf = new osg::BlendFunc;
241        ss->setAttributeAndModes(bf.get());
242
243        return xform.take();
244}
245
246EffectPanel *build_gui(osg::Group *root)
247{
248        osg::ref_ptr<osg::Group> hud = build_hud_base(root);
249
250        osg::ref_ptr<EffectPanel> effect_panel = new EffectPanel;
251        effect_panel->setCaption("osgFX Effect Browser");
252        effect_panel->setRect(Rect(20, 20, 1000, 280));
253
254        hud->addChild(effect_panel.get());
255
256        return effect_panel.take();
257}
258
259void build_world(osg::Group *root, osg::Node *scene, osgProducer::Viewer &viewer)
260{
261        osg::ref_ptr<EffectPanel> effect_panel = build_gui(root);
262        effect_panel->setScene(scene);
263        effect_panel->rebuild();
264
265        viewer.getEventHandlerList().push_front(new EffectPanel::KeyboardHandler(effect_panel.get()));
266
267        root->addChild(effect_panel->getRoot());
268}
269
270int main(int argc, char *argv[])
271{
272    // use an ArgumentParser object to manage the program arguments.
273    osg::ArgumentParser arguments(&argc, argv);
274
275    // set up the usage document, in case we need to print out how to use this program.
276    arguments.getApplicationUsage()->setApplicationName(arguments.getApplicationName());
277    arguments.getApplicationUsage()->setDescription(arguments.getApplicationName() + " is a simple browser that allows you to apply osgFX effects to models interactively.");
278    arguments.getApplicationUsage()->setCommandLineUsage(arguments.getApplicationName() + " [options] filename ...");
279    arguments.getApplicationUsage()->addCommandLineOption("-h or --help", "Display this information");
280        arguments.getApplicationUsage()->addKeyboardMouseBinding("Left", "Apply previous effect");
281        arguments.getApplicationUsage()->addKeyboardMouseBinding("Right", "Apply next effect");
282        arguments.getApplicationUsage()->addKeyboardMouseBinding("Del", "Enable or disable osgFX");
283        arguments.getApplicationUsage()->addKeyboardMouseBinding("Return", "Show or hide the effect information panel");
284        arguments.getApplicationUsage()->addKeyboardMouseBinding("x", "Save the scene graph with current effect applied");
285
286
287    // construct the viewer.
288    osgProducer::Viewer viewer(arguments);
289
290    // set up the value with sensible default event handlers.
291    viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS);
292
293    // get details on keyboard and mouse bindings used by the viewer.
294    viewer.getUsage(*arguments.getApplicationUsage());
295
296    // if user request help write it out to cout.
297    if (arguments.read("-h") || arguments.read("--help")) {
298        arguments.getApplicationUsage()->write(std::cout);
299        return 1;
300    }
301
302    // any option left unread are converted into errors to write out later.
303    arguments.reportRemainingOptionsAsUnrecognized();
304
305    // report any errors if they have occured when parsing the program aguments.
306    if (arguments.errors()) {
307        arguments.writeErrorMessages(std::cout);
308        return 1;
309    }
310
311    if (arguments.argc() <= 1) {
312        arguments.getApplicationUsage()->write(std::cout, osg::ApplicationUsage::COMMAND_LINE_OPTION);
313        return 1;
314    }
315
316    osg::Timer timer;
317    osg::Timer_t start_tick = timer.tick();
318
319    // read the scene from the list of file specified commandline args.
320    osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments);
321
322    // if no model has been successfully loaded report failure.
323    if (!loadedModel) {
324        std::cout << arguments.getApplicationName() << ": No data loaded" << std::endl;
325        return 1;
326    }
327
328    osg::Timer_t end_tick = timer.tick();
329
330    std::cout << "Time to load = " << timer.delta_s(start_tick,end_tick) << std::endl;
331
332    // optimize the scene graph, remove rendundent nodes and state etc.
333    osgUtil::Optimizer optimizer;
334    optimizer.optimize(loadedModel.get());
335
336        // set up a transform to rotate the model
337        osg::ref_ptr<osg::MatrixTransform> xform = new osg::MatrixTransform;
338        rotate_cb = new RotateCallback;
339        xform->setUpdateCallback(rotate_cb);
340        xform->addChild(loadedModel.get());
341
342        osg::ref_ptr<osg::Light> light = new osg::Light;
343        light->setLightNum(0);
344        light->setDiffuse(osg::Vec4(1, 1, 1, 1));
345        light->setSpecular(osg::Vec4(1, 1, 0.8f, 1));
346        light->setAmbient(osg::Vec4(0.2f, 0.2f, 0.2f, 0.2f));
347        light->setPosition(osg::Vec4(1, -1, 1, 0));
348
349        osg::ref_ptr<osg::LightSource> root = new osg::LightSource;
350        root->setLight(light.get());
351        root->setLocalStateSetModes();
352
353        build_world(root.get(), xform.get(), viewer);
354
355    // set the scene to render
356    viewer.setSceneData(root.get());
357
358    // create the windows and run the threads.
359    viewer.realize();
360
361    while(!viewer.done())
362    {
363        // wait for all cull and draw threads to complete.
364        viewer.sync();
365
366        // update the scene by traversing it with the the update visitor which will
367        // call all node update callbacks and animations.
368        viewer.update();
369
370        // fire off the cull and draw traversals of the scene.
371        viewer.frame();
372
373    }
374
375    // wait for all cull and draw threads to complete before exit.
376    viewer.sync();
377
378    return 0;
379}
Note: See TracBrowser for help on using the browser.