定制cocos2d的GLView

前端之家收集整理的这篇文章主要介绍了定制cocos2d的GLView前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

使用场景

需求:将cocos2d 的输出窗口设置为一个子窗口,父窗口其它部分仍然有控件

cocos2d功能强大,但是却不好整合进各种gdi和MFC程序中,有些实现是改cocos2d的项目源代码,这样的话,后续升级版本麻烦些,本文提供的方法可以不修改cocos2d源码

实现步骤

1.从cocos2d::GLView派生类WGLView,需要实现 end,swapBuffers,isOpenGLReady,setIMEKeyboardState,windowShouldClose,getWin32Window 这几个虚函数

2.windows 下的 OpenGL初始化流程有这么几项:

(1).外部提供一个HWND,需要窗口类注册时具有 CS_OWNDC标志

(2).获取HWND的HDC,使用SetPixelFormat来调整窗口像素格式,选择的格式需要具有PFD_SUPPORT_OPENGL,PFD_DRAW_TO_WINDOW,PFD_TYPE_RGBA,PFD_DOUBLEBUFFER这几个标志

(3).使用wglCreateContext创建OpenGL环境上下文

//如果准备在其它线程内使用OpenGL,下面转入该线程执行

(4).wglMakeCurrent使用创建好的上下文

(5).初始化glew (必须在 wglMakeCurrent调用后执行,否则glewInit() 会返回错误 1)

(6).Director::setOpenGLView 设置 GLView(必须在glew初始化后执行,否则内部会报空指针错误,因为对应的glew函数指针尚未初始化)

(7).一些后续的初始化

代码(适用于cocos2d 3.13)

Application
static bool glew_dynamic_binding()
{
	const char *gl_extensions = (const char*)glGetString(GL_EXTENSIONS);

	// If the current opengl driver doesn't have framebuffers methods,check if an extension exists
	if (glGenFramebuffers == nullptr)
	{
		log("OpenGL: glGenFramebuffers is nullptr,try to detect an extension");
		if (strstr(gl_extensions,"ARB_framebuffer_object"))
		{
			log("OpenGL: ARB_framebuffer_object is supported");

			glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)wglGetProcAddress("glIsRenderbuffer");
			glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)wglGetProcAddress("glBindRenderbuffer");
			glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)wglGetProcAddress("glDeleteRenderbuffers");
			glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)wglGetProcAddress("glGenRenderbuffers");
			glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)wglGetProcAddress("glRenderbufferStorage");
			glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)wglGetProcAddress("glGetRenderbufferParameteriv");
			glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)wglGetProcAddress("glIsFramebuffer");
			glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wglGetProcAddress("glBindFramebuffer");
			glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)wglGetProcAddress("glDeleteFramebuffers");
			glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)wglGetProcAddress("glGenFramebuffers");
			glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)wglGetProcAddress("glCheckFramebufferStatus");
			glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)wglGetProcAddress("glFramebufferTexture1D");
			glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)wglGetProcAddress("glFramebufferTexture2D");
			glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)wglGetProcAddress("glFramebufferTexture3D");
			glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)wglGetProcAddress("glFramebufferRenderbuffer");
			glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)wglGetProcAddress("glGetFramebufferAttachmentParameteriv");
			glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)wglGetProcAddress("glGenerateMipmap");
		}
		else if (strstr(gl_extensions,"EXT_framebuffer_object"))
		{
			log("OpenGL: EXT_framebuffer_object is supported");
			glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC)wglGetProcAddress("glIsRenderbufferEXT");
			glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC)wglGetProcAddress("glBindRenderbufferEXT");
			glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC)wglGetProcAddress("glDeleteRenderbuffersEXT");
			glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC)wglGetProcAddress("glGenRenderbuffersEXT");
			glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC)wglGetProcAddress("glRenderbufferStorageEXT");
			glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC)wglGetProcAddress("glGetRenderbufferParameterivEXT");
			glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC)wglGetProcAddress("glIsFramebufferEXT");
			glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC)wglGetProcAddress("glBindFramebufferEXT");
			glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC)wglGetProcAddress("glDeleteFramebuffersEXT");
			glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC)wglGetProcAddress("glGenFramebuffersEXT");
			glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC)wglGetProcAddress("glCheckFramebufferStatusEXT");
			glFramebufferTexture1D = (PFNGLFRAMEBUFFERTEXTURE1DPROC)wglGetProcAddress("glFramebufferTexture1DEXT");
			glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC)wglGetProcAddress("glFramebufferTexture2DEXT");
			glFramebufferTexture3D = (PFNGLFRAMEBUFFERTEXTURE3DPROC)wglGetProcAddress("glFramebufferTexture3DEXT");
			glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC)wglGetProcAddress("glFramebufferRenderbufferEXT");
			glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC)wglGetProcAddress("glGetFramebufferAttachmentParameterivEXT");
			glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC)wglGetProcAddress("glGenerateMipmapEXT");
		}
		else
		{
			log("OpenGL: No framebuffers extension is supported");
			log("OpenGL: Any call to Fbo will crash!");
			return false;
		}
	}
	return true;
}
static bool initGlew()
{
	GLenum GlewInitResult = glewInit();
	if (GLEW_OK != GlewInitResult)
		return false;	//must be called after calling wglMakeCurrent

	if (glew_dynamic_binding() == false)
		return false;
	return true;
}

class AppDelegate : public cocos2d::Application
{
	float sceneWidth_,sceneHeight_,frameRate_;
	HWND hwnd_;
	cocos2d::GLView *glview_;

public:
	AppDelegate(float sceneWidth,float sceneHeight,float frameRate,HWND hwndRender)
	: sceneWidth_(sceneWidth),sceneHeight_(sceneHeight),frameRate_(frameRate),hwnd_(hwndRender),glview_(nullptr)
	{
		extern cocos2d::GLView* CreateWGLView(HWND);
		glview_ = CreateWGLView(hwnd_);
	}

	virtual bool applicationDidFinishLaunching()
	{	// execute in engine thread
		glview_->setFrameSize(sceneWidth_,sceneHeight_);
		glview_->setDesignResolutionSize(sceneWidth_,ResolutionPolicy::NO_BORDER);

		extern void ActiveWGLView(cocos2d::GLView *);
		ActiveWGLView(glview_);
		initGlew();
		auto director = Director::getInstance();
		director->setOpenGLView(glview_);
		director->setContentScaleFactor(1.0);
		director->setDisplayStats(false);
		director->setAnimationInterval(1.0 / frameRate_);
		return true;
	}
	virtual void applicationDidEnterBackground()
	{
		Director::getInstance()->stopAnimation();
	}
	virtual void applicationWillEnterForeground()
	{
		Director::getInstance()->startAnimation();
	}
};
GLView
static int findPixelFormat(HDC hdc,int colorBits,int depthBits,int stencilBits)
{
	int currMode;                               // pixel format mode ID
	int bestMode = 0;                           // return value,best pixel format
	int currscore = 0;                          // points of current mode
	int bestscore = 0;                          // points of best candidate
	PIXELFORMATDESCRIPTOR pfd;

	// search the available formats for the best mode
	bestMode = 0;
	bestscore = 0;
	for (currMode = 1; ::DescribePixelFormat(hdc,currMode,sizeof(pfd),&pfd) > 0; ++currMode)
	{
		// ignore if cannot support opengl
		if (!(pfd.dwFlags & PFD_SUPPORT_OPENGL))
			continue;

		// ignore if cannot render into a window
		if (!(pfd.dwFlags & PFD_DRAW_TO_WINDOW))
			continue;

		// ignore if cannot support rgba mode
		if ((pfd.iPixelType != PFD_TYPE_RGBA) || (pfd.dwFlags & PFD_NEED_PALETTE))
			continue;

		// ignore if not double buffer
		if (!(pfd.dwFlags & PFD_DOUBLEBUFFER))
			continue;

		// try to find best candidate
		currscore = 0;

		// colour bits
		if (pfd.cColorBits >= colorBits) ++currscore;
		if (pfd.cColorBits == colorBits) ++currscore;

		// depth bits
		if (pfd.cDepthBits >= depthBits) ++currscore;
		if (pfd.cDepthBits == depthBits) ++currscore;

		// stencil bits
		if (pfd.cStencilBits >= stencilBits) ++currscore;
		if (pfd.cStencilBits == stencilBits) ++currscore;

		// alpha bits
		if (pfd.cAlphaBits > 0) ++currscore;

		// check if it is best mode so far
		if (currscore > bestscore)
		{
			bestscore = currscore;
			bestMode = currMode;
		}
	}
	return bestMode;
}
static bool setPixelFormat(HDC hdc,int stencilBits)
{
	PIXELFORMATDESCRIPTOR pfd;

	// find out the best matched pixel format
	int pixelFormat = findPixelFormat(hdc,colorBits,depthBits,stencilBits);
	if (pixelFormat == 0)
		return false;

	// set members of PIXELFORMATDESCRIPTOR with given mode ID
	::DescribePixelFormat(hdc,pixelFormat,&pfd);

	// set the fixel format
	if (!::SetPixelFormat(hdc,&pfd))
		return false;

	return true;
}

class WGLView : public cocos2d::GLView
{
	HWND hwnd_;
	HDC hdc_;
	HGLRC hglrc_;
public:
	WGLView() : hwnd_(0),hdc_(0),hglrc_(0)
	{}

	virtual void end() override
	{
		closeContext();
	}
	virtual void swapBuffers() override
	{
		::SwapBuffers(hdc_);
	}
	virtual bool isOpenGLReady() override { return hwnd_ != 0; }
	virtual void setIMEKeyboardState(bool open) override {}
	virtual bool windowShouldClose() override { return true; };
	virtual HWND getWin32Window() override { return hwnd_; }

	bool createContext(HWND hwnd,int stencilBits)
	{
		// retrieve a handle to a display device context
		hwnd_ = hwnd;
		hdc_ = ::GetDC(hwnd);

		// set pixel format
		if (!setPixelFormat(hdc_,stencilBits))
		{
			::ReleaseDC(hwnd,hdc_);
			return false;
		}

		// create a new OpenGL rendering context
		hglrc_ = ::wglCreateContext(hdc_);
		::ReleaseDC(hwnd,hdc_);
		return true;
	}
	void activeContext()
	{
		::wglMakeCurrent(hdc_,hglrc_);
	}
	void closeContext()
	{
		if (!hdc_ || !hglrc_)
			return;

		// delete DC and RC
		::wglMakeCurrent(0,0);
		::wglDeleteContext(hglrc_);
		::ReleaseDC(hwnd_,hdc_);

		hdc_ = 0;
		hglrc_ = 0;
		hwnd_ = 0;
	}

};

void ActiveWGLView(cocos2d::GLView *view)
{
	WGLView *v = dynamic_cast<WGLView *>(view);
	if (v)
		v->activeContext();
}
cocos2d::GLView* CreateWGLView(HWND wndExist)
{
	WGLView *view = new WGLView();
	if (!view->createContext(wndExist,32,24,8))
	{
		delete view;
		return nullptr;
	}
	return view;
}
函数 initGlew 从cocos2d-2.2.6拷贝的,3.13一样可以用

另外,推荐一下一个wgl + OpenGL的例子:http://www.songho.ca/opengl/gl_mvc.html

猜你在找的Cocos2d-x相关文章