【cocos2d-x 源码解析】创建 OpenGL 环境

本文深入解析cocos2d-x如何基于OpenGL创建游戏环境,涉及GLView和GLViewImpl类,从初始化GLContextAttrs到窗口启动,详细阐述了glfw在创建OpenGL窗口和事件处理中的作用,以及Director与GLView如何协同完成渲染过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

创建 OpenGL 上下文

cocos2d-x 是基本 OpenGL 实现的,所以游戏启动之后做的第一件事就是创建 OpenGL 上下文,之后才能进行渲染。在 win32 上,创建 OpenGL context 的过程就是创建一个 OpenGL 窗口,cocos2d-x 使用的是 glfw 库,首先我们回顾一下 glfw 创建窗口的过程

int main()
{
    glfwInit();
    glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
    glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 4);
    glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
    glfwWindowHint(GLFW_RESIZABLE, GLFW_TRUE);
    GLFWwindow* window = glfwCreateWindow(400, 400, "Color", nullptr, nullptr);
    if (window == nullptr) { return 1; }
    glfwMakeContextCurrent(window);

    glewExperimental = GL_TRUE;
    if (GLEW_OK != glewInit()) { return 2; }

    glClearColor(255, 255, 255, 255);
    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        glClear(GL_COLOR_BUFFER_BIT);
        //render
        glfwSwapBuffers(window);
    }

    glfwTerminate();
    return 0;
}

这是 glfw 创建 OpenGL 窗口、调用 OpenGL 渲染指令以及监听处理各种事件的过程,接下来看看 cocos2d-x 中是如何使用 glfw 的。

回顾窗口启动

关于 cocos2d-x 的窗口启动过程可以看我前面的文章
cocos2d-x 窗口启动
下面简单的回顾一下这个过程。在 main 函数创建一个 AppDelegate 实例之后,调用 Application 的 run 方法启动游戏

int Application::run()
{
    //...
    initGLContextAttrs();

    if (!applicationDidFinishLaunching())
    {
        return 1;
    }

    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    glview->retain();

    while(!glview->windowShouldClose())
    {
        //...
        director->mainLoop();
        glview->pollEvents();
    }

    if (glview->isOpenGLReady())
    {
        director->end();
        director->mainLoop();
        director = nullptr;
    }
    glview->release();
    return 0;
}

这是 run 方法的关键代码,首先调用 initGLContextAttrs 设置 OpenGL context 的属性,这个方法在其子类 Appdelegate 中实现

void AppDelegate::initGLContextAttrs()
{
    GLContextAttrs glContextAttrs = {
  8, 8, 8, 8, 24, 8};
    GLView::setGLContextAttrs(glContextAttrs);
}

目前 cocos2d-x 只能设置六个属性,分别是 rgba 四个颜色属性,深度和模板;定义一个 GLContextAttrs 变量,然后调用 GLView 的静态方法进行设置,GLView 是我们这篇文章的重点,下面会解析这个类。设置完 OpenGL Context 属性之后,调用 applicationDidFinishLaunching 方法进行一些初始化,这个方法也是在子类 AppDelegate 中实现

bool AppDelegate::applicationDidFinishLaunching() {
    auto director = Director::getInstance();
    auto glview = director->getOpenGLView();
    if(!glview) {
#if (CC_TARGET_PLATFORM == CC_PLATFORM_WIN32) || (CC_TARGET_PLATFORM == CC_PLATFORM_MAC) || (CC_TARGET_PLATFORM == CC_PLATFORM_LINUX)
        glview = GLViewImpl::createWithRect("CppSource", Rect(0, 0, designResolutionSize.width, designResolutionSize.height));
#else
        glview = GLViewImpl::create("CppSource");
#endif
        director->setOpenGLView(glview);
    }
    //...
    return true;
}

applicationDidFinishLaunching 做了很多初始化工作,其中最重要的就是初始化导演实例 Director 和 OpenGL 窗口管理类实例 GLView。Director 对象中有一个 GLView 实例,该实例默认为空,调用 GLViewImpl 的 createWithRect 创建一个实例。GLViewImpl 继承自 GLView,是桌面程序的 OpenGL 窗口管理类,而 GLView 则是一个上层的 OpenGL 窗口管理类,提供部分接口,更多的接口则在 GLViewImpl 中实现。GLView 和 GLViewImpl 的目录结构

|-cocos
    |-platform
        |-CCGLView.h
        |-CCGLView.cpp
        |-desktop
            |-CCGLViewImpl-desktop.h
            |-CCGLViewImpl-desktop.cpp

applicationDidFinishLaunching 执行完成之后就得到了一个 Director 实例和一个 GLViewImpl 实例,OpenGL 窗口也创建出来了,OpenGL context 也存在了,可以说 OpenGL 环境已经具备了,接下来就可以开始渲染了。在 while 循环中调用 GLView 的 windowShouldClose 检测 OpenGL 窗口是否关闭,如果关闭了则跳出循环,做一些回收操作然后程序结束,如果没关闭则程序在这里阻塞,每一帧都会进入到这个 while 循环体中,这个循环体做的事情就是监听事件和 OpenGL 渲染。

GLView(GLViewImpl)

接下来就是主角 GLView(GLViewImpl) 登场了,首先看 GLViewImpl 的构造函数

GLViewImpl::GLViewImpl(bool initglfw)
: _captured(false)
, _supportTouch(false)
, _isInRetinaMonitor(false)
, _isRetinaEnabled(false)
, _retinaFactor(1)
, _frameZoomFactor(1.0f)
, _mainWindow(nullptr)
, _monitor(nullptr)
, _mouseX(0.0f)
, _mouseY(0.0f)
{
    _viewName = "cocos2dx";
    g_keyCodeMap.clear();
    for (auto& item : g_keyCodeStructArray)
    {
        g_keyCodeMap[item.glfwKeyCode] = item.keyCode;
    }

    GLFWEventHandler::setGLViewImpl(this);
    if (initglfw)
    {
        glfwSetErrorCallback(GLFWEventHandler::onGLFWError);
        glfwInit();
    }
}

这里做了两件重要的事,第一件就是初始化 GLFWEventHandler;第二件就是执行 glfwInit(),也就是我们熟悉的 glfw 初始化了。接下来看GLFWEventHandler 这个类,这个类在 CCGLViewImpl-desktop.cpp 中定义,它的内容很简单

class GLFWEventHandler
{
public:
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值