1 /* -*-c++-*- */
2 /* osgEarth - Geospatial SDK for OpenSceneGraph
3 * Copyright 2008-2014 Pelican Mapping
4 * http://osgearth.org
5 *
6 * osgEarth is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public License
17 * along with this program.  If not, see <http://www.gnu.org/licenses/>
18 */
19 #include <osgViewer/Viewer>
20 #include <osgDB/FileNameUtils>
21 #include <osgEarth/NodeUtils>
22 #include <osgEarth/LineDrawable>
23 #include <osgEarth/Registry>
24 #include <osgEarthUtil/EarthManipulator>
25 #include <osgEarthUtil/ExampleResources>
26 #include <osgEarthUtil/Controls>
27 #include <osgEarthTriton/TritonAPIWrapper>
28 #include <osgEarthTriton/TritonCallback>
29 #include <osgEarthTriton/TritonOptions>
30 #include <osgEarthTriton/TritonLayer>
31 #include <osgEarthAnnotation/AnnotationLayer>
32 #include <osgEarthAnnotation/PlaceNode>
33 #include <osgEarthAnnotation/GeoPositionNode>
34 
35 #define LC "[osgearth_triton] "
36 
37 using namespace osgEarth;
38 using namespace osgEarth::Util;
39 using namespace osgEarth::Triton;
40 using namespace osgEarth::Annotation;
41 namespace ui = osgEarth::Util::Controls;
42 
43 struct Settings
44 {
45     optional<double> chop;
46     optional<double> seaState;
47     optional<float> alpha;
48     osg::observer_ptr<TritonLayer> tritonLayer;
49 
applySettings50     void apply(Environment& env, Ocean& ocean)
51     {
52         if (chop.isSet())
53         {
54             ocean.SetChoppiness(chop.get());
55             chop.clear();
56         }
57 
58         if (seaState.isSet())
59         {
60             env.SimulateSeaState(seaState.get(), 0.0);
61             seaState.clear();
62         }
63 
64         osg::ref_ptr<TritonLayer> layer;
65         if (alpha.isSet() && tritonLayer.lock(layer))
66         {
67             layer->setOpacity(alpha.value());
68             alpha.clear();
69         }
70     }
71 };
72 
73 class TritonCallback : public osgEarth::Triton::Callback
74 {
75 public:
TritonCallback(Settings & settings)76     TritonCallback(Settings& settings) : _settings(settings) { }
77 
onInitialize(Environment & env,Ocean & ocean)78     void onInitialize(Environment& env, Ocean& ocean)
79     {
80         //todo
81     }
82 
onDrawOcean(Environment & env,Ocean & ocean)83     void onDrawOcean(Environment& env, Ocean& ocean)
84     {
85         _settings.apply(env, ocean);
86     }
87 
88     Settings& _settings;
89 };
90 
91 
92 struct App
93 {
AppApp94     App()
95     {
96         tritonLayer = NULL;
97         map = NULL;
98         const double lon = -118.5406, lat = 32.7838;
99 
100         anchor.set(
101             SpatialReference::get("wgs84"), lon, lat, 0.0,
102             ALTMODE_ABSOLUTE);
103 
104         isect = new Triton::TritonIntersections();
105     }
106 
107     Map*         map;
108     TritonLayer* tritonLayer;
109     Settings     settings;
110     osg::ref_ptr<Triton::TritonIntersections> isect;
111     AnnotationLayer* labels;
112     AnnotationLayer* normals;
113     LineDrawable* normalDrawable;
114     GeoPoint anchor;
115 
addTritonApp116     void addTriton()
117     {
118         // Create TritonNode from TritonOptions
119         osgEarth::Triton::TritonOptions tritonOptions;
120         tritonOptions.user()        = "my_user_name";
121         tritonOptions.licenseCode() = "my_license_code";
122         tritonOptions.maxAltitude() = 100000;
123         tritonOptions.useHeightMap() = true;
124 
125         const char* ev_t = ::getenv("TRITON_PATH");
126         if ( ev_t )
127         {
128             tritonOptions.resourcePath() = osgDB::concatPaths(
129                 std::string(ev_t),
130                 "Resources" );
131 
132             OE_INFO << LC
133                 << "Setting resource path to << " << tritonOptions.resourcePath().get()
134                 << std::endl;
135         }
136         else
137         {
138             OE_WARN << LC
139                 << "No resource path! Triton might not initialize properly. "
140                 << "Consider setting the TRITON_PATH environment variable."
141                 << std::endl;
142         }
143 
144 
145         tritonLayer = new TritonLayer(tritonOptions, new TritonCallback(settings));
146         map->addLayer(tritonLayer);
147         settings.tritonLayer = tritonLayer;
148 
149         tritonLayer->addIntersections(isect.get());
150     }
151 
removeTritonApp152     void removeTriton()
153     {
154         if (tritonLayer)
155             map->removeLayer(tritonLayer);
156         tritonLayer = 0L;
157     }
158 
addBuoyancyTestApp159     void addBuoyancyTest(osg::Node* model)
160     {
161         //labels = new AnnotationLayer();
162         //map->addLayer(labels);
163 
164         normals = new AnnotationLayer();
165         map->addLayer(normals);
166 
167         // geometry for a unit normal vector
168         normalDrawable = new LineDrawable(GL_LINES);
169         normalDrawable->setColor(osg::Vec4(1,1,0,1));
170         normalDrawable->pushVertex(osg::Vec3(0,0,0));
171         normalDrawable->pushVertex(osg::Vec3(0,0,10));
172         normalDrawable->pushVertex(osg::Vec3(-2,0,0.5));
173         normalDrawable->pushVertex(osg::Vec3(2,0,0.5));
174         normalDrawable->pushVertex(osg::Vec3(0,-2,0.5));
175         normalDrawable->pushVertex(osg::Vec3(0,2,0.5));
176         normalDrawable->finish();
177 
178         // a single shared anchor point for the intersection set:
179         isect->setAnchor(anchor);
180 
181         // generate a bunch of local points around the anchor:
182         for(int x=-50; x<=50; x+=25)
183         {
184             for(int y=-50; y<=50; y+=25)
185             {
186                 isect->addLocalPoint(osg::Vec3d(x, y, 0));
187 
188                 // a label communicating the wave height:
189                 //PlaceNode* label = new PlaceNode();
190                 //label->setDynamic(true);
191                 //label->setPosition(anchor);
192                 //label->setIconImage(image);
193                 //label->setText("-");
194                 //labels->getGroup()->addChild(label);
195 
196                 // a normal vector and optional model:
197                 GeoPositionNode* normal = new GeoPositionNode();
198                 normal->setDynamic(true);
199                 normal->getPositionAttitudeTransform()->addChild(normalDrawable);
200                 if (model)
201                     normal->getPositionAttitudeTransform()->addChild(model);
202                 normal->setPosition(anchor);
203                 normals->getGroup()->addChild(normal);
204             }
205         }
206 
207         //ScreenSpaceLayout::setDeclutteringEnabled(false);
208     }
209 
updateBuoyancyTestApp210     void updateBuoyancyTest()
211     {
212         for(unsigned i=0; i<isect->getHeights().size(); ++i)
213         {
214             osg::Vec3d local = isect->getInput()[i];
215             local.z() = isect->getHeights()[i];
216 
217             //PlaceNode* label = dynamic_cast<PlaceNode*>(labels->getGroup()->getChild(i));
218             //label->getPositionAttitudeTransform()->setPosition(local);
219             //label->setText(Stringify()<<std::setprecision(2)<<local.z());
220 
221             GeoPositionNode* normalNode = dynamic_cast<GeoPositionNode*>(normals->getGroup()->getChild(i));
222             normalNode->getPositionAttitudeTransform()->setPosition(local);
223             osg::Quat q;
224             q.makeRotate(osg::Vec3d(0,0,1), isect->getNormals()[i]);
225             normalNode->getPositionAttitudeTransform()->setAttitude(q);
226         }
227     }
228 };
229 
230 App s_app;
231 
232 
233 
234 template<typename T> struct Set : public ui::ControlEventHandler
235 {
236     optional<T>& _var;
SetSet237     Set(optional<T>& var) : _var(var) { }
onValueChangedSet238     void onValueChanged(ui::Control*, double value) { _var = value; }
239 };
240 
241 struct Toggle : public ui::ControlEventHandler
242 {
onValueChangedToggle243     void onValueChanged(ui::Control*, bool value) {
244         if (s_app.tritonLayer)
245             s_app.removeTriton();
246         else
247             s_app.addTriton();
248     }
249 };
250 
createUI()251 Container* createUI()
252 {
253     VBox* box = new VBox();
254     box->setBackColor(0,0,0,0.5);
255     Grid* grid = box->addControl(new Grid());
256     int r=0;
257     grid->setControl(0, r, new LabelControl("Chop"));
258     grid->setControl(1, r, new HSliderControl(0, 3, 0, new Set<double>(s_app.settings.chop)));
259     ++r;
260     grid->setControl(0, r, new LabelControl("Sea State"));
261     grid->setControl(1, r, new HSliderControl(0, 12, 5, new Set<double>(s_app.settings.seaState)));
262     ++r;
263     grid->setControl(0, r, new LabelControl("Alpha"));
264     grid->setControl(1, r, new HSliderControl(0, 1.0, 1.0, new Set<float>(s_app.settings.alpha)));
265     ++r;
266     grid->setControl(0, r, new LabelControl("Toggle"));
267     grid->setControl(1, r, new CheckBoxControl(true, new Toggle()));
268 
269     grid->getControl(1, r-1)->setHorizFill(true,200);
270 
271     return box;
272 }
273 
274 
275 int
usage(const char * name)276 usage(const char* name)
277 {
278     OE_DEBUG
279         << "\nUsage: " << name << " file.earth" << std::endl
280         << osgEarth::Util::MapNodeHelper().usage() << std::endl;
281 
282     return 0;
283 }
284 
285 int
main(int argc,char ** argv)286 main(int argc, char** argv)
287 {
288     osg::ArgumentParser arguments(&argc,argv);
289 
290     // help?
291     if ( arguments.read("--help") )
292         return usage(argv[0]);
293 
294     osg::Node* model = 0L;
295     std::string filename;
296     if (arguments.read("--model", filename))
297     {
298         model = osgDB::readRefNodeFile(filename).release();
299         Registry::shaderGenerator().run(model);
300     }
301 
302     // create a viewer:
303     osgViewer::Viewer viewer(arguments);
304 
305     // Tell the database pager to not modify the unref settings
306     viewer.getDatabasePager()->setUnrefImageDataAfterApplyPolicy( false, false );
307 
308     // install our default manipulator (do this before calling load)
309     EarthManipulator* manip = new EarthManipulator();
310     viewer.setCameraManipulator(manip);
311 
312     // load an earth file, and support all or our example command-line options
313     // and earth file <external> tags
314     osg::Group* node = osgEarth::Util::MapNodeHelper().load(arguments, &viewer, createUI());
315     if ( node )
316     {
317         viewer.getCamera()->setNearFarRatio(0.00002);
318         viewer.getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
319 
320         viewer.setSceneData( node );
321 
322         s_app.map = MapNode::get( node )->getMap();
323 
324         s_app.addTriton();
325         s_app.addBuoyancyTest(model);
326 
327         // Zoom the camera to our area of interest:
328         Viewpoint vp;
329         vp.heading() = 25.0f;
330         vp.pitch() = -25;
331         vp.range() = 400.0;
332         vp.focalPoint() = s_app.anchor;
333         manip->setViewpoint(vp);
334 
335         while(!viewer.done())
336         {
337             viewer.frame();
338             s_app.updateBuoyancyTest();
339         }
340     }
341     else
342     {
343         return usage(argv[0]);
344     }
345 }
346