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

Revision 12529, 14.1 kB (checked in by robert, 3 years ago)

Replaced .osg with .osgt file usage

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