将OsgEarth集成到winform中

昨天尝试了使用Qt5集成的OsgEarth,使用C++的开发人员毕竟少,而使用WinForm画界面就方便多了,如何将OsgEarth集成到WInForm中,思路如下:

使用C++封装相应的代码,提供dll接口注入winform渲染句柄的传入。

使用的OsgEarth版本3.1、.net 版本5.0。

源代码下载路径:

(8条消息) OsgEarthWrapper.7z-C++文档类资源-CSDN文库

实现的效果如下:

 

1.C++接口的封装

此处代码参考了osg的示例程序osgviewerMFC

OSGEarthWrapper.h

#pragma once
#include <windows.h>
#include <string>

#include <osgViewer/Viewer>
#include <osgViewer/ViewerEventHandlers>
#include <osgViewer/api/win32/GraphicsWindowWin32>
#include <osgGA/TrackballManipulator>
#include <osgGA/KeySwitchMatrixManipulator>
#include <osgDB/DatabasePager>
#include <osgDB/Registry>
#include <osgDB/ReadFile>
#include <osgUtil/Optimizer>

#include <osgGA/StateSetManipulator>
#include <osgEarth/EarthManipulator>
#include <osgEarth/Map>
#include <osgEarth/MapNode>
#include <osgEarth/TMS>

//#include <osgEarthDrivers/model_feature_geom/FeatureGeomModelOptions>

// 3.1 FeatureSourceFactory / OGRFeatureOptions removed ->OGRFeatureSource
//#include <osgEarthDrivers/feature_ogr/OGRFeatureOptions>
#include <osgEarth/OGRFeatureSource>

#include <osgEarthDrivers/cache_filesystem/FileSystemCache>
#include <osgEarth/EarthManipulator>
#include <osgEarth/GeodeticGraticule>
#include <osgEarth/LatLongFormatter>
#include <osgEarth/Controls>
#include <osgEarth/MouseCoordsTool>
#include <osgEarth/AutoClipPlaneHandler>
#include <osg/PositionAttitudeTransform>
#include <osg/Group>
#include <osg/Node>
#include <osgDB/ReadFile>

#include <osgEarth/ImageLayer>
#include <osgEarth/Notify>
#include <osgEarth/EarthManipulator>
#include <osgEarth/ExampleResources>
#include <osgEarth/MapNode>
//3.1ThreadingUtils ->Threading
//#include <osgEarth/ThreadingUtils>
#include <osgEarth/Threading>
#include <osgEarth/Metrics>

class OSGEarthWrapper
{
public:
	OSGEarthWrapper(HWND hWnd);
	~OSGEarthWrapper();

	void InitOSG(std::string filename);
	void InitManipulators(void);
	void InitSceneGraph(void);
	void InitCameraConfig(void);
	void PreFrameUpdate(void);
	void PostFrameUpdate(void);
	void Done(bool value) { mDone = value; }
	bool Done(void) { return mDone; }

	osg::ref_ptr<osgViewer::Viewer> getViewer() { return viewer; }
	osg::ref_ptr<osgEarth::Util::EarthManipulator> getEm() { return manip; }
	osg::ref_ptr<osg::Group> getRoot() { return mRoot; }
	osg::ref_ptr<osgEarth::Map> getMap() { return mMap; }
	osg::ref_ptr<osgEarth::MapNode> getMapNode() { return mMapNode; }

private:
	bool mDone;
	std::string m_ModelName;
	HWND m_hWnd;                             //实际需要显示的窗体句柄
	osg::ref_ptr<osgViewer::Viewer> viewer;
	osg::ref_ptr<osg::Group> mRoot;
	osg::ref_ptr<osg::Node> mModel;
	osg::ref_ptr<osgEarth::Map> mMap;
	osg::ref_ptr<osgEarth::MapNode> mMapNode;

	osg::ref_ptr < osgEarth::Util::EarthManipulator> manip;
};

class CRenderingThread : public OpenThreads::Thread
{
public:
	CRenderingThread(OSGEarthWrapper* ptr);
	CRenderingThread(OSGEarthWrapper* ptr, bool is3dThread);
	virtual ~CRenderingThread();
	void Done(bool);
	bool isEnd();
	void setOsgRuningFlag(bool);
	bool getOsgRuningState();

	virtual void run();

protected:
	OSGEarthWrapper* _ptr;
	bool _done;
	bool _is3Dthread;
	bool _osgRuningFlag;
	bool _osgRuningState;
};

OSGEarthWrapper.cpp

#include "pch.h"
#include "OSGEarthWrapper.h"

OSGEarthWrapper::OSGEarthWrapper(HWND hWnd) :
	m_hWnd(hWnd)
{
}

OSGEarthWrapper::~OSGEarthWrapper()
{
	viewer->setDone(true);
	Sleep(100);
	viewer->stopThreading();
	viewer.~ref_ptr();
	delete viewer;
}

void OSGEarthWrapper::InitOSG(std::string modelname)
{
	// Store the name of the model to load
	m_ModelName = modelname;

	// Init different parts of OSG
	InitManipulators();
	InitSceneGraph();
	InitCameraConfig();
}

void OSGEarthWrapper::InitManipulators(void)
{
}

void OSGEarthWrapper::InitSceneGraph(void)
{
	// Init the main Root Node/Group
	mRoot = new osg::Group;

	int argc = 2;
	char* argv[2];

	argv[0] = _pgmptr;
	argv[1] = (char*)m_ModelName.c_str();
	osg::ArgumentParser arguments(&argc, argv);

	// Create the viewer for this window
	viewer = new osgViewer::Viewer();

	// Load the Model from the model name
	mModel = osgEarth::Util::MapNodeHelper().load(arguments, viewer);
	if (!mModel) return;

	// Optimize the model
	osgUtil::Optimizer optimizer;
	optimizer.optimize(mModel);
	optimizer.reset();

	// Add the model to the scene
	mRoot->addChild(mModel);
}

void OSGEarthWrapper::InitCameraConfig(void)
{
	// Local Variable to hold window size data
	RECT rect;

	// Add a Stats Handler to the viewer
	viewer->addEventHandler(new osgViewer::StatsHandler);

	// Get the current window size
	::GetWindowRect(m_hWnd, &rect);

	// Init the GraphicsContext Traits
	osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;

	// Init the Windata Variable that holds the handle for the Window to display OSG in.
	osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd);

	// Setup the traits parameters
	traits->x = 0;
	traits->y = 0;
	traits->width = rect.right - rect.left;
	traits->height = rect.bottom - rect.top;
	traits->windowDecoration = false;
	traits->doubleBuffer = true;

	traits->sharedContext = 0;

	traits->setInheritedWindowPixelFormat = true;
	traits->inheritedWindowData = windata;

	// Create the Graphics Context
	osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits.get());

	// Init Master Camera for this View
	osg::ref_ptr<osg::Camera> camera = viewer->getCamera();

	// Assign Graphics Context to the Camera
	camera->setGraphicsContext(gc);

	// Set the viewport for the Camera
	camera->setViewport(new osg::Viewport(0, 0, traits->width, traits->height));

	// set the draw and read buffers up for a double buffered window with rendering going to back buffer
	camera->setDrawBuffer(GL_BACK);
	camera->setReadBuffer(GL_BACK);

	// Set projection matrix and camera attribtues
	camera->setClearMask(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
	camera->setClearColor(osg::Vec4f(0.0f, 0.0f, 0.0f, 1.0f));
	camera->setProjectionMatrixAsPerspective(
		30.0f, static_cast<double>(traits->width) / static_cast<double>(traits->height), 1.0, 1000.0);

	viewer->setCamera(camera.get());

	osgEarth::MapNode* mapNode = osgEarth::MapNode::findMapNode(mRoot);
	mMapNode = mapNode;
	osgEarth::Map* map = mapNode->getMap();
	mMap = map;
	double equatorRadius = map->getSRS()->getEllipsoid()->getRadiusEquator();
	viewer->getCamera()->addCullCallback(new osgEarth::Util::AutoClipPlaneCullCallback(mapNode));

	manip = new osgEarth::Util::EarthManipulator();
	manip->setHomeViewpoint(osgEarth::Util::Viewpoint("北京", 116.3, 39.9, 0, 0, -90, equatorRadius * 4));
	viewer->setCameraManipulator(manip);

	// Set the Scene Data
	viewer->setSceneData(mRoot);
	viewer->setThreadingModel(osgViewer::ViewerBase::ThreadingModel::SingleThreaded);

	viewer->addEventHandler(new osgViewer::StatsHandler);
	viewer->addEventHandler(new osgGA::StateSetManipulator(viewer->getCamera()->getOrCreateStateSet()));
	viewer->addEventHandler(new osgViewer::ThreadingHandler);
	viewer->addEventHandler(new osgViewer::RecordCameraPathHandler);
	viewer->addEventHandler(new osgViewer::LODScaleHandler);
	viewer->addEventHandler(new osgViewer::ScreenCaptureHandler);
	viewer->realize();
}

void OSGEarthWrapper::PreFrameUpdate()
{
	// Due any preframe updates in this routine
}

void OSGEarthWrapper::PostFrameUpdate()
{
	// Due any postframe updates in this routine
}

CRenderingThread::CRenderingThread(OSGEarthWrapper* ptr)
	: OpenThreads::Thread(), _ptr(ptr), _done(false)
{
	_osgRuningFlag = true;
	_osgRuningState = true;
}
CRenderingThread::CRenderingThread(OSGEarthWrapper* ptr, bool is3dThread)
	: OpenThreads::Thread(), _ptr(ptr), _done(false)
{
	_is3Dthread = is3dThread;
	_osgRuningFlag = true;
	_osgRuningState = true;
}

CRenderingThread::~CRenderingThread()
{
	_done = true;
	if (isRunning())
	{
		cancel();
		join();
	}
}

void CRenderingThread::Done(bool flag)
{
	_done = flag;
}

void  CRenderingThread::setOsgRuningFlag(bool b)
{
	_osgRuningFlag = b;
}

bool  CRenderingThread::getOsgRuningState()
{
	return _osgRuningState;
}
bool CRenderingThread::isEnd()
{
	osgViewer::Viewer* viewer = _ptr->getViewer();
	if (!testCancel() && !viewer->done() && !_done)
		return false;
	else
		return true;
}

void CRenderingThread::run()
{
	if (!_ptr)
	{
		_done = true;
		return;
	}

	osgViewer::Viewer* viewer = _ptr->getViewer();
	do
	{
		if (_osgRuningFlag)
		{
			_ptr->PreFrameUpdate();
			viewer->frame();
			_ptr->PostFrameUpdate();
			_osgRuningState = true;
		}
		else
		{
			_osgRuningState = false;
			Sleep(5);
		}
	} while (!testCancel() && !viewer->done() && !_done);
}

提供对外的DLL入口:

#pragma once
extern "C"
{
	//传入控件句柄,初始化控件为OSG三维显示
	NativeExport int InitOsgEarth(HWND _hwnd);
	//销毁OSG渲染窗口
	NativeExport int DestroyOsgEarth();
};
#include "pch.h"
#include "api.h"
#include "OSGEarthWrapper.h"
//窗口全局唯一变量
OSGEarthWrapper* mOSG = nullptr;
//渲染线程全局变量
CRenderingThread* mThreadHandle = nullptr;

NativeExport int InitOsgEarth(HWND _hwnd)
{
	//通过传入的句柄初始化cOSG对象
	mOSG = new OSGEarthWrapper(_hwnd);
	mOSG->InitOSG("simple.earth");

	//创建渲染线程并开始渲染
	mThreadHandle = new CRenderingThread(mOSG);
	mThreadHandle->start();

	return 0;
}

NativeExport int DestroyOsgEarth()
{
	if (mThreadHandle != nullptr)
	{
		mThreadHandle->Done(true);
		while (!mThreadHandle->isEnd())
		{
			Sleep(10);
		}
		delete mThreadHandle;
		mThreadHandle = nullptr;
	}
	if (mOSG != 0)
	{
		delete mOSG;
		mOSG = nullptr;
	}
	return 2;
}

2.DotNet客户端的调用

  public partial class Form1 : Form
    {
        [DllImport("OsgEarthWrapper.dll", EntryPoint = "InitOsgEarth", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern int InitOsgEarth(IntPtr x);

        [DllImport("OsgEarthWrapper.dll", EntryPoint = "DestroyOsgEarth", CharSet = CharSet.Auto, CallingConvention = CallingConvention.Cdecl)]
        public static extern int DestroyOsgEarth();

        public Form1()
        {
            InitializeComponent();
            this.Load += Form1_Load;

            this.FormClosed += Form1_FormClosed;
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            DestroyOsgEarth();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            IntPtr ptr = this.MapPanel.Handle;
            InitOsgEarth(ptr);
        }
    }

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值