上一篇我们配置了运行环境,但是并不完美,MFC窗口 和 cosos2d 窗口是分开运行的。 如果用来做工具 看起来不太好看,这一篇我们将修改cocos2d 代码,让其运行在MFC控件上
参考:http://blog.youkuaiyun.com/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;
}
这样就解决闪一下的问题
转载请注明出处。
Test下载地址:点击打开链接