您的位置:首页 > 移动开发 > Cocos引擎

在MFC 窗口中运行 cocos2d-x 3.2 (二) 让其在MFC picture控件中运行

2014-09-26 16:04 495 查看
上一篇我们配置了运行环境,但是并不完美,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;
}


4.initWithRect 代码

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);
}


修改函数 bool GLView::initWithRect(const std::string& viewName, Rect rect, float frameZoomFactor)
在函数最后添加

m_hwnd = glfwGetWin32Window(_mainWindow);


7. 打开Application 类添加一个 int cocosrun() public成员函数

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;
}


11. 给对话框添加一个 Picture 控件(注意更改默认 ID),并为其添加Control 类型成员变量 m_cocosWin , 修改上篇中button的消息响应函数

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下载地址:点击打开链接

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: