[osg-users] Synchronizing with textures uploads.

Altin Gjata altingjataj at gmail.com
Thu Mar 8 07:19:14 PST 2018


Just an update. Calling setDataVariance(osg::Object::DYNAMIC), either (or both) in quad's StateSet or in the texture itself doesn't seem to have any affect.

In SingleThreaded mode it works OK. 

If the driver uses triple buffering, can I do anything to disable it?

I'm using OSG 3.5.6. I understand that it's neither the stable release nor the most updated development release, but it's the version that vcpkg installs.
Maybe this is all irrelevant.

The content of the entire source file is below, including the commented out hacks.

Code:

#include "StdAfx.h"
#include <osgViewer/Renderer>
#include "Viewer.h"
#include "../sciter/Window.h"
#include "../opencv/feature_detector.h"


osg::Matrix to_osg_Matrix(cv::Matx44d const& rhs) {
	osg::Matrix		lhs{}; // identity
	for (int row = 0; 4 > row; ++row)
		for (int col = 0; 4 > col; ++ col)
			lhs(row, col) = rhs(row, col);
	return lhs;
}



Viewer::Viewer(osg::ArgumentParser& arguments)
	:	BaseClass(arguments)
	,	circularFrameBuffer_(2) // 2 element capacity
{
	logging::fmt_print("{} >> Viewer\n", cclock::now());
	configure();
}

Viewer::Viewer(int argc, char* argv[])
	:	Viewer(osg::ArgumentParser(&argc, argv))
{
}

Viewer::~Viewer() {
	release_pending_frames();
	logging::fmt_print("{} << Viewer\n", cclock::now());
}



void Viewer::on_frame(frame_stream_t frame_stream) {
	concurrentFrameQueue_.push(frame_stream);
}



int Viewer::run () {
    setReleaseContextAtEndOfFrameHint(false); // copied from osgViewer::Viewer

	// copied from ViewerBase
    if (!isRealized())
    {
        realize();
    }

    const char* run_frame_count_str = getenv("OSG_RUN_FRAME_COUNT");
    unsigned int runTillFrameNumber = run_frame_count_str==0 ? osg::UNINITIALIZED_FRAME_NUMBER : atoi(run_frame_count_str);

    while(!done() && (run_frame_count_str==0 || getViewerFrameStamp()->getFrameNumber()<runTillFrameNumber))
    {
		//SDL_Delay(100);
		upload_video_frame();
		//SDL_Delay(1000);
		use_and_release_video_frame();
		//SDL_Delay(1000);
        double minFrameTime = _runMaxFrameRate>0.0 ? 1.0/_runMaxFrameRate : 0.0;
        osg::Timer_t startFrameTick = osg::Timer::instance()->tick();
        if (_runFrameScheme==ON_DEMAND)
        {
            if (checkNeedToDoFrame())
            {
                frame();
            }
            else
            {
                // we don't need to render a frame but we don't want to spin the run loop so make sure the minimum
                // loop time is 1/100th of second, if not otherwise set, so enabling the frame microSleep below to
                // avoid consume excessive CPU resources.
                if (minFrameTime==0.0) minFrameTime=0.01;
            }
        }
        else
        {
            frame();
        }

        // work out if we need to force a sleep to hold back the frame rate
        osg::Timer_t endFrameTick = osg::Timer::instance()->tick();
        double frameTime = osg::Timer::instance()->delta_s(startFrameTick, endFrameTick);
        if (frameTime < minFrameTime) OpenThreads::Thread::microSleep(static_cast<unsigned int>(1000000.0*(minFrameTime-frameTime)));
    }


	release_pending_frames();
    return 0;
}


/* Copied from ViewerBase */
void Viewer::frame(double simulationTime) {
    if (_done) return;

    // OSG_NOTICE<<std::endl<<"CompositeViewer::frame()"<<std::endl<<std::endl;

    if (_firstFrame)
    {
        viewerInit();

        if (!isRealized())
        {
            realize();
        }

        _firstFrame = false;
    }
    advance(simulationTime);

    eventTraversal();
    updateTraversal();
	//circular_swap_frames_.push_back(true);
	renderingTraversals();
}


//void Viewer::prerender_uploaded_frame() {
//    Contexts contexts;
//    getContexts(contexts);
//
//    // check to see if windows are still valid
//    checkWindowStatus(contexts);
//    if (_done) return;
//
//    double beginRenderingTraversals = elapsedTime();
//
//    osg::FrameStamp* frameStamp = getViewerFrameStamp();
//    unsigned int frameNumber = frameStamp ? frameStamp->getFrameNumber() : 0;
//
//
//    Scenes scenes;
//    getScenes(scenes);
//
//    for(Scenes::iterator sitr = scenes.begin();
//        sitr != scenes.end();
//        ++sitr)
//    {
//        osgViewer::Scene* scene = *sitr;
//        if (!scene) continue;
//
//        osgDB::DatabasePager* dp = scene->getDatabasePager();
//        if (dp) dp->signalBeginFrame(frameStamp);
//
//        osgDB::ImagePager* ip = scene->getImagePager();
//        if (ip) ip->signalBeginFrame(frameStamp);
//
//        if (scene->getSceneData())
//        {
//            // fire off a build of the bounding volumes while we
//            // are still running single threaded.
//            scene->getSceneData()->getBound();
//        }
//    }
//
//    // OSG_NOTICE<<std::endl<<"Start frame"<<std::endl;
//
//
//    Cameras cameras;
//    getCameras(cameras);
//
//    Contexts::iterator itr;
//
//    bool doneMakeCurrentInThisThread = false;
//
//    if (_endDynamicDrawBlock.valid())
//    {
//        _endDynamicDrawBlock->reset();
//    }
//
//    // dispatch the rendering threads
//    if (_startRenderingBarrier.valid()) _startRenderingBarrier->block();
//
//    // reset any double buffer graphics objects
//    for(Cameras::iterator camItr = cameras.begin();
//        camItr != cameras.end();
//        ++camItr)
//    {
//        osg::Camera* camera = *camItr;
//        osgViewer::Renderer* renderer = dynamic_cast<osgViewer::Renderer*>(camera->getRenderer());
//        if (renderer)
//        {
//            if (!renderer->getGraphicsThreadDoesCull() && !(camera->getCameraThread()))
//            {
//                renderer->cull();
//            }
//        }
//    }
//
//    for(itr = contexts.begin();
//        itr != contexts.end() && !_done;
//        ++itr)
//    {
//        if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
//        {
//            doneMakeCurrentInThisThread = true;
//            makeCurrent(*itr);
//            (*itr)->runOperations();
//        }
//    }
//
//    // OSG_NOTICE<<"Joing _endRenderingDispatchBarrier block "<<_endRenderingDispatchBarrier.get()<<std::endl;
//
//    // wait till the rendering dispatch is done.
//    if (_endRenderingDispatchBarrier.valid()) _endRenderingDispatchBarrier->block();
//
//    for(itr = contexts.begin();
//        itr != contexts.end() && !_done;
//        ++itr)
//    {
//        if (!((*itr)->getGraphicsThread()) && (*itr)->valid())
//        {
//            doneMakeCurrentInThisThread = true;
//            makeCurrent(*itr);
//            //(*itr)->swapBuffers();
//			//glFlush();
//        }
//    }
//
//    for(Scenes::iterator sitr = scenes.begin();
//        sitr != scenes.end();
//        ++sitr)
//    {
//        osgViewer::Scene* scene = *sitr;
//        if (!scene) continue;
//
//        osgDB::DatabasePager* dp = scene->getDatabasePager();
//        if (dp) dp->signalEndFrame();
//
//        osgDB::ImagePager* ip = scene->getImagePager();
//        if (ip) ip->signalEndFrame();
//    }
//
//    // wait till the dynamic draw is complete.
//    if (_endDynamicDrawBlock.valid())
//    {
//        // osg::Timer_t startTick = osg::Timer::instance()->tick();
//        _endDynamicDrawBlock->block();
//        // OSG_NOTICE<<"Time waiting "<<osg::Timer::instance()->delta_m(startTick, osg::Timer::instance()->tick())<<std::endl;;
//    }
//
//    if (_releaseContextAtEndOfFrameHint && doneMakeCurrentInThisThread)
//    {
//        //OSG_NOTICE<<"Doing release context"<<std::endl;
//        releaseContext();
//    }
//
//    _requestRedraw = false;
//}


void Viewer::upload_video_frame() {
	frame_stream_t frameStream;
	if (concurrentFrameQueue_.try_pop(frameStream)) {
		auto frame = std::get<0>(frameStream);
		auto imageStream = std::get<1>(frameStream);
		// set image buffer and dirty flag
		imageStream->setImage(frame);
		//if (auto gc = bg_image_camera_->getGraphicsContext()) {
		//	if (auto go = bg_image_camera_->getRenderer()) {
		//		(*go)(gc);
		//	}
		//}
		// signal to draw the 3D scene
		//osg::ref_ptr<osg::Node> sd = getSceneData();
		//auto mm = sd->getNodeMask();
		//sd->setNodeMask(0);
		//circular_swap_frames_.push_back(false);
		////renderingTraversals();
		//prerender_uploaded_frame();
		//sd->setNodeMask(mm);
		//logging::fmt_print("frame:{:n}\n", frame->ccc);
		circularFrameBuffer_.push_back(frameStream);
	}
}
void Viewer::use_and_release_video_frame() {
	if (!circularFrameBuffer_.empty()) {
		frame_stream_t	frameStream = circularFrameBuffer_.front();
		circularFrameBuffer_.pop_front();
		auto frame = std::get<0>(frameStream);
		update_tracked_objects(frame);
		//dbg_show_colored_plane(frame->dbg_color_);
		async_finished(frame);
		requestRedraw();
	}
}



void Viewer::update_tracked_objects(frame_t frame) {
	if (auto frameData = dynamic_cast<FeatureDetector::FrameData*>(frame->data.get())) {
		for (auto& matched_pattern: frameData->matched_patterns) {
			if (tracked_) {
				tracked_->setMatrix(to_osg_Matrix(matched_pattern->transform()));
			}
			break;
		}
	}
}


void Viewer::release_pending_frames() {
	frame_stream_t frame_stream;
	while (!circularFrameBuffer_.empty()) {
		frame_stream = circularFrameBuffer_.front();
		circularFrameBuffer_.pop_front();
		async_finished(std::get<0>(frame_stream));
	}
	while (concurrentFrameQueue_.try_pop(frame_stream)) {
		async_finished(std::get<0>(frame_stream));
	}
}


void Viewer::dbg_show_colored_plane(int val) {
	if (0 <= val) {
		float red = (float)val / 255.0;
		if (!dbgPlane) {
			if (auto root = dynamic_cast<osg::Group*>(getSceneData())) {
				const float width = 5, height = 5, distance = -20;
				dbgPlane = osg::createTexturedQuadGeometry(
					osg::Vec3(-width / 2 - 4, height / 2 + 4, distance), osg::Vec3(width, 0, 0), osg::Vec3(0, -height, 0), 0, 0, 1, 1);
				dbgPlane->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF | osg::StateAttribute::PROTECTED);
			root->addChild(dbgPlane);
			}
		}
		if (dbgPlane) {
			osg::Vec4Array* colours = new osg::Vec4Array(1);
			(*colours)[0].set(red,0.0f,0.0, 1);
			dbgPlane->setColorArray(colours, osg::Array::BIND_OVERALL);
		}
	} else if (dbgPlane) {
		if (auto root = dynamic_cast<osg::Group*>(getSceneData())) {
			root->removeChild(dbgPlane);
			dbgPlane = nullptr;
		}
	}
}



/*
**-----------------------------------------------------------------------------
**
**-----------------------------------------------------------------------------
*/

class RenderGUIEventHandler : public osgGA::GUIEventHandler
{
public:
	RenderGUIEventHandler(Viewer *viewer)
		:	viewer_(viewer)
	{}
	~RenderGUIEventHandler() {
	}
	// osgGA::GUIEventHandler:
	bool handle(const osgGA::GUIEventAdapter& ea, osgGA::GUIActionAdapter& aa) override {
		switch (ea.getEventType()) {
		case	osgGA::GUIEventAdapter::KEYDOWN:
			switch (ea.getKey()) {
			case	osgGA::GUIEventAdapter::KEY_F8:
				++viewer_->resizing_mode_;
				viewer_->resizeViewports();
				return true;
			}
			break;
		}
		return	false;
	}

private:
	Viewer	*viewer_;
};




void Viewer::configure() {
	// https://groups.google.com/forum/#!topic/osg-users/s8ESNvqtfag
	osgDB::setLibraryFilePathList(".;D:/programing/vcpkg/installed/x86-windows/tools/osg/osgPlugins-3.5.6");
	osgDB::setDataFilePathList(".;D:/programing/sdk/OSG/OpenSceneGraph-Data;D:/programing/sdk/OSG/data");

	//osg::DisplaySettings::instance()->setNumMultiSamples(4);

	auto main_camera = getCamera();
	main_camera->setClearMask(GL_DEPTH_BUFFER_BIT);

	// 'F7' - cycle between stats
	osg::ref_ptr<osgViewer::StatsHandler>	statsHandler = new osgViewer::StatsHandler();
	statsHandler->setKeyEventTogglesOnScreenStats(osgGA::GUIEventAdapter::KEY_F7);
	addEventHandler(statsHandler);
	// 'F11' - fullscreen / windowed
	osg::ref_ptr<osgViewer::WindowSizeHandler>	sizeHandler = new osgViewer::WindowSizeHandler();
	sizeHandler->setKeyEventToggleFullscreen(osgGA::GUIEventAdapter::KEY_F11);
	addEventHandler(sizeHandler);

	addEventHandler(new RenderGUIEventHandler{this});

	// disable closing window with Esc
	setKeyEventSetsDone(0);


	setRunFrameScheme(osgViewer::Viewer::ON_DEMAND);
	//setRunMaxFrameRate(30);
	setThreadingModel(osgViewer::Viewer::SingleThreaded);
}



osg::ref_ptr<osg::Geometry> Viewer::createTexturedQuadGeometry(const osg::Vec3& pos,float width,float height,
	osg::ref_ptr<osg::Image> image,	bool useTextureRectangle, bool xyPlane, bool option_flip)
{
    bool flip = image->getOrigin()==osg::Image::TOP_LEFT;
    if (option_flip) flip = !flip;

    if (useTextureRectangle)
    {
        osg::ref_ptr<osg::Geometry> pictureQuad = osg::createTexturedQuadGeometry(pos,
                                           osg::Vec3(width,0.0f,0.0f),
                                           xyPlane ? osg::Vec3(0.0f,height,0.0f) : osg::Vec3(0.0f,0.0f,height),
                                           0.0f, flip ? image->t() : 0.0, image->s(), flip ? 0.0 : image->t());

        osg::ref_ptr<osg::TextureRectangle> texture = new osg::TextureRectangle(image);
        texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
        texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);


        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
                                                                        texture,
                                                                        osg::StateAttribute::ON);

        return pictureQuad;
    }
    else
    {
        osg::ref_ptr<osg::Geometry> pictureQuad = osg::createTexturedQuadGeometry(pos,
                                           osg::Vec3(width,0.0f,0.0f),
                                           xyPlane ? osg::Vec3(0.0f,height,0.0f) : osg::Vec3(0.0f,0.0f,height),
                                           0.0f, flip ? 1.0f : 0.0f , 1.0f, flip ? 0.0f : 1.0f);

        osg::ref_ptr<osg::Texture2D> texture = new osg::Texture2D(image);
        texture->setResizeNonPowerOfTwoHint(false);
        texture->setFilter(osg::Texture::MIN_FILTER,osg::Texture::LINEAR);
        texture->setWrap(osg::Texture::WRAP_S, osg::Texture::CLAMP_TO_EDGE);
        texture->setWrap(osg::Texture::WRAP_T, osg::Texture::CLAMP_TO_EDGE);


        pictureQuad->getOrCreateStateSet()->setTextureAttributeAndModes(0,
                    texture,
                    osg::StateAttribute::ON);

        return pictureQuad;
    }
}


osg::ref_ptr<osg::Camera> Viewer::create_display_image_camera(osg::View& view,
	osg::ref_ptr<osg::Drawable> video_quad, bool b_background)
{
	const osg::BoundingBox& bb = video_quad->getBoundingBox();

	osg::ref_ptr<osg::Camera> image_camera{new osg::Camera{}};

	image_camera->setReferenceFrame(osg::Camera::ABSOLUTE_RF);
	image_camera->setAllowEventFocus(false);

	image_camera->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF);

	image_camera->setGraphicsContext(view.getCamera()->getGraphicsContext());
	image_camera->setViewport(view.getCamera()->getViewport());

	//image_camera->setViewMatrix(osg::Matrixd::identity());
	image_camera->setProjectionMatrix(osg::Matrix::ortho2D(bb.xMin(), bb.xMax(), bb.yMin(), bb.yMax()));

	if (b_background) {
		image_camera->setRenderOrder(osg::Camera::PRE_RENDER);
		image_camera->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::OFF);
		//image_camera->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		//image_camera->setClearMask(0);
		image_camera->setClearColor(osg::Vec4(.3f, 0.4f, 0.5f, 1.f));
	} else {
		image_camera->setRenderOrder(osg::Camera::POST_RENDER);
		image_camera->getOrCreateStateSet()->setMode(GL_BLEND, osg::StateAttribute::ON);
		image_camera->setClearMask(GL_DEPTH_BUFFER_BIT);
	}

	image_camera->addChild(video_quad);
	view.addSlave(image_camera, false);

	return image_camera;
}


void Viewer::cameraSetGraphicsContext(osg::Camera* camera, osg::GraphicsContext* gc) {
	if (camera && gc) {
		camera->setGraphicsContext(gc);

		double fovy, aspectRatio, zNear, zFar;
		camera->getProjectionMatrixAsPerspective(fovy, aspectRatio, zNear, zFar);

		osg::GraphicsContext::Traits const *traits = gc->getTraits();
		double newAspectRatio = double(traits->width) / double(traits->height);
		double aspectRatioChange = newAspectRatio / aspectRatio;
		if (aspectRatioChange != 1.0)
		{
			camera->getProjectionMatrix() *= osg::Matrix::scale(1.0/aspectRatioChange,1.0,1.0);
		}

		camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));

		GLenum buffer = traits->doubleBuffer ? GL_BACK : GL_FRONT;

		camera->setDrawBuffer(buffer);
		camera->setReadBuffer(buffer);
	}
}


class DrawSciterAndSwap : public osg::GraphicsContext::SwapCallback
{
public:
	DrawSciterAndSwap(Viewer& viewer, std::shared_ptr<Window> window)
		:	viewer_(viewer), window_(window)
	{}
private:
	void swapBuffersImplementation(osg::GraphicsContext* gc) override {
		//bool bSwap = viewer_.circular_swap_frames_.front();
		//viewer_.circular_swap_frames_.pop_front();
		//if (bSwap) {
			glFlush(); // flickering happens without this
			if (auto win = window_.lock()) {
				win->drawWithOpenGL();
			}
			gc->swapBuffersImplementation();
		//}
	}

	Viewer&							viewer_;
	std::weak_ptr<Window>			window_;
};



class GraphicsContextResizedCallback : public osg::GraphicsContext::ResizedCallback
{
public:
	GraphicsContextResizedCallback(Viewer *viewer)
		:	viewer_(viewer)
	{}
	~GraphicsContextResizedCallback() {}
private:
	// osg::GraphicsContext::ResizedCallback:
	void resizedImplementation(osg::GraphicsContext *gc, int x, int y, int width, int height) override {
		if (viewer_) {
			viewer_->resizeViewports(width, height);
			auto traits = const_cast<osg::GraphicsContext::Traits*>(gc->getTraits());
			traits->x = x;
			traits->y = y;
			traits->width = width;
			traits->height = height;
		} else {
			gc->resizedImplementation(x, y, width, height);
		}
	}

	Viewer		*viewer_;
};


void Viewer::setGraphicsContext(std::shared_ptr<Window> window) {
	auto graphicsContext = window->getGraphicsContext();
	cameraSetGraphicsContext(getCamera(), graphicsContext);
	graphicsContext->setSwapCallback(new DrawSciterAndSwap(*this, window));

	std::vector<osg::GraphicsContext*>	contexts;
	getContexts(contexts);
	for (auto ctx: contexts) {
		ctx->setClearColor(osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
		ctx->setClearMask(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
		ctx->setResizedCallback(new GraphicsContextResizedCallback(this));
	}

	//main_camera->setProjectionResizePolicy(osg::Camera::ProjectionResizePolicy::FIXED);
	//if (auto gw = dynamic_cast<osgViewer::GraphicsWindow*>(main_camera->getGraphicsContext())) {
	//	gw->setSyncToVBlank(false);
	//}
}


class BgImageResizedCallback : public osg::Image::DimensionsChangedCallback
{
public:
	BgImageResizedCallback(Viewer& viewer)
		:	viewer_(viewer)
	{
	}
	void operator()(osg::Image* image) override {
		viewer_.create_or_update_image_scene(image);
	}
	Viewer& viewer_;
};



void Viewer::create_or_update_image_scene(osg::ref_ptr<osg::Image> image) {
	if (image) {
		if (image != bg_image_) {
			if (bg_image_) {
				bg_image_->removeDimensionsChangedCallback(bg_image_resized_callback_);
			}
			bg_image_ = image;
			if (!bg_image_resized_callback_)
				bg_image_resized_callback_ = new BgImageResizedCallback(*this);
			bg_image_->addDimensionsChangedCallback(bg_image_resized_callback_);
			if (osg::ImageStream *imageStream = dynamic_cast<osg::ImageStream*>(image.get())) {
				imageStream->play();
			}
		}
		float	width = image->s() * image->getPixelAspectRatio();
		float	height = image->t();
		float xMin = 0.f, xMax = 0.f, yMin = 0.f, yMax = 0.f;
		if (auto geom = dynamic_cast<osg::Geometry*>(bg_image_quad_.get())) {
			if (auto coords = dynamic_cast<osg::Vec3Array*>(geom->getVertexArray())) {
				(*coords)[2].x() = width;
				(*coords)[3].x() = width;
				(*coords)[0].y() = height;
				(*coords)[3].y() = height;
				xMin = (*coords)[1].x();
				yMin = (*coords)[1].y();
				xMax = (*coords)[3].x();
				yMax = (*coords)[3].y();
				coords->dirty();
			}
			if (auto tcoords = dynamic_cast<osg::Vec2Array*>(geom->getTexCoordArray(0))) {
				bool flip = image->getOrigin()==osg::Image::TOP_LEFT;
				float	l = 0.0f,
						b = flip ? image->t() : 0.0,
						r = image->s(),
						t = flip ? 0.0 : image->t()
					;
				(*tcoords)[0].set(l, t);
				(*tcoords)[1].set(l, b);
				(*tcoords)[2].set(r, b);
				(*tcoords)[3].set(r, t);
				tcoords->dirty();
			}
			geom->dirtyGLObjects();
			geom->dirtyBound();
			if (bg_image_camera_) {
				bg_image_camera_->setProjectionMatrix(osg::Matrix::ortho2D(xMin, xMax, yMin, yMax));
			}
			if (fg_image_camera_) {
				bg_image_camera_->setProjectionMatrix(osg::Matrix::ortho2D(xMin, xMax, yMin, yMax));
			}
			resizeViewports();
		} else if (0 < width && 0 < height)
		{
			bg_image_quad_ = createTexturedQuadGeometry(osg::Vec3(), width, height, image, true, true, false);
			if (auto state = bg_image_quad_->getStateSet()) {
				// as explained here: http://forum.openscenegraph.org/viewtopic.php?t=9004
				// DYNAMIC has effect only when applied to StateSet or Drawable
				// apparently DYNAMIC hurt performance, as said here:
				// https://wiki.openmw.org/index.php?title=Rendering_Architecture
				state->setDataVariance(osg::Object::DYNAMIC);
				if (osg::ref_ptr<osg::Texture> texture = dynamic_cast<osg::Texture*>(state->getTextureAttribute(0, osg::StateAttribute::TEXTURE))) {
					if (auto myImg = dynamic_cast<ImageStream*>(texture->getImage(0))) {
						texture->setDataVariance(osg::Object::DYNAMIC);
					}
				}
			}
			bg_image_camera_ = create_display_image_camera(*this, bg_image_quad_, true);
			//fg_image_camera_ = create_display_image_camera(*this, bg_image_quad_, false);
			resizeViewports();
		}
	}
}


void Viewer::resizeViewports(int availWidth, int availHeight) {
	if (0 > availWidth || 0 > availHeight) {
		std::vector<osg::GraphicsContext*>	contexts;
		getContexts(contexts);
		if (contexts.empty())
			return;
		//assert(0 < contexts.size());
		auto traits = contexts[0]->getTraits();
		availWidth = traits->width;
		availHeight = traits->height;
	}

	if (!bg_image_)
		return;
	//assert(bg_image_);
    float imgWidth = bg_image_->s() * bg_image_->getPixelAspectRatio();
    float imgHeight = bg_image_->t();
	if (0 >= imgWidth || 0 >= imgHeight) {
		imgWidth = 128.f;
		imgHeight = 64.f;
	}

	double imgAspectRatio = imgWidth / imgHeight;
	double availAspectRatio = (double)availWidth / availHeight;

	float vpX, vpY, vpWidth, vpHeight;

	switch (resizing_mode_) {
	case	kOriginalSize:
		vpWidth = imgWidth;
		vpHeight = imgHeight;
		break;
	case	kFitWindow:
		vpWidth = availWidth;
		vpHeight = availHeight;
		break;
	case	kMaintainAspectRatio:
		if (imgAspectRatio < availAspectRatio) {
			vpHeight = availHeight;
			vpWidth = vpHeight * imgAspectRatio;
		} else {
			vpWidth = availWidth;
			vpHeight = vpWidth / imgAspectRatio;
		}
		break;
	}
	vpX = (availWidth - vpWidth)  / 2.0;
	vpY = (availHeight - vpHeight) / 2.0;

	std::vector<osg::Camera*>	cameras;
	cameras.push_back(getCamera());
	if (bg_image_camera_) cameras.push_back(bg_image_camera_);
	if (fg_image_camera_) cameras.push_back(fg_image_camera_);
	for (auto camera : cameras) {
		if (auto viewport = camera->getViewport()) {
			viewport->setViewport(vpX, vpY, vpWidth, vpHeight);
		}
	}
	if (auto camera = getCamera()) {
		double fovy, aspectRatio, zNear, zFar;
		camera->getProjectionMatrixAsPerspective(fovy, aspectRatio, zNear, zFar);
		camera->setProjectionMatrixAsPerspective(fovy, imgAspectRatio, zNear, zFar);
	}
}








... 

Thank you!

Cheers,
Altin[/code]

------------------
Read this topic online here:
http://forum.openscenegraph.org/viewtopic.php?p=73049#73049







More information about the osg-users mailing list