source: trunk/packages/vizservers/geovis/Renderer.cpp @ 4087

Last change on this file since 4087 was 4087, checked in by ldelgass, 11 years ago

Fix setting model layer opacity

File size: 18.0 KB
Line 
1/* -*- mode: c++; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 * Copyright (C) 2004-2013  HUBzero Foundation, LLC
4 *
5 * Author: Leif Delgass <ldelgass@purdue.edu>
6 */
7
8#include <cfloat>
9#include <cstring>
10#include <cassert>
11#include <cmath>
12
13#include <GL/gl.h>
14
15#ifdef WANT_TRACE
16#include <sys/time.h>
17#endif
18
19#include <osgGA/StateSetManipulator>
20
21#include <osgEarth/Version>
22#include <osgEarth/MapNode>
23#include <osgEarth/TerrainLayer>
24#include <osgEarth/ImageLayer>
25#include <osgEarth/ElevationLayer>
26#include <osgEarth/ModelLayer>
27#include <osgEarthUtil/EarthManipulator>
28#include <osgEarthUtil/AutoClipPlaneHandler>
29#include <osgEarthUtil/MouseCoordsTool>
30#include <osgEarthDrivers/gdal/GDALOptions>
31
32#include "Renderer.h"
33#include "Trace.h"
34
35#define MSECS_ELAPSED(t1, t2) \
36    ((t1).tv_sec == (t2).tv_sec ? (((t2).tv_usec - (t1).tv_usec)/1.0e+3) : \
37     (((t2).tv_sec - (t1).tv_sec))*1.0e+3 + (double)((t2).tv_usec - (t1).tv_usec)/1.0e+3)
38
39using namespace GeoVis;
40
41Renderer::Renderer() :
42    _needsRedraw(true),
43    _windowWidth(500),
44    _windowHeight(500)
45{
46    _bgColor[0] = 0;
47    _bgColor[1] = 0;
48    _bgColor[2] = 0;
49    _minFrameTime = 1.0/30.0;
50    _lastFrameTime = _minFrameTime;
51    _viewer = new osgViewer::Viewer();
52    _viewer->setThreadingModel(osgViewer::ViewerBase::SingleThreaded);
53    _viewer->getDatabasePager()->setUnrefImageDataAfterApplyPolicy(false, false);
54    _viewer->setReleaseContextAtEndOfFrameHint(false);
55    setBackgroundColor(_bgColor);
56    _captureCallback = new ScreenCaptureCallback();
57    _viewer->getCamera()->setPostDrawCallback(_captureCallback.get());
58    osgEarth::MapOptions mapOpts;
59    mapOpts.coordSysType() = osgEarth::MapOptions::CSTYPE_PROJECTED;
60    mapOpts.profile() = osgEarth::ProfileOptions("global-geodetic");
61    osgEarth::Map *map = new osgEarth::Map(mapOpts);
62    _map = map;
63    osgEarth::Drivers::GDALOptions bopts;
64    bopts.url() = "/usr/share/osgearth/data/world.tif";
65    addImageLayer("base", bopts);
66    osgEarth::MapNodeOptions mapNodeOpts;
67    mapNodeOpts.enableLighting() = false;
68    osgEarth::MapNode *mapNode = new osgEarth::MapNode(map, mapNodeOpts);
69    _mapNode = mapNode;
70    _sceneRoot = mapNode;
71    _viewer->setSceneData(_sceneRoot.get());
72    _manipulator = new osgEarth::Util::EarthManipulator;
73    _viewer->setCameraManipulator(_manipulator.get());
74    _viewer->addEventHandler(new osgGA::StateSetManipulator(_viewer->getCamera()->getOrCreateStateSet()));
75    _coordsCallback = new MouseCoordsCallback();
76    _mouseCoordsTool = new osgEarth::Util::MouseCoordsTool(mapNode);
77    _mouseCoordsTool->addCallback(_coordsCallback);
78    _viewer->addEventHandler(_mouseCoordsTool);
79    _viewer->getCamera()->setNearFarRatio(0.00002);
80    _viewer->getCamera()->setSmallFeatureCullingPixelSize(-1.0f);
81    _viewer->setUpViewInWindow(0, 0, _windowWidth, _windowHeight);
82    _viewer->realize();
83#ifdef DEBUG
84    if (_viewer->getViewerStats() != NULL) {
85        TRACE("Enabling stats");
86        _viewer->getViewerStats()->collectStats("scene", true);
87    }
88#endif
89#if 0
90    osgViewer::ViewerBase::Windows windows;
91    _viewer->getWindows(windows);
92    if (windows.size() == 1) {
93        windows[0]->setSyncToVBlank(false);
94    } else {
95        ERROR("Num windows: %lu", windows.size());
96    }
97#endif
98}
99
100osgGA::EventQueue *Renderer::getEventQueue()
101{
102    osgViewer::ViewerBase::Windows windows;
103    _viewer->getWindows(windows);
104    return windows[0]->getEventQueue();
105}
106
107Renderer::~Renderer()
108{
109    TRACE("Enter");
110
111    TRACE("Leave");
112}
113
114void Renderer::loadEarthFile(const char *path)
115{
116    TRACE("Loading %s", path);
117    osg::Node *node = osgDB::readNodeFile(path);
118    if (node == NULL) {
119        ERROR("Couldn't load %s", path);
120        return;
121    }
122    osgEarth::MapNode *mapNode = osgEarth::MapNode::findMapNode(node);
123    if (mapNode == NULL) {
124        ERROR("Couldn't find MapNode");
125        return;
126    } else {
127        _sceneRoot = node;
128        _map = mapNode->getMap();
129    }
130    _mapNode = mapNode;
131    if (_mouseCoordsTool.valid())
132        _viewer->removeEventHandler(_mouseCoordsTool.get());
133    _mouseCoordsTool = new osgEarth::Util::MouseCoordsTool(mapNode);
134    _mouseCoordsTool->addCallback(_coordsCallback.get());
135    if (_clipPlaneCullCallback.valid()) {
136        _viewer->getCamera()->removeCullCallback(_clipPlaneCullCallback.get());
137        _clipPlaneCullCallback = NULL;
138    }
139    if (_map->isGeocentric()) {
140        _clipPlaneCullCallback = new osgEarth::Util::AutoClipPlaneCullCallback(mapNode);
141        _viewer->getCamera()->addCullCallback(_clipPlaneCullCallback.get());
142    }
143    _viewer->addEventHandler(_mouseCoordsTool.get());
144    _viewer->setSceneData(_sceneRoot.get());
145    _manipulator = new osgEarth::Util::EarthManipulator;
146    _viewer->setCameraManipulator(_manipulator.get());
147    _manipulator->setNode(NULL);
148    _manipulator->setNode(_sceneRoot.get());
149    _manipulator->computeHomePosition();
150    _viewer->home();
151    _needsRedraw = true;
152}
153
154void Renderer::resetMap(osgEarth::MapOptions::CoordinateSystemType type, const char *profile)
155{
156    TRACE("Restting map with type %d, profile %s", type, profile);
157
158    osgEarth::MapOptions mapOpts;
159    mapOpts.coordSysType() = type;
160    if (profile != NULL) {
161        mapOpts.profile() = osgEarth::ProfileOptions(profile);
162    } else if (type == osgEarth::MapOptions::CSTYPE_PROJECTED) {
163        mapOpts.profile() = osgEarth::ProfileOptions("global-geodetic");
164    }
165    osgEarth::Map *map = new osgEarth::Map(mapOpts);
166    _map = map;
167    osgEarth::MapNodeOptions mapNodeOpts;
168    mapNodeOpts.enableLighting() = false;
169    osgEarth::MapNode *mapNode = new osgEarth::MapNode(map, mapNodeOpts);
170    _mapNode = mapNode;
171    _sceneRoot = mapNode;
172    if (_mouseCoordsTool.valid())
173        _viewer->removeEventHandler(_mouseCoordsTool.get());
174    _mouseCoordsTool = new osgEarth::Util::MouseCoordsTool(mapNode);
175    _mouseCoordsTool->addCallback(_coordsCallback.get());
176    _viewer->addEventHandler(_mouseCoordsTool.get());
177
178    if (_clipPlaneCullCallback.valid()) {
179        _viewer->getCamera()->removeCullCallback(_clipPlaneCullCallback.get());
180        _clipPlaneCullCallback = NULL;
181    }
182    if (_map->isGeocentric()) {
183        _clipPlaneCullCallback = new osgEarth::Util::AutoClipPlaneCullCallback(mapNode);
184        _viewer->getCamera()->addCullCallback(_clipPlaneCullCallback.get());
185    }
186    _viewer->setSceneData(_sceneRoot.get());
187    _manipulator = new osgEarth::Util::EarthManipulator;
188    _viewer->setCameraManipulator(_manipulator.get());
189    _manipulator->setNode(NULL);
190    _manipulator->setNode(_sceneRoot.get());
191    _manipulator->computeHomePosition();
192    _viewer->home();
193    _needsRedraw = true;
194}
195
196void Renderer::clearMap()
197{
198    if (_map.valid()) {
199        _map->clear();
200    }
201    _needsRedraw = true;
202}
203
204bool Renderer::mapMouseCoords(float mouseX, float mouseY, osgEarth::GeoPoint& map)
205{
206    osg::Vec3d world;
207    if (_mapNode->getTerrain()->getWorldCoordsUnderMouse(_viewer->asView(), mouseX, mouseY, world)) {
208        map.fromWorld(_mapNode->getMapSRS(), world);
209        return true;
210    }
211    return false;
212}
213
214void Renderer::addImageLayer(const char *name, const osgEarth::TileSourceOptions& opts)
215{
216    osgEarth::ImageLayerOptions layerOpts(name, opts);
217    _map->addImageLayer(new osgEarth::ImageLayer(layerOpts));
218    _needsRedraw = true;
219}
220
221void Renderer::removeImageLayer(const char *name)
222{
223    osgEarth::ImageLayer *layer = _map->getImageLayerByName(name);
224    if (layer != NULL) {
225        _map->removeImageLayer(layer);
226        _needsRedraw = true;
227    } else {
228        TRACE("Image layer not found: %s", name);
229    }
230}
231
232void Renderer::moveImageLayer(const char *name, unsigned int pos)
233{
234    osgEarth::ImageLayer *layer = _map->getImageLayerByName(name);
235    if (layer != NULL) {
236        _map->moveImageLayer(layer, pos);
237        _needsRedraw = true;
238    } else {
239        TRACE("Image layer not found: %s", name);
240    }
241}
242
243void Renderer::setImageLayerOpacity(const char *name, double opacity)
244{
245    osgEarth::ImageLayer *layer = _map->getImageLayerByName(name);
246    if (layer != NULL) {
247        layer->setOpacity(opacity);
248        _needsRedraw = true;
249    } else {
250        TRACE("Image layer not found: %s", name);
251    }
252}
253
254void Renderer::setImageLayerVisibility(const char *name, bool state)
255{
256#if OSGEARTH_MIN_VERSION_REQUIRED(2, 4, 0)
257    osgEarth::ImageLayer *layer = _map->getImageLayerByName(name);
258    if (layer != NULL) {
259        layer->setVisible(state);
260        _needsRedraw = true;
261    } else {
262        TRACE("Image layer not found: %s", name);
263    }
264#endif
265}
266
267void Renderer::addElevationLayer(const char *name, const osgEarth::TileSourceOptions& opts)
268{
269    osgEarth::ElevationLayerOptions layerOpts(name, opts);
270    _map->addElevationLayer(new osgEarth::ElevationLayer(layerOpts));
271    _needsRedraw = true;
272}
273
274void Renderer::removeElevationLayer(const char *name)
275{
276    osgEarth::ElevationLayer *layer = _map->getElevationLayerByName(name);
277    if (layer != NULL) {
278        _map->removeElevationLayer(layer);
279        _needsRedraw = true;
280    } else {
281        TRACE("Elevation layer not found: %s", name);
282    }
283}
284
285void Renderer::moveElevationLayer(const char *name, unsigned int pos)
286{
287    osgEarth::ElevationLayer *layer = _map->getElevationLayerByName(name);
288    if (layer != NULL) {
289        _map->moveElevationLayer(layer, pos);
290        _needsRedraw = true;
291    } else {
292        TRACE("Elevation layer not found: %s", name);
293    }
294}
295
296void Renderer::setElevationLayerVisibility(const char *name, bool state)
297{
298#if OSGEARTH_MIN_VERSION_REQUIRED(2, 4, 0)
299    osgEarth::ElevationLayer *layer = _map->getElevationLayerByName(name);
300    if (layer != NULL) {
301        layer->setVisible(state);
302        _needsRedraw = true;
303    } else {
304        TRACE("Elevation layer not found: %s", name);
305    }
306#endif
307}
308
309void Renderer::addModelLayer(const char *name, const osgEarth::ModelSourceOptions& opts)
310{
311    osgEarth::ModelLayerOptions layerOpts(name, opts);
312    _map->addModelLayer(new osgEarth::ModelLayer(layerOpts));
313    _needsRedraw = true;
314}
315
316void Renderer::removeModelLayer(const char *name)
317{
318    osgEarth::ModelLayer *layer = _map->getModelLayerByName(name);
319    if (layer != NULL) {
320        _map->removeModelLayer(layer);
321        _needsRedraw = true;
322    } else {
323        TRACE("Model layer not found: %s", name);
324    }
325}
326
327void Renderer::moveModelLayer(const char *name, unsigned int pos)
328{
329    osgEarth::ModelLayer *layer = _map->getModelLayerByName(name);
330    if (layer != NULL) {
331        _map->moveModelLayer(layer, pos);
332        _needsRedraw = true;
333    } else {
334        TRACE("Model layer not found: %s", name);
335    }
336}
337
338void Renderer::setModelLayerOpacity(const char *name, double opacity)
339{
340#if OSGEARTH_MIN_VERSION_REQUIRED(2, 5, 0)
341    osgEarth::ModelLayer *layer = _map->getModelLayerByName(name);
342    if (layer != NULL) {
343        layer->setOpacity(opacity);
344        _needsRedraw = true;
345    } else {
346        TRACE("Model layer not found: %s", name);
347    }
348#endif
349}
350
351void Renderer::setModelLayerVisibility(const char *name, bool state)
352{
353#if OSGEARTH_MIN_VERSION_REQUIRED(2, 4, 0)
354    osgEarth::ModelLayer *layer = _map->getModelLayerByName(name);
355    if (layer != NULL) {
356        layer->setVisible(state);
357        _needsRedraw = true;
358    } else {
359        TRACE("Model layer not found: %s", name);
360    }
361#endif
362}
363
364/**
365 * \brief Resize the render window (image size for renderings)
366 */
367void Renderer::setWindowSize(int width, int height)
368{
369    if (_windowWidth == width &&
370        _windowHeight == height) {
371        TRACE("No change");
372        return;
373    }
374
375    TRACE("Setting window size to %dx%d", width, height);
376
377    _windowWidth = width;
378    _windowHeight = height;
379    osgViewer::ViewerBase::Windows windows;
380    _viewer->getWindows(windows);
381    if (windows.size() == 1) {
382        windows[0]->setWindowRectangle(0, 0, _windowWidth, _windowHeight);
383    } else {
384        ERROR("Num windows: %lu", windows.size());
385    }
386    _needsRedraw = true;
387}
388
389/**
390 * \brief Set the orientation of the camera from a quaternion
391 * rotation
392 *
393 * \param[in] quat A quaternion with scalar part first: w,x,y,z
394 * \param[in] absolute Is rotation absolute or relative?
395 */
396void Renderer::setCameraOrientation(const double quat[4], bool absolute)
397{
398    _manipulator->setRotation(osg::Quat(quat[1], quat[2], quat[3], quat[0]));
399    _needsRedraw = true;
400}
401
402/**
403 * \brief Reset pan, zoom, clipping planes and optionally rotation
404 *
405 * \param[in] resetOrientation Reset the camera rotation/orientation also
406 */
407void Renderer::resetCamera(bool resetOrientation)
408{
409    TRACE("Enter: resetOrientation=%d", resetOrientation ? 1 : 0);
410    _viewer->home();
411    _needsRedraw = true;
412}
413
414/**
415 * \brief Perform a 2D translation of the camera
416 *
417 * x,y pan amount are specified as signed absolute pan amount in viewport
418 * units -- i.e. 0 is no pan, .5 is half the viewport, 2 is twice the viewport,
419 * etc.
420 *
421 * \param[in] x Viewport coordinate horizontal panning (positive number pans
422 * camera left, object right)
423 * \param[in] y Viewport coordinate vertical panning (positive number pans
424 * camera up, object down)
425 * \param[in] absolute Control if pan amount is relative to current or absolute
426 */
427void Renderer::panCamera(double x, double y, bool absolute)
428{
429    TRACE("Enter: %g %g, abs: %d",
430          x, y, (absolute ? 1 : 0));
431
432    _manipulator->pan(x, y);
433    _needsRedraw = true;
434}
435
436void Renderer::rotateCamera(double x, double y, bool absolute)
437{
438    TRACE("Enter: %g %g, abs: %d",
439          x, y, (absolute ? 1 : 0));
440
441    _manipulator->rotate(x, y);
442    _needsRedraw = true;
443}
444
445/**
446 * \brief Dolly camera or set orthographic scaling based on camera type
447 *
448 * \param[in] z Ratio to change zoom (greater than 1 is zoom in, less than 1 is zoom out)
449 * \param[in] absolute Control if zoom factor is relative to current setting or absolute
450 */
451void Renderer::zoomCamera(double z, bool absolute)
452{
453    TRACE("Enter: z: %g, abs: %d",
454          z, (absolute ? 1 : 0));
455
456    // FIXME: zoom here wants y mouse coords in normalized viewport coords
457
458    _manipulator->zoom(0, z);
459    _needsRedraw = true;
460}
461
462void Renderer::keyPress(int key)
463{
464    getEventQueue()->keyPress(key);
465    _needsRedraw = true;
466}
467
468void Renderer::keyRelease(int key)
469{
470    getEventQueue()->keyRelease(key);
471    _needsRedraw = true;
472}
473
474void Renderer::setThrowingEnabled(bool state)
475{
476    _manipulator->getSettings()->setThrowingEnabled(state);
477}
478
479void Renderer::mouseDoubleClick(int button, double x, double y)
480{
481    getEventQueue()->mouseDoubleButtonPress((float)x, (float)y, button);
482    _needsRedraw = true;
483}
484
485void Renderer::mouseClick(int button, double x, double y)
486{
487    getEventQueue()->mouseButtonPress((float)x, (float)y, button);
488    _needsRedraw = true;
489}
490
491void Renderer::mouseDrag(int button, double x, double y)
492{
493    getEventQueue()->mouseMotion((float)x, (float)y);
494    _needsRedraw = true;
495}
496
497void Renderer::mouseRelease(int button, double x, double y)
498{
499    getEventQueue()->mouseButtonRelease((float)x, (float)y, button);
500    _needsRedraw = true;
501}
502
503void Renderer::mouseMotion(double x, double y)
504{
505    //getEventQueue()->mouseMotion((float)x, (float)y);
506    //return;
507    osgEarth::GeoPoint map;
508    if (mapMouseCoords(x, y, map)) {
509        _coordsCallback->set(map, _viewer.get(), _mapNode);
510    } else {
511        _coordsCallback->reset(_viewer.get(), _mapNode);
512    }
513}
514
515void Renderer::mouseScroll(int direction)
516{
517    getEventQueue()->mouseScroll((direction > 0 ? osgGA::GUIEventAdapter::SCROLL_UP : osgGA::GUIEventAdapter::SCROLL_DOWN));
518    _needsRedraw = true;
519}
520
521/**
522 * \brief Set the RGB background color to render into the image
523 */
524void Renderer::setBackgroundColor(float color[3])
525{
526    _bgColor[0] = color[0];
527    _bgColor[1] = color[1];
528    _bgColor[2] = color[2];
529
530    _viewer->getCamera()->setClearColor(osg::Vec4(color[0], color[1], color[2], 1));
531
532    _needsRedraw = true;
533}
534
535/**
536 * \brief Sets flag to trigger rendering next time render() is called
537 */
538void Renderer::eventuallyRender()
539{
540    _needsRedraw = true;
541}
542
543/**
544 * \brief Get a timeout in usecs for select()
545 *
546 * If the paging thread is idle, returns <0 indicating that the
547 * select call can block until data is available.  Otherwise,
548 * if the frame render time was faster than the target frame
549 * rate, return the remaining frame time.
550 */
551long Renderer::getTimeout()
552{
553    if (!checkNeedToDoFrame())
554        // <0 means no timeout, block until socket has data
555        return -1L;
556    if (_lastFrameTime < _minFrameTime) {
557        return (long)1000000.0*(_minFrameTime - _lastFrameTime);
558    } else {
559        // No timeout (poll)
560        return 0L;
561    }
562}
563
564/**
565 * \brief Check if paging thread is quiescent
566 */
567bool Renderer::isPagerIdle()
568{
569    return (!_viewer->getDatabasePager()->requiresUpdateSceneGraph() &&
570            !_viewer->getDatabasePager()->getRequestsInProgress());
571}
572
573/**
574 * \brief Check is frame call is necessary to render and/or update
575 * in response to events or timed actions
576 */
577bool Renderer::checkNeedToDoFrame()
578{
579    return (_needsRedraw ||
580            _viewer->checkNeedToDoFrame());
581}
582
583/**
584 * \brief Cause the rendering to render a new image if needed
585 *
586 * The _needsRedraw flag indicates if a state change has occured since
587 * the last rendered frame
588 */
589bool Renderer::render()
590{
591    if (checkNeedToDoFrame()) {
592        TRACE("Enter needsRedraw=%d",  _needsRedraw ? 1 : 0);
593
594        osg::Timer_t startFrameTick = osg::Timer::instance()->tick();
595        TRACE("Before frame()");
596        _viewer->frame();
597        TRACE("After frame()");
598        osg::Timer_t endFrameTick = osg::Timer::instance()->tick();
599        _lastFrameTime = osg::Timer::instance()->delta_s(startFrameTick, endFrameTick);
600        TRACE("Frame time: %g sec", _lastFrameTime);
601#if 0
602        if (frameTime < minFrameTime) {
603            TRACE("Sleeping for %g secs", minFrameTime-frameTime);
604            OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(minFrameTime-frameTime)));
605        }
606#endif
607#ifdef WANT_TRACE
608        if (_viewer->getViewerStats() != NULL) {
609            _viewer->getViewerStats()->report(std::cerr, _viewer->getViewerStats()->getLatestFrameNumber());
610        }
611#endif
612        _needsRedraw = false;
613        return true;
614    } else
615        return false;
616}
617
618/**
619 * \brief Read back the rendered framebuffer image
620 */
621osg::Image *Renderer::getRenderedFrame()
622{
623    return _captureCallback->getImage();
624}
Note: See TracBrowser for help on using the repository browser.