| [6941] | 1 | |
|---|
| 2 | |
|---|
| 3 | |
|---|
| 4 | |
|---|
| 5 | |
|---|
| 6 | |
|---|
| 7 | |
|---|
| 8 | |
|---|
| 9 | |
|---|
| 10 | |
|---|
| 11 | |
|---|
| 12 | |
|---|
| 13 | |
|---|
| 14 | |
|---|
| 15 | |
|---|
| 16 | |
|---|
| 17 | |
|---|
| 18 | |
|---|
| [2184] | 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 | |
|---|
| [5923] | 27 | #include <osgViewer/Viewer> |
|---|
| [2184] | 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> |
|---|
| [5923] | 46 | #include <iostream> |
|---|
| [2184] | 47 | |
|---|
| 48 | class RotateCallback: public osg::NodeCallback { |
|---|
| 49 | public: |
|---|
| [4805] | 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_) { |
|---|
| [6051] | 55 | double t = nv->getFrameStamp()->getSimulationTime(); |
|---|
| [4805] | 56 | xform->setMatrix(osg::Matrix::rotate(t, osg::Vec3(0, 0, 1))); |
|---|
| 57 | } |
|---|
| 58 | traverse(node, nv); |
|---|
| 59 | } |
|---|
| [2184] | 60 | |
|---|
| [4805] | 61 | bool enabled_; |
|---|
| [2184] | 62 | }; |
|---|
| 63 | |
|---|
| 64 | |
|---|
| 65 | |
|---|
| 66 | |
|---|
| 67 | RotateCallback *rotate_cb; |
|---|
| 68 | |
|---|
| 69 | |
|---|
| [3529] | 70 | class EffectPanel: public osgfxbrowser::Frame { |
|---|
| [2184] | 71 | public: |
|---|
| 72 | |
|---|
| [4805] | 73 | class KeyboardHandler: public osgGA::GUIEventHandler { |
|---|
| 74 | public: |
|---|
| 75 | KeyboardHandler(EffectPanel* ep): ep_(ep) {} |
|---|
| [2184] | 76 | |
|---|
| [4805] | 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') { |
|---|
| [12529] | 97 | osgDB::writeNodeFile(*ep_->getRoot(), "osgfx_model.osgt"); |
|---|
| 98 | std::cout << "written nodes to \"osgfx_model.osgt\"\n"; |
|---|
| [4805] | 99 | return true; |
|---|
| 100 | } |
|---|
| 101 | if (ea.getKey() == 'r') { |
|---|
| 102 | rotate_cb->enabled_ = !rotate_cb->enabled_; |
|---|
| 103 | return true; |
|---|
| 104 | } |
|---|
| 105 | } |
|---|
| [2184] | 106 | |
|---|
| [4805] | 107 | return false; |
|---|
| 108 | } |
|---|
| [2184] | 109 | |
|---|
| [4805] | 110 | private: |
|---|
| 111 | osg::ref_ptr<EffectPanel> ep_; |
|---|
| 112 | }; |
|---|
| [2184] | 113 | |
|---|
| [4805] | 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)); |
|---|
| [2184] | 124 | |
|---|
| [4805] | 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 | } |
|---|
| [2184] | 132 | |
|---|
| [4805] | 133 | std::cout << "INFO: " << emap.size() << " effect(s) ready.\n"; |
|---|
| [2184] | 134 | |
|---|
| [4805] | 135 | if (!_effects.empty()) { |
|---|
| 136 | _selected_fx = 0; |
|---|
| 137 | } |
|---|
| 138 | } |
|---|
| [2184] | 139 | |
|---|
| [4805] | 140 | inline osg::Group* getRoot() { return _root.get(); } |
|---|
| 141 | inline void setRoot(osg::Group* node) { _root = node; } |
|---|
| [2184] | 142 | |
|---|
| [4805] | 143 | inline osg::Node* getScene() { return _scene.get(); } |
|---|
| 144 | inline void setScene(osg::Node* node) { _scene = node; } |
|---|
| [2184] | 145 | |
|---|
| [4805] | 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 | } |
|---|
| [2184] | 154 | |
|---|
| [4805] | 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 | } |
|---|
| [2184] | 163 | |
|---|
| [4805] | 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 | } |
|---|
| [2184] | 171 | |
|---|
| 172 | protected: |
|---|
| [4805] | 173 | void rebuild_client_area(const osgfxbrowser::Rect &client_rect) |
|---|
| 174 | { |
|---|
| [3156] | 175 | float zPos = -0.1; |
|---|
| 176 | |
|---|
| 177 | |
|---|
| [4805] | 178 | osg::ref_ptr<osgText::Font> arial = osgText::readFontFile("fonts/arial.ttf"); |
|---|
| [2184] | 179 | |
|---|
| [4805] | 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()); |
|---|
| [2184] | 188 | |
|---|
| [4805] | 189 | std::string effect_name = "No Effect Selected"; |
|---|
| 190 | std::string effect_description = ""; |
|---|
| [2184] | 191 | |
|---|
| [4805] | 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()); |
|---|
| [2184] | 199 | |
|---|
| [4805] | 200 | if (_scene.valid() && _root.valid()) { |
|---|
| [5122] | 201 | _root->removeChildren(0, _root->getNumChildren()); |
|---|
| [4805] | 202 | osg::ref_ptr<osgFX::Effect> effect = _effects[_selected_fx].get(); |
|---|
| 203 | effect->setEnabled(_fxen); |
|---|
| [5122] | 204 | effect->removeChildren(0, effect->getNumChildren()); |
|---|
| [4805] | 205 | effect->addChild(_scene.get()); |
|---|
| 206 | effect->setUpDemo(); |
|---|
| 207 | _root->addChild(effect.get()); |
|---|
| 208 | } |
|---|
| 209 | } |
|---|
| [2184] | 210 | |
|---|
| [4805] | 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()); |
|---|
| [2184] | 219 | |
|---|
| [4805] | 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 | } |
|---|
| [2184] | 230 | |
|---|
| 231 | private: |
|---|
| [4805] | 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; |
|---|
| [2184] | 241 | }; |
|---|
| 242 | |
|---|
| 243 | |
|---|
| [4119] | 244 | osg::Group* build_hud_base(osg::Group* root) |
|---|
| [2184] | 245 | { |
|---|
| [4805] | 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()); |
|---|
| [2184] | 249 | |
|---|
| [4805] | 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()); |
|---|
| [2184] | 253 | |
|---|
| [4805] | 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); |
|---|
| [2184] | 258 | |
|---|
| [4805] | 259 | osg::ref_ptr<osg::BlendFunc> bf = new osg::BlendFunc; |
|---|
| 260 | ss->setAttributeAndModes(bf.get()); |
|---|
| [2184] | 261 | |
|---|
| [5187] | 262 | return xform.release(); |
|---|
| [2184] | 263 | } |
|---|
| 264 | |
|---|
| [4119] | 265 | EffectPanel* build_gui(osg::Group* root) |
|---|
| [2184] | 266 | { |
|---|
| [4805] | 267 | osg::ref_ptr<osg::Group> hud = build_hud_base(root); |
|---|
| [2184] | 268 | |
|---|
| [4805] | 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)); |
|---|
| [2184] | 272 | |
|---|
| [4805] | 273 | hud->addChild(effect_panel.get()); |
|---|
| [2184] | 274 | |
|---|
| [5187] | 275 | return effect_panel.release(); |
|---|
| [2184] | 276 | } |
|---|
| 277 | |
|---|
| [5923] | 278 | void build_world(osg::Group* root, osg::Node* scene, osgViewer::Viewer& viewer) |
|---|
| [2184] | 279 | { |
|---|
| [4805] | 280 | osg::ref_ptr<EffectPanel> effect_panel = build_gui(root); |
|---|
| 281 | effect_panel->setScene(scene); |
|---|
| 282 | effect_panel->rebuild(); |
|---|
| [2184] | 283 | |
|---|
| [5923] | 284 | viewer.addEventHandler(new EffectPanel::KeyboardHandler(effect_panel.get())); |
|---|
| [2184] | 285 | |
|---|
| [4805] | 286 | root->addChild(effect_panel->getRoot()); |
|---|
| [2184] | 287 | } |
|---|
| 288 | |
|---|
| 289 | int main(int argc, char *argv[]) |
|---|
| 290 | { |
|---|
| 291 | |
|---|
| 292 | osg::ArgumentParser arguments(&argc, argv); |
|---|
| 293 | |
|---|
| 294 | |
|---|
| 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"); |
|---|
| [4805] | 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"); |
|---|
| [2184] | 304 | |
|---|
| 305 | |
|---|
| 306 | |
|---|
| [5923] | 307 | osgViewer::Viewer viewer; |
|---|
| [2184] | 308 | |
|---|
| 309 | |
|---|
| 310 | if (arguments.read("-h") || arguments.read("--help")) { |
|---|
| 311 | arguments.getApplicationUsage()->write(std::cout); |
|---|
| 312 | return 1; |
|---|
| 313 | } |
|---|
| 314 | |
|---|
| [6835] | 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 | |
|---|
| [10869] | 323 | |
|---|
| 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 | |
|---|
| [2184] | 329 | |
|---|
| 330 | arguments.reportRemainingOptionsAsUnrecognized(); |
|---|
| 331 | |
|---|
| [7648] | 332 | |
|---|
| [2184] | 333 | if (arguments.errors()) { |
|---|
| 334 | arguments.writeErrorMessages(std::cout); |
|---|
| 335 | return 1; |
|---|
| 336 | } |
|---|
| 337 | |
|---|
| 338 | |
|---|
| 339 | osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments); |
|---|
| 340 | |
|---|
| [6909] | 341 | |
|---|
| [12529] | 342 | if (!loadedModel) loadedModel = osgDB::readNodeFile("dumptruck.osgt"); |
|---|
| [6909] | 343 | |
|---|
| 344 | if (!loadedModel) |
|---|
| 345 | { |
|---|
| 346 | std::cout << arguments.getApplicationName() <<": No data loaded" << std::endl; |
|---|
| [2184] | 347 | return 1; |
|---|
| 348 | } |
|---|
| 349 | |
|---|
| [7648] | 350 | |
|---|
| [2184] | 351 | osgUtil::Optimizer optimizer; |
|---|
| 352 | optimizer.optimize(loadedModel.get()); |
|---|
| 353 | |
|---|
| [4805] | 354 | |
|---|
| 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()); |
|---|
| [2184] | 359 | |
|---|
| [4805] | 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)); |
|---|
| [2184] | 366 | |
|---|
| [4805] | 367 | osg::ref_ptr<osg::LightSource> root = new osg::LightSource; |
|---|
| 368 | root->setLight(light.get()); |
|---|
| 369 | root->setLocalStateSetModes(); |
|---|
| [2184] | 370 | |
|---|
| [4805] | 371 | build_world(root.get(), xform.get(), viewer); |
|---|
| [2184] | 372 | |
|---|
| 373 | |
|---|
| 374 | viewer.setSceneData(root.get()); |
|---|
| 375 | |
|---|
| [5923] | 376 | return viewer.run(); |
|---|
| [2184] | 377 | } |
|---|