| 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 | |
|---|
| 29 | class RotateCallback: public osg::NodeCallback { |
|---|
| 30 | public: |
|---|
| 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 | |
|---|
| 47 | |
|---|
| 48 | RotateCallback *rotate_cb; |
|---|
| 49 | |
|---|
| 50 | |
|---|
| 51 | class EffectPanel: public osgfxbrowser::Frame { |
|---|
| 52 | public: |
|---|
| 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 | |
|---|
| 153 | protected: |
|---|
| 154 | void rebuild_client_area(const osgfxbrowser::Rect &client_rect) |
|---|
| 155 | { |
|---|
| 156 | float zPos = -0.1; |
|---|
| 157 | |
|---|
| 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->removeChild(0, _root->getNumChildren()); |
|---|
| 184 | osg::ref_ptr<osgFX::Effect> effect = _effects[_selected_fx].get(); |
|---|
| 185 | effect->setEnabled(_fxen); |
|---|
| 186 | effect->removeChild(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 | |
|---|
| 215 | private: |
|---|
| 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 | |
|---|
| 228 | osg::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 | |
|---|
| 249 | EffectPanel* 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 | |
|---|
| 262 | void 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 | |
|---|
| 273 | int main(int argc, char *argv[]) |
|---|
| 274 | { |
|---|
| 275 | |
|---|
| 276 | osg::ArgumentParser arguments(&argc, argv); |
|---|
| 277 | |
|---|
| 278 | |
|---|
| 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 | |
|---|
| 291 | osgProducer::Viewer viewer(arguments); |
|---|
| 292 | |
|---|
| 293 | |
|---|
| 294 | viewer.setUpViewer(osgProducer::Viewer::STANDARD_SETTINGS); |
|---|
| 295 | |
|---|
| 296 | |
|---|
| 297 | viewer.getUsage(*arguments.getApplicationUsage()); |
|---|
| 298 | |
|---|
| 299 | |
|---|
| 300 | if (arguments.read("-h") || arguments.read("--help")) { |
|---|
| 301 | arguments.getApplicationUsage()->write(std::cout); |
|---|
| 302 | return 1; |
|---|
| 303 | } |
|---|
| 304 | |
|---|
| 305 | |
|---|
| 306 | arguments.reportRemainingOptionsAsUnrecognized(); |
|---|
| 307 | |
|---|
| 308 | |
|---|
| 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 | |
|---|
| 323 | osg::ref_ptr<osg::Node> loadedModel = osgDB::readNodeFiles(arguments); |
|---|
| 324 | |
|---|
| 325 | |
|---|
| 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 | |
|---|
| 336 | osgUtil::Optimizer optimizer; |
|---|
| 337 | optimizer.optimize(loadedModel.get()); |
|---|
| 338 | |
|---|
| 339 | |
|---|
| 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 | |
|---|
| 359 | viewer.setSceneData(root.get()); |
|---|
| 360 | |
|---|
| 361 | |
|---|
| 362 | viewer.realize(); |
|---|
| 363 | |
|---|
| 364 | while(!viewer.done()) |
|---|
| 365 | { |
|---|
| 366 | |
|---|
| 367 | viewer.sync(); |
|---|
| 368 | |
|---|
| 369 | |
|---|
| 370 | |
|---|
| 371 | viewer.update(); |
|---|
| 372 | |
|---|
| 373 | |
|---|
| 374 | viewer.frame(); |
|---|
| 375 | |
|---|
| 376 | } |
|---|
| 377 | |
|---|
| 378 | |
|---|
| 379 | viewer.sync(); |
|---|
| 380 | |
|---|
| 381 | return 0; |
|---|
| 382 | } |
|---|