作者:boqing
经常需要在对话框上添加osg的浏览功能,一开始是仿照osgviewerMFC的例子去写,可是每次在对话框上添加此功能的时候都要重复复制很多处代码,且位置和大小控制也不是很方便。因此写了个简单的OSG Active控件解决此问题。
开发工具:vc2005
OSG版本:osg2.2
具体开发步骤:
一 建立Active工程
项目类型选择:MFC,模板选择MFC ActiveX Control
下一步的向导中保持默认,点完成
二 配置viewer
定义viewer为成员函数
osg::ref_ptr<osgViewer::Viewer>viewer;
构造函数中初始化
viewer=new osgViewer::Viewer;
为了使得其能正常显示在拖动的空间中,大小和位置与拖出区域的大小和位置一致。编写configViewer函数
#include <osgViewer/api/win32/GraphicsWindowWin32>
void COSGControlCtrl::configViewer(HWND m_hWnd)
{
RECT rect;
//得到控件的大小
::GetWindowRect(m_hWnd, &rect);
osg::ref_ptr<osg::GraphicsContext::Traits> traits = new osg::GraphicsContext::Traits;
osg::ref_ptr<osg::Referenced> windata = new osgViewer::GraphicsWindowWin32::WindowData(m_hWnd);
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;
osg::GraphicsContext* gc = osg::GraphicsContext::createGraphicsContext(traits.get());
osg::ref_ptr<osg::Camera> camera = new osg::Camera;
camera->setGraphicsContext(gc);
camera->setViewport(new osg::Viewport(traits->x, traits->y, traits->width, traits->height));
viewer.addSlave(camera.get());
}
三 添加自定义方法setSceneData
在类视图中展开OSGControlLib,右键单击_DOSGControl,选择添加->添加方法,按照下图进行填写
确定后,在类COSGControlCtrl的实现中添加以下代码:
void COSGControlCtrl::setSceneData(ULONG* data)
{
AFX_MANAGE_STATE(AfxGetStaticModuleState());
// TODO: Add your dispatch handler code here
if (!isSetSceneData)
{
configViewer(m_hWnd);
}
osg::Node *node=(osg::Node *)data;
viewer->setSceneData(node);
isSetSceneData=true;
}
isSetSceneData是类成员,构造函数中初始化为false,记录着是否曾经调用过viewer->setSceneData函数
四 写静态线程函数
在函数里主要是加入viewer.run()语句,这样的话osg的运行和程序的其它响应才能同时进行。
声明:
static UINT ThreadRun(LPVOID lparam);
实现:
UINT COSGControlCtrl::ThreadRun(LPVOID lparam)//请求状态。
{
((osgViewer::Viewer *)(lparam))->run();
return 0;
}
五 启动线程
本来想在OnInitDialog函数中启动,可是检查后发现,COSGControlCtrl类并不提供此函数的重载,因此,只好写在OnDraw函数里,因为OnDraw函数一旦当前区域移动、被遮挡等情况下都要调用,因此我们还要保证OnDraw只运行一次。
void COSGControlCtrl::OnDraw(
CDC* pdc, const CRect& rcBounds, const CRect& rcInvalid)
{
if (!pdc)
return;
// TODO: Replace the following code with your own drawing code.
static bool flag=true;
if (flag)
{
MessageBox("OnDraw");
flag=false;
if(!isSetSceneData)
{
configViewer(m_hWnd);//配置默认的viewer
viewer->setSceneData(osgDB::readNodeFile("cow.osg"));//默认数据
}
HANDLE hHandle=CreateThread(NULL,0,ThreadRun,(LPVOID)(viewer.get()),0,NULL);
CloseHandle(hHandle);
}
}
六 程序退出后结束run函数的循环
void COSGControlCtrl::OnDestroy()
{
COleControl::OnDestroy();
// TODO: Add your message handler code here
viewer->setDone(true);
Sleep(1000);
viewer->stopThreading();
}
七 测试
F7,编译通过,生成了解决方案,新打开vc,建一个对话框程序,右键点击“插入Active控件”,选择“OSGControl”,确定
在对话框上拖出一个合适的区域,Ctrl+F5,运行,结果如下:
给控件添加变量m_osg
在合适的位置调用
m_osg.setSceneData((ULONG*)(osgDB::readNodeFile("axes.osg")));
就可以改变viewer的数据了
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/yangdelong/archive/2009/07/14/4348212.aspx