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

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

Add method to set model layer opacity

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