Max GAME

这是一种对 3dsmax 的改造方法,可以作为制作Game Editor 的另一种参考方案:

选择 Views/Extended/Game 将进入自定义的渲染视图,右击菜单可以返回常规视图,或者通过Viewport Config也可以返回;

3dsmax允许创建自己的视图窗口,你可以从ViewWindow类继承,然后使用COREInterface 注册视图;要求实现几个纯虚函数

     class GameViewWindow:public ViewWindow

     {

         //返回的名字,就是在Views/Extended中看到的名字

          MCHAR *GetName(){return "Game";}

          //在这里创建你自己的渲染窗口,一般使用WS_CHILD创建,如果你希望包含自己的菜单,可以使用对话框模版实现,这是惟一可以包含菜单又可以作为子窗口的方式

          //然后响应父窗口的WM_SIZE和WM_MOVE来调整它;另外,如果使用OpenGL,请注意使用独立线程;防止3dsmax 使用opengl窗口时发生混乱; 

          HWND CreateViewWindow(HWND hParent, int x, int y, int w, int h);

          //切换视图时会导致Destroy 发生,传入的hWnd就是你自己创建的那个窗口的句柄

          void DestroyViewWindow(HWND hWnd); 

          ...

     }

     在插件dll被初始化的时候注册视图:

     GetCOREInterface()->RegisterViewWindow(&vw);

     从上面看到,按照3dsmax 的协议,创建了自己的渲染窗口,基本上可以为所欲为了,因为在dll中和在宿主exe中的控制能力没有什么区别;

     另外采取hook 手段,可以完全控制宿主3dsmax的行为,因为3dsmax 框架是基于纯虚函数实现的,hook纯虚函数是一件很容易的实际,然后

     就可以在hook后的函数中做各种各样的事情:),这个方法已经试验成功,由于时间关系,这个话题将在后续的blog中写。

 

static GameViewWindow gvw;

Interface* f = 0;

LRESULT WINAPI __DefWindowProc(HWND hWnd,UINT Msg,WPARAM wParam,LPARAM lParam)
{
     PAINTSTRUCT ps;
     HDC hdc;
 
     RECT area;
     GraphicsWindow* gw;
     HMENU hMenu,HMenuView;
     HINSTANCE hBase;
 
     switch( Msg )
     {
          case WM_LBUTTONDOWN:
          {
               HWND hwnd1 = f->GetActiveViewport()->GetHWnd();
               HWND hwnd2 = ::GetParent( hWnd );
               if(hwnd1!=hWnd)
               { 
                    f->MakeExtendedViewportActive( hWnd ); 
               } 
          }
          break;
          case WM_RBUTTONUP:
          {
               hBase = ::GetModuleHandle( 0 );
               hMenu = ::LoadMenu( theApp.m_hInstance,MAKEINTRESOURCE(IDR_MENU1));
               HMenuView = ::GetSubMenu( hMenu,0);
               DWORD fwKeys = wParam; 
               POINT pt;
               pt.x= LOWORD(lParam); 
               pt.y = HIWORD(lParam);
    
               f->PutUpViewMenu( hWnd,pt);

               ::TrackPopupMenu( HMenuView,0,pt.x,pt.y,0,hWnd,&area);
          }
          break;
          case WM_COMMAND:
          {
               DWORD type = HIWORD(wParam);
               DWORD id = LOWORD(wParam);
               if(  type == 0 )
               {
                    switch(id)
                    {
                         case ID_FILE_CLOSE:
                         break;
                    }
               }
          break;
          }
          case WM_PAINT:  
          break;
          case WM_SIZE:
          {

               int cx = LOWORD( lParam );
               int cy = HIWORD( lParam );
               glMatrixMode( GL_PROJECTION );
               glLoadIdentity();
               ::gluPerspective(90,1,1,100000.f);
               glViewport(0,0,cx,cy);
               glMatrixMode( GL_MODELVIEW);

               Eng_Resize( cx, cy);
          }
          break;
     }
     return ::DefWindowProc( hWnd,Msg,wParam,lParam);
}

struct CreateStruct
{
     DWORD dwExStyle;
     DWORD style;
     int x;
     int y;
     int w;
     int h;
     HWND hParent;
     HINSTANCE hInst;
     HWND hWnd;

     volatile int lock;
};

class GameViewWindow : public ViewWindow
{
public:
     int m_bClose;
     HWND m_hWnd;
     HGLRC m_hrc;
     HANDLE m_hThread;
     DWORD m_dwThreadID;
 
     MCHAR *GetName(){return "Game";}
     virtual int NumberCanCreate() { return 1; }
     HWND CreateViewWindow(HWND hParent, int x, int y, int w, int h);
     void DestroyViewWindow(HWND hWnd); 
     BOOL CanCreate();
};

void start_address( void * p )
{
     CreateStruct* cs = (CreateStruct*)p;
     gvw.m_dwThreadID = ::GetCurrentThreadId();

     cs->lock = gvw.m_dwThreadID - gvw.m_dwThreadID;
     HDC hdc = ::GetDC(gvw.m_hWnd);

     PIXELFORMATDESCRIPTOR pfd = { 
          sizeof(PIXELFORMATDESCRIPTOR),   // size of this pfd 
          1,                     // version number 
          PFD_DRAW_TO_WINDOW |   // support window 
          PFD_SUPPORT_OPENGL |   // support OpenGL 
          PFD_DOUBLEBUFFER,      // double buffered 
          PFD_TYPE_RGBA,         // RGBA type 
          24,                    // 24-bit 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,            // accum bits ignored 
          32,                    // 32-bit z-buffer 
          0,                     // no stencil buffer 
          0,                     // no auxiliary buffer 
          PFD_MAIN_PLANE,        // main layer 
          0,                     // reserved 
          0, 0, 0                // layer masks ignored 
     }; 
 
     int  iPixelFormat; 
  
     // get the best available match of pixel format for the device context  
     iPixelFormat = ChoosePixelFormat(hdc, &pfd); 
  
     // make that the pixel format of the device context 
     SetPixelFormat(hdc, iPixelFormat, &pfd);

     gvw.m_hrc = ::wglCreateContext( hdc );

     wglMakeCurrent(hdc,gvw.m_hrc);

     glClearColor( 0.2,0.2,0.2,1.0);
     glEnable( GL_DEPTH_TEST);

     MSG msg;

     static int frame_count = 0;

     while ( 1 )
     {
          if( gvw.m_bClose )
          {

               ::wglMakeCurrent( 0,0);
               ::wglDeleteContext( gvw.m_hrc);
               gvw.m_hrc =0;
               break;
          }

          glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT );
  
          glMatrixMode( GL_MODELVIEW);
          glLoadIdentity();
  
          static int a = -1;
          static float b = -0.01;
  
          glTranslatef(a*0.1,0,b);
          glRotatef(a*10.f,0,1,0);
          if( a == -1)
               a = 1;
          else 
               a = -1;

          //Handle Input          

          if( GetKeyState( VK_LCONTROL)&0x8000)
          {
   
          }

          glRectf(-0.2,-0.2,0.2,0.2);
          SwapBuffers( hdc ); 
     }

     return ;
}

HWND GameViewWindow::CreateViewWindow(HWND hParent, int x, int y, int w, int h)
{
     HGDIOBJ hbr = ::GetStockObject( DKGRAY_BRUSH );
     HINSTANCE hInst = theApp.m_hInstance; 

     RECT area;
     ::GetClientRect(hParent,&area);

     int ww = area.right - area.left;
     int hh = area.bottom - area.top;

     WNDCLASSEX wc = { sizeof(WNDCLASSEX), CS_CLASSDC, __DefWindowProc, 0L, 0L, 
          hInst, NULL, NULL, NULL, NULL,
          "OPENGLWINDOW", NULL };

     ::RegisterClassEx( &wc ); 

     static CreateStruct cs;
     cs.x = x;
     cs.y = y;
     cs.w = ww;
     cs.h = hh;
     cs.style = WS_CHILD|WS_VISIBLE;
     cs.dwExStyle = 0;
     cs.hParent = hParent;
     cs.hInst = hInst;

     HWND hWnd = CreateWindow( 
          "OPENGLWINDOW", 
          "",
          cs.style,
          cs.x,cs.y,cs.w,cs.h,
          cs.hParent, 
          NULL, 
          cs.hInst, 
          NULL );

     m_hWnd = hWnd;
  
     cs.hWnd = hWnd;
     cs.lock = 1;

     ShowWindow( hWnd,SW_SHOW);
     UpdateWindow( hWnd );

     m_bClose = 0;
     m_hThread = (HANDLE)::_beginthread(start_address,0,&cs);

     //等待线程

     while( cs.lock == 1 )
     {
          Sleep(0);
     }
 
      ::AttachThreadInput( m_dwThreadID,::GetCurrentThreadId(),TRUE);

      return cs.hWnd;
}

void GameViewWindow::DestroyViewWindow(HWND hWnd)
{

     //等待线程退出
     m_bClose = 1;
     CONTEXT ctx;

     while( ::GetThreadContext( m_hThread,&ctx) )
     {

          Sleep(0);
     }

     ::DestroyWindow( m_hWnd );
     m_hWnd = 0;
}

BOOL GameViewWindow::CanCreate()
{
      return TRUE;
}

//注册Extend View 菜单项

DLL_Initinstance()

      f = GetCOREInterface();

      BOOL x = f->RegisterViewWindow(&gvw);

}

posted on 2008-12-31 10:42  cgwolver  阅读(1716)  评论(13编辑  收藏  举报

导航