欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

混合语言编程—C#使用原生的Directx和OpenGL绘图的方法

程序员文章站 2024-02-18 14:23:17
由于项目需要做一些图形展示,所以就想到了使用directx和opengl来绘图,但项目准备使用c#来开发(大家比较熟悉c#),在网上看了相关的资料,有一些第三方的控件可用,...

由于项目需要做一些图形展示,所以就想到了使用directx和opengl来绘图,但项目准备使用c#来开发(大家比较熟悉c#),在网上看了相关的资料,有一些第三方的控件可用,试用了下,一运行就占了几百m的内存,而且也不知道是否稳定,教程也少,还不如直接使用原生的。在网上看的directx和opengl的教程基本上都是c/c++的,找了很久也就找到相关介绍,只能自己研究下。

我以前做过c#和c++混合语言编程相关的东西,在c++实现一些c#不好实现的功能,c#动态调用dll文件,所以也想到了用c++的代码来控制winform控件的绘画,这样就可实现用direct和opengl在winform的控件上绘画了。

由于我对direct和opengl都不熟悉,没有这方面的编程经验,只能去瞎折腾,下面分别说说最近在directx和opengl怎么试验的。

directx:

之前没学过directx,拿了同学的代码来看,也是雾里看花啊,不过有一点启示了我,在初始化的时候,要传入一个句柄去创建设备(createdevice),通常都是传入窗口的设备,我想如果传入一个控件的句柄,那所有的绘画都将在这个控件上实现,因为控件也是继承自window的。而winform的控件在底层的实现应该和win32是一样的。这样的话只要把winform的控件的句柄传入c++代码进行初始化,那么绘画的结果将显示在这个控件上。结果一试,还真行。关键代码如下:

复制代码 代码如下:

extern "c" _declspec(dllexport) hresult initd3d( hwnd hwnd );

extern "c" _declspec(dllexport) void render();

在initd3d传入控件的句柄进行初始化,c#再调用render进行绘画,以下是c#代码:

复制代码 代码如下:

hwnd handle = this.button1.handle;

initd3d(handle);

private void draw()

  {

         for (; ; )

            {

                render();

            }

        }
 


效果图:

混合语言编程—C#使用原生的Directx和OpenGL绘图的方法

opengl:
         查看了opengl的相关教程(推荐http://www.yakergong.net/nehe/),opengl是通过rc来执行的,创建rc时就必须指定一个dc,还要设置dc的像素格式。每个线程有且只能拥有一个rc。
         如果在初始化opengl的绘画环境时传入一个winform的控件句柄,再通过这个句柄取到hdc,就可使用这个hdc来创建rc,这样opengl的绘画环境就准备好了,并且这个rc关联到winform的控件上。
         在给制前,先为当前线程选择rc(之前通过hdc创建的),再进行绘制,这样绘制的结果将显示在这个winform控件上。
         关键代码如下:
c++:

复制代码 代码如下:

extern "c" _declspec(dllexport) void init( hwnd hwnd);
extern "c" _declspec(dllexport) void render();
void init(hwnd hwnd)
{
   int pixelformat;
   int bits = 16;
   hdc = getdc(hwnd);
   static  pixelformatdescriptor pfd=           // pfd tells windows how we want things to be
   {
      sizeof(pixelformatdescriptor),              // size of this pixel format descriptor
      1,                                                            // version number
      pfd_draw_to_window |                        // format must support window
      pfd_support_opengl |                          // format must support opengl
      pfd_doublebuffer,                               // must support double buffering
      pfd_type_rgba,                                     // request an rgba format
      bits,                                                        // select our color depth
      0, 0, 0, 0, 0, 0,                                       // color bits ignored
      0,                                                         // no alpha buffer
      0,                                                         // shift bit ignored
      0,                                                        // no accumulation buffer
      0, 0, 0, 0,                                           // accumulation bits ignored
      16,                                                    // 16bit z-buffer (depth buffer)
      0,                                                     // no stencil buffer
      0,                                                     // no auxiliary buffer
      pfd_main_plane,                         // main drawing layer
      0,                                                  // reserved
      0, 0, 0                                          // layer masks ignored
   };
   pixelformat=choosepixelformat(hdc,&pfd);
   setpixelformat(hdc,pixelformat,&pfd);
   hrc=wglcreatecontext(hdc);
}
void render()
{
   wglmakecurrent(hdc, hrc);
   draw();
   swapbuffers(hdc);
   wglmakecurrent(null, null);
}

c#:
复制代码 代码如下:

init(this.picturebox1.handle);
//开始绘制
var timer = new system.timers.timer();
timer.interval = 100;
 timer.elapsed += (tsender, te) =>
                {
                    render();
                };
timer.autoreset = true;
timer.enabled = true;

效果图:

混合语言编程—C#使用原生的Directx和OpenGL绘图的方法

wpf:wpf的控件没有句柄,但是可以换个思路,把绘画代码封装在winform控件上,在wpf使用自定义的winform控件。

混合语言编程—C#使用原生的Directx和OpenGL绘图的方法