一个简单的osg控件开发例子

作者: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

你可能感兴趣的:(控件开发)