Example #1
0
void Renderer::render()
{
    if (m_exiting)
        return;

    QOpenGLContext *ctx = m_glwidget->context();
    if (!ctx) // QOpenGLWidget not yet initialized
        return;

    // Grab the context.
    m_grabMutex.lock();
    emit contextWanted();
    m_grabCond.wait(&m_grabMutex);
    QMutexLocker lock(&m_renderMutex);
    m_grabMutex.unlock();

    if (m_exiting)
        return;

    Q_ASSERT(ctx->thread() == QThread::currentThread());

    // Make the context (and an offscreen surface) current for this thread. The
    // QOpenGLWidget's fbo is bound in the context.
    m_glwidget->makeCurrent();

    if (!m_inited) {
        m_inited = true;
        initializeOpenGLFunctions();

        QMutexLocker initLock(initMutex());
        QOpenGLShader *vshader = new QOpenGLShader(QOpenGLShader::Vertex, this);
        const char *vsrc =
            "attribute highp vec4 vertex;\n"
            "attribute mediump vec3 normal;\n"
            "uniform mediump mat4 matrix;\n"
            "varying mediump vec4 color;\n"
            "void main(void)\n"
            "{\n"
            "    vec3 toLight = normalize(vec3(0.0, 0.3, 1.0));\n"
            "    float angle = max(dot(normal, toLight), 0.0);\n"
            "    vec3 col = vec3(0.40, 1.0, 0.0);\n"
            "    color = vec4(col * 0.2 + col * 0.8 * angle, 1.0);\n"
            "    color = clamp(color, 0.0, 1.0);\n"
            "    gl_Position = matrix * vertex;\n"
            "}\n";
        vshader->compileSourceCode(vsrc);

        QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment, this);
        const char *fsrc =
            "varying mediump vec4 color;\n"
            "void main(void)\n"
            "{\n"
            "    gl_FragColor = color;\n"
            "}\n";
        fshader->compileSourceCode(fsrc);

        program.addShader(vshader);
        program.addShader(fshader);
        program.link();

        vertexAttr = program.attributeLocation("vertex");
        normalAttr = program.attributeLocation("normal");
        matrixUniform = program.uniformLocation("matrix");

        m_fAngle = 0;
        m_fScale = 1;
        createGeometry();

        vbo.create();
        vbo.bind();
        const int verticesSize = vertices.count() * 3 * sizeof(GLfloat);
        vbo.allocate(verticesSize * 2);
        vbo.write(0, vertices.constData(), verticesSize);
        vbo.write(verticesSize, normals.constData(), verticesSize);

        m_elapsed.start();
    }

    //qDebug("%p elapsed %lld", QThread::currentThread(), m_elapsed.restart());

    glClearColor(0.1f, 0.2f, 0.2f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

    glFrontFace(GL_CW);
    glCullFace(GL_FRONT);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);

    QMatrix4x4 modelview;
    modelview.rotate(m_fAngle, 0.0f, 1.0f, 0.0f);
    modelview.rotate(m_fAngle, 1.0f, 0.0f, 0.0f);
    modelview.rotate(m_fAngle, 0.0f, 0.0f, 1.0f);
    modelview.scale(m_fScale);
    modelview.translate(0.0f, -0.2f, 0.0f);

    program.bind();
    program.setUniformValue(matrixUniform, modelview);
    paintQtLogo();
    program.release();

    glDisable(GL_DEPTH_TEST);
    glDisable(GL_CULL_FACE);

    m_fAngle += 1.0f;

    // Make no context current on this thread and move the QOpenGLWidget's
    // context back to the gui thread.
    m_glwidget->doneCurrent();
    ctx->moveToThread(qGuiApp->thread());

    // Schedule composition. Note that this will use QueuedConnection, meaning
    // that update() will be invoked on the gui thread.
    QMetaObject::invokeMethod(m_glwidget, "update");
}