上一篇我们配置了运行环境,但是并不完美,MFC窗口 和 cosos2d 窗口是分开运行的。 如果用来做工具 看起来不太好看,这一篇我们将修改cocos2d 代码,让其运行在MFC控件上
参考:http://blog.csdn.net/akof1314/article/details/8133800
要把cocos2d 窗口运行在 MFC 控件上, 我们就要找到这个窗口的句柄,下面我们来一步步找,看看怎样得到这个窗口句柄
1.首先我们来分析cocos2d的运行机制
打开cocos2d::Application::getInstance()->run(); run()函数的源码:
int Application::run() { PVRFrameEnableControlWindow(false); // Main message loop: LARGE_INTEGER nFreq; LARGE_INTEGER nLast; LARGE_INTEGER nNow; QueryPerformanceFrequency(&nFreq); QueryPerformanceCounter(&nLast); //这里调用了AppDelegate中的<span style="font-family: Arial, Helvetica, sans-serif;">applicationDidFinishLaunching() // Initialize instance and cocos2d. if (!applicationDidFinishLaunching()) { return 0; } //那么游戏窗口一定是在这之前创建的</span> auto director = Director::getInstance(); auto glview = director->getOpenGLView(); // Retain glview to avoid glview being released in the while loop glview->retain(); //下面是游戏主循环</span> while(!glview->windowShouldClose()) { QueryPerformanceCounter(&nNow); if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart) { nLast.QuadPart = nNow.QuadPart; director->mainLoop(); glview->pollEvents(); } else { Sleep(0); } } // Director should still do a cleanup if the window was closed manually. if (glview->isOpenGLReady()) { director->end(); director->mainLoop(); director = nullptr; } glview->release(); return true; }2. 于是我们查看AppDelegate::applicationDidFinishLaunching() 代码:
bool AppDelegate::applicationDidFinishLaunching() { // initialize director auto director = Director::getInstance(); auto glview = director->getOpenGLView(); if(!glview) {
//第一次运行肯定会进入这里,这个create函数创建了GLView对象 glview = GLView::create("My Game"); director->setOpenGLView(glview); } // turn on display FPS director->setDisplayStats(true); // set FPS. the default value is 1.0/60 if you don't call this director->setAnimationInterval(1.0 / 60); // create a scene. it's an autorelease object auto scene = HelloWorld::createScene(); // run director->runWithScene(scene); return true; }3. 我们看看GLView::create函数代码
GLView* GLView::create(const std::string& viewName) { auto ret = new GLView;
//调用了initWithRect()</span> if(ret && ret->initWithRect(viewName, Rect(0, 0, 960, 640), 1)) { ret->autorelease(); return ret; } return nullptr; }
bool GLView::initWithRect(const std::string& viewName, Rect rect, float frameZoomFactor) { setViewName(viewName); _frameZoomFactor = frameZoomFactor; glfwWindowHint(GLFW_RESIZABLE,GL_FALSE);
//找到了,glfwCreateWindow 这个函数就是创建窗口的(我只知道glfw是个open gl 的库,想了解的可以去搜一下),下面我们来取窗口句柄 _mainWindow = glfwCreateWindow(rect.size.width * _frameZoomFactor, rect.size.height * _frameZoomFactor, _viewName.c_str(), _monitor, nullptr); glfwMakeContextCurrent(_mainWindow); glfwSetMouseButtonCallback(_mainWindow, GLFWEventHandler::onGLFWMouseCallBack); glfwSetCursorPosCallback(_mainWindow, GLFWEventHandler::onGLFWMouseMoveCallBack); glfwSetScrollCallback(_mainWindow, GLFWEventHandler::onGLFWMouseScrollCallback); glfwSetCharCallback(_mainWindow, GLFWEventHandler::onGLFWCharCallback); glfwSetKeyCallback(_mainWindow, GLFWEventHandler::onGLFWKeyCallback); glfwSetWindowPosCallback(_mainWindow, GLFWEventHandler::onGLFWWindowPosCallback); glfwSetFramebufferSizeCallback(_mainWindow, GLFWEventHandler::onGLFWframebuffersize); glfwSetWindowSizeCallback(_mainWindow, GLFWEventHandler::onGLFWWindowSizeFunCallback); setFrameSize(rect.size.width, rect.size.height); // check OpenGL version at first const GLubyte* glVersion = glGetString(GL_VERSION); if ( utils::atof((const char*)glVersion) < 1.5 ) { char strComplain[256] = {0}; sprintf(strComplain, "OpenGL 1.5 or higher is required (your version is %s). Please upgrade the driver of your video card.", glVersion); MessageBox(strComplain, "OpenGL version too old"); return false; } initGlew(); // Enable point size by default. glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); return true; }5. 有个API 函数glfwGetWin32Window() 可以取得窗口句柄。(由于不了解glfw 网上搜了半天才找到这个。。。)
参考: http://www.glfw.org/docs/3.0/group__native.html
6.下面开始修改代码
在CCGLView.cpp 前面添加(头文件一定要在宏定义后面)
#define GLFW_EXPOSE_NATIVE_WIN32 #define GLFW_EXPOSE_NATIVE_WGL #include "glfw3native.h"
给GLView类添加成员:
HWND getHwnd(); void closeWindow(); HWND m_hwnd;
HWND GLView::getHwnd() { return m_hwnd; } void GLView::closeWindow() { glfwSetWindowShouldClose(_mainWindow, 1); }
在函数最后添加
m_hwnd = glfwGetWin32Window(_mainWindow);
int Application::cocosrun() { PVRFrameEnableControlWindow(false); // Main message loop: LARGE_INTEGER nFreq; LARGE_INTEGER nLast; LARGE_INTEGER nNow; QueryPerformanceFrequency(&nFreq); QueryPerformanceCounter(&nLast); // Initialize instance and cocos2d. if (!applicationDidFinishLaunching()) { return 0; } auto director = Director::getInstance(); auto glview = director->getOpenGLView(); // Retain glview to avoid glview being released in the while loop glview->retain(); ShowWindow(glview->getHwnd(), SW_SHOW); while(!glview->windowShouldClose()) { QueryPerformanceCounter(&nNow); if (nNow.QuadPart - nLast.QuadPart > _animationInterval.QuadPart) { nLast.QuadPart = nNow.QuadPart; director->mainLoop(); glview->pollEvents(); } else { Sleep(0); } } // Director should still do a cleanup if the window was closed manually. if (glview->isOpenGLReady()) { director->end(); director->mainLoop(); director = nullptr; } glview->release(); return true; }
8. 打开Application 类添加一个 void closeWindow() public成员函数
void Application::closeWindow() { auto director = cocos2d::Director::getInstance(); auto glview = director->getOpenGLView(); glview->closeWindow(); }
9. 给类 AppDelegate添加 成员
HWND m_hwnd; RECT m_parentRect; void AppDelegate::setParent(HWND hwnd,RECT rect) { m_hwnd = hwnd; m_parentRect.left = rect.left; m_parentRect.top = rect.top; m_parentRect.right = rect.right; m_parentRect.bottom = rect.bottom; }
10 修改AppDelegate::applicationDidFinishLaunching() 函数
bool AppDelegate::applicationDidFinishLaunching() { // initialize director auto director = Director::getInstance(); auto glview = director->getOpenGLView(); if(!glview) { glview = GLView::create("My Game"); director->setOpenGLView(glview); } ::SetParent(glview->getHwnd(), m_hwnd); SetWindowLong(glview->getHwnd(), GWL_STYLE, GetWindowLong(glview->getHwnd(), GWL_STYLE) & ~WS_CAPTION ); ::SetWindowPos(glview->getHwnd(), HWND_TOP, m_parentRect.left, m_parentRect.top, m_parentRect.right - m_parentRect.left, m_parentRect.bottom - m_parentRect.top, SWP_NOCOPYBITS | SWP_HIDEWINDOW); // turn on display FPS director->setDisplayStats(true); // set FPS. the default value is 1.0/60 if you don't call this director->setAnimationInterval(1.0 / 60); // create a scene. it's an autorelease object auto scene = HelloWorld::createScene(); // run director->runWithScene(scene); return true; }
void CCocosEditorDlg::OnBnClickedButton1() { AppDelegate app; RECT rc; m_cocos2dWin.GetClientRect(&rc); app.setParent(m_cocos2dWin.m_hWnd, rc); cocos2d::Application::getInstance()->cocosrun(); }
12. 关闭cocos2d窗口, 在类向导中 给MFC对话框窗口添加 WM_CLOSE消息响应函数:
void CCocosEditorDlg::OnClose() { cocos2d::Application::getInstance()->closeWindow(); CDialogEx::OnClose(); }
13.编译运行程序:
14 .运行时会发现 cocos2d窗口闪了下,这个原因是cocos2d先创建,然后移到了Picture控件上,那我们让Cocos2d的窗口创建时 先不可见:
bool GLView::initWithRect(const std::string& viewName, Rect rect, float frameZoomFactor) { setViewName(viewName); _frameZoomFactor = frameZoomFactor; glfwWindowHint(GLFW_RESIZABLE,GL_FALSE); glfwWindowHint(GLFW_VISIBLE , GL_FALSE); _mainWindow = glfwCreateWindow(rect.size.width * _frameZoomFactor, rect.size.height * _frameZoomFactor, _viewName.c_str(), _monitor, nullptr); glfwMakeContextCurrent(_mainWindow); glfwSetMouseButtonCallback(_mainWindow, GLFWEventHandler::onGLFWMouseCallBack); glfwSetCursorPosCallback(_mainWindow, GLFWEventHandler::onGLFWMouseMoveCallBack); glfwSetScrollCallback(_mainWindow, GLFWEventHandler::onGLFWMouseScrollCallback); glfwSetCharCallback(_mainWindow, GLFWEventHandler::onGLFWCharCallback); glfwSetKeyCallback(_mainWindow, GLFWEventHandler::onGLFWKeyCallback); glfwSetWindowPosCallback(_mainWindow, GLFWEventHandler::onGLFWWindowPosCallback); glfwSetFramebufferSizeCallback(_mainWindow, GLFWEventHandler::onGLFWframebuffersize); glfwSetWindowSizeCallback(_mainWindow, GLFWEventHandler::onGLFWWindowSizeFunCallback); setFrameSize(rect.size.width, rect.size.height); // check OpenGL version at first const GLubyte* glVersion = glGetString(GL_VERSION); if ( utils::atof((const char*)glVersion) < 1.5 ) { char strComplain[256] = {0}; sprintf(strComplain, "OpenGL 1.5 or higher is required (your version is %s). Please upgrade the driver of your video card.", glVersion); MessageBox(strComplain, "OpenGL version too old"); return false; } initGlew(); // Enable point size by default. glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); m_hwnd = glfwGetWin32Window(_mainWindow);</span> return true; }
这样就解决闪一下的问题
转载请注明出处。