与cocos相伴4年了,从起初的cocos2d到如今的cocos2d-x,静静地看着触控拖沓的前进着。一路沿着cocos的代码一点一点学习游戏开发,对cocos的感情难以言喻,尽管cocos有着这样那样的缺陷,unity有着这样那样的优势,依然抱着cocos不肯撒手。很久很久以前就想自己动手写一个基于cocos的编辑器,但是一会儿我一个小屁程序员怎么搞的定,一会儿想想cocosstudio几百个人的团队做着呢,一会儿想想这么一个没钱途的事情,做了有什么意义,一会儿想想就自己那懒样,哪能做得起那么大一个工程,就硬生生的一直拖着。不过最近呢有些想通了,平时多余的时间拼命想着怎么赚钱压力大而且真的赚不到什么,发发呆又有些浪费,那么就发展一下兴趣爱好吧,正好又看到“红孩儿”博客写的“一个勤奋的人 可以超越一家懒惰的公司”,真的是人生榜样。当然了,我非常的有自知之明,自己绝不是勤奋之人,平时是能省一分力觉不会多浪费一厘。拿起很久很久以前的兴趣,着手自己diy一个cocos的编辑器。(之后文中出现的cocos一般就是指的cocos2d-x)
步入正题,关于编辑器,我选择在mac平台上开发,纯属个人爱好。在实现方式上,我选择重用大部分cocos引擎的代码,在引擎代码之上拦截Events,重新提供一套编辑器使用的mainloop和事件的处理方案。
那么,第一件事,就是重写编辑器专用的GLViewImpl,查看cocos的代码之后,差点吐血,在mac和windows上完全是使用glfw创建了一个不可改变大小的窗口,然后再看看glfw的代码,stop了objc的runloop,自己另起炉灶,然后cocos在代码里写了一个
while(!_exit) { mainloop(); sleep(); }
,这让我只是在mac版本上简单修改扩展的梦想完全破灭。虽然glfw做了很多便捷的处理,但是我是没有办法通过glfw和mac app一起混编。只好自己动手了,一步一步来实现一个GlView。鉴于方便的考虑,我的代码只直接使用cocos2dx 3.8创建了一个空项目,然后在项目生成的ios_mac工程中修改的,那第一件事的第一步就是新建一个editor专用的target,咱要从main.m开始重写了,建好基本的mac应用需要的内容,目录大致如下:
其中CXMMainView将作为编辑器的主窗口(暂时没他什么事),CCGLViewImpl-CXM就是这次的重点,重写的GLView。
重写create方法首当其冲,原本的CCGLViewImple-desktop在create中主要做了3件事,设置glfw窗口需要的参数,设置glfw窗口事件的回调,最后创建opengl窗口,我们要做的呢就是从glfw源码中把相关的代码一点一点挖出来,其实还是很简单的,直接贴上一些代码:
在.h中增加一些属性方法:
bool initWithRect(const std::string& viewName, Rect rect, float frameZoomFactor);
void* _glView; void* _glPixelFormat; void* _glContext;
在.mm增加实现:
bool CXMGLViewImpl::initWithRect(const std::string& viewName, Rect rect, float frameZoomFactor) { setViewName(viewName); _screenSize = rect.size; _designResolutionSize = rect.size; _frameZoomFactor = frameZoomFactor; _viewPortRect = rect; //init view _glView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, _screenSize.width, _screenSize.height)]; //init pixel format #define ADD_ATTR(x) { attributes[attributeCount++] = x; } #define ADD_ATTR2(x, y) { ADD_ATTR(x); ADD_ATTR(y); } unsigned int attributeCount = 0; NSOpenGLPixelFormatAttribute attributes[40]; ADD_ATTR(NSOpenGLPFAAccelerated); ADD_ATTR(NSOpenGLPFAClosestPolicy); ADD_ATTR2(NSOpenGLPFAAuxBuffers, 0); ADD_ATTR2(NSOpenGLPFAAccumSize, 0); int colorBits = _glContextAttrs.redBits + _glContextAttrs.greenBits + _glContextAttrs.blueBits; ADD_ATTR2(NSOpenGLPFAColorSize, colorBits); ADD_ATTR2(NSOpenGLPFAAlphaSize, _glContextAttrs.alphaBits); ADD_ATTR2(NSOpenGLPFADepthSize, _glContextAttrs.depthBits); ADD_ATTR2(NSOpenGLPFAStencilSize, _glContextAttrs.stencilBits); ADD_ATTR(NSOpenGLPFADoubleBuffer); ADD_ATTR2(NSOpenGLPFASampleBuffers, 4); ADD_ATTR(0); #undef ADD_ATTR #undef ADD_ATTR2 _glPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; if(!_glPixelFormat) { MessageBox("Failed to create pixel format.", "error"); return false; } //init content _glContext = [[NSOpenGLContext alloc] initWithFormat:(NSOpenGLPixelFormat*)_glPixelFormat shareContext:nil]; [(NSOpenGLContext*)_glContext setView:(NSView*)_glView]; [(NSOpenGLContext*)_glContext makeCurrentContext]; // 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; } // Enable point size by default. glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); return true; }
其中大多数的代码都是搬来搬去复制过来的,请叫我大自然的搬运工。剩下还有一些简单重写的方法,比如isOpenGLReady、swapBuffers等等就不贴出来了。
未完待续,还有关于frameSize, viewport和坐标转换部分。