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