1 // -*-c++-*- osgWidget - Code by: Jeremy Moles (cubicool) 2007-2008
2 // $Id: osgwidgetwindow.cpp 66 2008-07-14 21:54:09Z cubicool $
3 
4 #include <iostream>
5 #include <osgDB/ReadFile>
6 #include <osgGA/StateSetManipulator>
7 #include <osgViewer/Viewer>
8 #include <osgViewer/ViewerEventHandlers>
9 #include <osgWidget/WindowManager>
10 #include <osgWidget/ViewerEventHandlers>
11 #include <osgWidget/Box>
12 
13 const unsigned int MASK_2D = 0xF0000000;
14 const unsigned int MASK_3D = 0x0F000000;
15 
16 // Here we create (and later demonstrate) the use of a simple function callback.
windowClicked(osgWidget::Event & ev)17 bool windowClicked(osgWidget::Event& ev) {
18     std::cout << "windowClicked: " << ev.getWindow()->getName() << std::endl;
19 
20     if(ev.getData()) {
21         std::string* s = static_cast<std::string*>(ev.getData());
22 
23         std::cout << "This is data attached to the event: " << *s << std::endl;
24     }
25 
26     return true;
27 }
28 
windowScrolled(osgWidget::Event & ev)29 bool windowScrolled(osgWidget::Event& ev) {
30     osgWidget::warn()
31         << "scrolling up? " << ev.getWindowManager()->isMouseScrollingUp()
32         << std::endl
33     ;
34 
35     return true;
36 }
37 
38 // Here we dcreate a new class and show how to use a method callback (which differs from
39 // a function callback in that we are required to also pass the "this" argument).
40 struct Object {
windowClickedObject41     bool windowClicked(osgWidget::Event& ev) {
42         std::cout << "Object::windowClicked " << ev.getWindow()->getName() << std::endl;
43 
44         return true;
45     }
46 };
47 
48 // This is the more "traditional" method of creating a callback.
49 struct CallbackObject: public osgWidget::Callback {
CallbackObjectCallbackObject50     CallbackObject(osgWidget::EventType evType):
51     osgWidget::Callback(evType) {
52     }
53 
operator ()CallbackObject54     virtual bool operator()(osgWidget::Event& /*ev*/) {
55         std::cout << "here" << std::endl;
56 
57         return false;
58     }
59 };
60 
main(int,char **)61 int main(int, char**)
62 {
63     osgViewer::Viewer viewer;
64 
65     // Let's get busy! The WindowManager class is actually an osg::Switch,
66     // so you can add it to (ideally) an orthographic camera and have it behave as
67     // expected. Note that you create a WindowManager with a NodeMask--it is very important
68     // that this be unique for picking to work properly. This also makes it possible to have
69     // multiple WindowManagers each operating on their own, unique set of Window objects.
70     // The final bool argument is a group of flags that introduce optional functionality
71     // for the WindowManager. In our case we include the flags USE_PYTHON and USE_LUA,
72     // to demonstrate (and test) their usage. Finally, we pass the temporary WM_NO_BETA_WARN
73     // argument, which prevents creating the orange warning window. :) It will be shown
74     // in other examples...
75     osgWidget::WindowManager* wm = new osgWidget::WindowManager(
76         &viewer,
77         1280.0f,
78         1024.0f,
79         MASK_2D,
80         osgWidget::WindowManager::WM_USE_LUA |
81         osgWidget::WindowManager::WM_USE_PYTHON |
82         osgWidget::WindowManager::WM_PICK_DEBUG
83     );
84 
85     // An actual osgWidget::Window is pure virtual, so we've got to use the osgWidget::Box
86     // implementation for now. At a later time, support for Tables and other kinds of
87     // advanced layout Window types will be added.
88     osgWidget::Window* box = new osgWidget::Box("box", osgWidget::Box::HORIZONTAL);
89 
90     // Now we actually attach our two types of callbacks to the box instance. The first
91     // uses the simple function signature, the second uses a bound method, passing "this"
92     // as the second argument to the Callback constructor.
93     // Object obj;
94 
95     static std::string data = "lol ur face!";
96 
97     /*
98     box->addCallback(new osgWidget::Callback(&windowClicked, osgWidget::EVENT_MOUSE_PUSH, &data));
99     box->addCallback(new osgWidget::Callback(&windowScrolled, osgWidget::EVENT_MOUSE_SCROLL));
100     box->addCallback(osgWidget::Callback(
101         &Object::windowClicked,
102         &obj,
103         osgWidget::EVENT_MOUSE_PUSH
104     ));
105     */
106 
107     box->addCallback(new CallbackObject(osgWidget::EVENT_MOUSE_PUSH));
108 
109     // Create some of our "testing" Widgets; included are two Widget subclasses I made
110     // during testing which I've kept around for testing purposes. You'll notice
111     // that you cannot move the box using the NullWidget, and that the NotifyWidget
112     // is a bit verbose. :)
113     osgWidget::Widget* widget1 = new osgWidget::NotifyWidget("widget1", 300.0f, 100.0f);
114     osgWidget::Widget* widget2 = new osgWidget::NullWidget("widget2", 400.0f, 75.0f);
115     osgWidget::Widget* widget3 = new osgWidget::Widget("widget3", 100.0f, 100.0f);
116     // Set the colors of widget1 and widget3 to green.
117     widget1->setColor(0.0f, 1.0f, 0.0f, 1.0f);
118     widget1->setCanFill(true);
119     widget3->setColor(0.0f, 1.0f, 0.0f, 1.0f);
120 
121     widget1->setImage(osgDB::readRefImageFile("Images/Saturn.TGA"), true);
122 
123     // Set the color of widget2, to differentiate it and make it sassy. This is
124     // like a poor man's gradient!
125     widget2->setColor(0.9f, 0.0f, 0.0f, 0.9f, osgWidget::Widget::LOWER_LEFT);
126     widget2->setColor(0.9f, 0.0f, 0.0f, 0.9f, osgWidget::Widget::LOWER_RIGHT);
127     widget2->setColor(0.0f, 0.0f, 0.9f, 0.9f, osgWidget::Widget::UPPER_RIGHT);
128     widget2->setColor(0.0f, 0.0f, 0.9f, 0.9f, osgWidget::Widget::UPPER_LEFT);
129 
130     // Now add our newly created widgets to our box.
131     box->addWidget(widget1);
132     box->addWidget(widget2);
133     box->addWidget(widget3);
134 
135     // For maximum efficiency, Windows don't automatically reallocate their geometry
136     // and internal positioning every time a widget is added. Thus, we either have to
137     // call the WindowManger::resizeAllWindows method or manually call
138     // Window::resize when we're ready.
139     box->resize();
140 
141     // Now, lets clone our existing box and create a new copy of of it, also adding that
142     // to the WindowManager. This demonstrates the usages of OSG's ->clone() support,
143     // though that is abstracted by our META_UIObject macro.
144     osgWidget::Window* boxCopy = osg::clone(box, "newBox", osg::CopyOp::DEEP_COPY_ALL);
145 
146     // Move our copy to make it visible.
147     boxCopy->setOrigin(0.0f, 125.0f);
148 
149     boxCopy->getByName("widget1")->setColor(0.5f, 0.0f, 1.0f, 1.0f);
150     boxCopy->getByName("widget3")->setColor(0.5f, 0.0f, 1.0f, 1.0f);
151 
152     // Add the successfully created Box (if we get this far) into the WindowManager, so
153     // that they can receive events.
154     wm->addChild(box);
155     wm->addChild(boxCopy);
156 
157     // Now, ask our new box to be 100% the width of the WindowManager.
158     boxCopy->resizePercent(100.0f, 0.0f);
159 
160     // Here we demonstrate the use of osgWidget/io_utils. This is really only useful for
161     // debugging at the moment.
162     // std::cout << *box << std::endl << *boxCopy << std::endl;
163 
164     // Setup our OSG objects for our scene; note the use of the utility function
165     // createOrthoCamera, which is just a helper for setting up a proper viewing area.
166     // An alternative (and a MUCH easier alternative at that!) is to
167     // simply use the createParentOrthoCamera method of the WindowManager class,
168     // which will wrap the calls to createOrthoCamera and addChild for us! Check out
169     // some of the other examples to see this in action...
170     osg::ref_ptr<osg::Group>  group  = new osg::Group();
171     osg::ref_ptr<osg::Camera> camera = osgWidget::createOrthoCamera(1280.0f, 1024.0f);
172     osg::ref_ptr<osg::Node>   model  = osgDB::readRefNodeFile("cow.osgt");
173 
174     // Add our event handler; is this better as a MatrixManipulator? Add a few other
175     // helpful ViewerEventHandlers.
176     viewer.addEventHandler(new osgWidget::MouseHandler(wm));
177     viewer.addEventHandler(new osgWidget::KeyboardHandler(wm));
178     viewer.addEventHandler(new osgWidget::ResizeHandler(wm, camera.get()));
179     viewer.addEventHandler(new osgWidget::CameraSwitchHandler(wm, camera.get()));
180     viewer.addEventHandler(new osgViewer::StatsHandler());
181     viewer.addEventHandler(new osgViewer::WindowSizeHandler());
182     viewer.addEventHandler(new osgGA::StateSetManipulator(
183         viewer.getCamera()->getOrCreateStateSet()
184     ));
185 
186     // Set our first non-UI node to be something other than the mask we created our
187     // WindowManager with to avoid picking.
188     // TODO: Do I need to create a mechanism for doing this automatically, or should
189     // that be the responsibility of the users of osgWidget?
190     model->setNodeMask(MASK_3D);
191 
192     // Add the WindowManager instance to the 2D camera. This isn't strictly necessary,
193     // and you can get some cool results putting the WindowManager directly into a
194     // 3D scene. This is not necessary if you use WindowManager::createParentOrthoCamera.
195     camera->addChild(wm);
196 
197     // Add our camera and a testing 3D model to the scene.
198     group->addChild(camera);
199     group->addChild(model);
200 
201     // Here we show how to both run simple strings of code AND run entire files. These
202     // assume that you're running the osgwidgetwindow example from the build directory,
203     // otherwise you'll need to adjust the file path below in the call to runFile().
204     wm->getLuaEngine()->eval("window = osgwidget.newWindow()");
205     wm->getLuaEngine()->runFile("osgWidget/osgwidgetwindow.lua");
206 
207     wm->getPythonEngine()->eval("import osgwidget");
208     wm->getPythonEngine()->runFile("osgWidget/osgwidgetwindow.py");
209 
210     viewer.setUpViewInWindow(0, 0, 1280, 1024);
211     viewer.setSceneData(group);
212 
213     /*
214     osgViewer::Viewer::Cameras cameras;
215     viewer.getCameras(cameras);
216     osg::Camera* c = cameras[0];
217     osg::Matrix s = osg::Matrix::scale(1.0f, -1.0f, 1.0f);
218     c->setProjectionMatrix(s * c->getProjectionMatrix());
219     */
220 
221     return viewer.run();
222 }
223