天天看點

NeHe-OpenGL-Qt5-Lesson01-注釋與學習-CreateWindow

NeHe-OpenGL-Qt5是用到QWindow和QOpenGLFunctions。

而OpenGLFunctions是OpenGL ES 2.0。

OpenGL ES (OpenGL for Embedded Systems) 是 OpenGL三維圖形 API 的子集,針對手機、PDA和遊戲主機等嵌入式裝置而設計。該API由Khronos集團定義推廣,Khronos是一個圖形軟硬體行業協會,該協會主要關注圖形和多媒體方面的開放标準。

OpenGL ES 是從 OpenGL 裁剪的定制而來的,去除了glBegin/glEnd,四邊形(GL_QUADS)、多邊形(GL_POLYGONS)等複雜圖元等許多非絕對必要的特性。經過多年發展,現在主要有兩個版本,OpenGL ES 1.x 針對固定管線硬體的,OpenGL ES 2.x 針對可程式設計管線硬體。OpenGL ES 1.0 是以 OpenGL 1.3 規範為基礎的,OpenGL ES 1.1 是以 OpenGL 1.5 規範為基礎的,它們分别又支援 common 和 common lite兩種profile。lite profile隻支援定點實數,而common profile既支援定點數又支援浮點數。 OpenGL ES 2.0 則是參照 OpenGL 2.0 規範定義的,common profile釋出于2005-8,引入了對可程式設計管線的支援。 [1] 

OpenGL ES 還有一個safety-critical profile。

Qt5.13.0下的OpenGL例子都是繼續了QOpenGLWindow。

NeHe-OpenGL-Qt5-Lesson01-注釋與學習-CreateWindow

而QGLWidget類盡量不要用了,它歸到legacy傳統中了。如果硬體不支援新的可以試一下。

代碼:

Lesson01_CreateWindow.pro

#-------------------------------------------------
#
# Project created by QtCreator 2014-06-09T11:37:36
#
# Modify by LINYOUBIAO 2021-02-11 15:43:00
#
#-------------------------------------------------

#為什麼不用添加opengl和相關的lib了 ???
QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

#輸出目标位置
target.path = E:/home/pi/NeHe_OpenGL_Qt5
#生成對象名稱
TARGET = Lesson01_CreateWindow
INSTALLS += target
TEMPLATE = app


SOURCES += main.cpp \
    openglwindow.cpp

HEADERS  += \
    openglwindow.h
           

openglwindow.h

#ifndef OPENGLWINDOW_H
#define OPENGLWINDOW_H

#include <QWindow>
#include <QOpenGLFunctions>
#include <QCoreApplication>
#include <QEvent>
#include <QResizeEvent>
#include <QKeyEvent>
#include <QMatrix4x4>

// QWindow
// The QWindow class represents a window in the underlying windowing system.
// Header: #include<QWindow>
// qmake: QT += qui
// Since: Qt 5.0
// inherits: QObject and QSurface
// inherited By: QPaintDeviceWindow, QQuickWindow, and QVulkanWindow
//
// Protected Functions
// virtual void	exposeEvent(QExposeEvent *ev)
// virtual void	focusInEvent(QFocusEvent *ev)
// virtual void	focusOutEvent(QFocusEvent *ev)
// virtual void	hideEvent(QHideEvent *ev)
// virtual void	keyPressEvent(QKeyEvent *ev)
// virtual void	keyReleaseEvent(QKeyEvent *ev)
// virtual void	mouseDoubleClickEvent(QMouseEvent *ev)
// virtual void	mouseMoveEvent(QMouseEvent *ev)
// virtual void	mousePressEvent(QMouseEvent *ev)
// virtual void	mouseReleaseEvent(QMouseEvent *ev)
// virtual void	moveEvent(QMoveEvent *ev)
// virtual bool	nativeEvent(const QByteArray &eventType, void *message, long *result)
// virtual void	resizeEvent(QResizeEvent *ev)
// virtual void	showEvent(QShowEvent *ev)
// virtual void	tabletEvent(QTabletEvent *ev)
// virtual void	touchEvent(QTouchEvent *ev)
// virtual void	wheelEvent(QWheelEvent *ev)

// QOpenGLFunctions
// The QOpenGLFunctions class provides cross-platform access to the OpenGL ES 2.0 API.
// Header: #include<QOpenGLFunctions>
// qmake: QT += qui
// Since: Qt 5.0
// Inherited By: QOpenGLExtraFunctions
class OpenGLWindow : public QWindow, protected QOpenGLFunctions
{
    Q_OBJECT
public:
    explicit OpenGLWindow(QWindow *parent = 0);
    ~OpenGLWindow();

    void setAnimating(bool animating);
public slots:
    void renderLater();

    void renderNow();
protected:
    // Override this to handle any event (ev) sent to the window. Return true if the event was recognized and processed.
    //
    // Remember to call the base class version if you wish for mouse events, key events, resize events,
    // etc to be dispatched as usual.
    bool event(QEvent *event);

    // The expose event (ev) is sent by the window system whenever an area of the window is invalidated,
    // for example due to the exposure in the windowing system changing.
    void exposeEvent(QExposeEvent *event);

    // Override this to handle resize events (ev).
    //
    // The resize event is called whenever the window is resized in the windowing system,
    // either directly through the windowing system acknowledging a setGeometry() or resize() request,
    // or indirectly through the user resizing the window manually.
    void resizeEvent(QResizeEvent * event);

    // Override this to handle key press events (ev).
    void keyPressEvent(QKeyEvent * event);

    // 定義render虛函數,用于渲染
    virtual void render();

    // 定義initialize虛函數,用于初始化
    virtual void initialize();

    // 定義resizeGL虛函數,用于縮放事件
    virtual void resizeGL(int w, int h);

    QMatrix4x4 m_projection;

    QMatrix4x4 m_modelView;
private:
    // 等待
    bool m_update_pending;
    // 動畫
    bool m_animating;
    // 上下文
    // QOpenGLContext
    // The QOpenGLContext class represents a native OpenGL context, enabling OpenGL rendering on a QSurface.
    // Header: #include<QOpenGLContext
    // qmake: QT += gui
    // Since: Qt 5.0
    // Inherits: QObject
    QOpenGLContext *m_context;
    // 是否全屏顯示
    bool m_show_full_screen;
};

#endif // OPENGLWINDOW_H
           

openglwindow.cpp

#include "openglwindow.h"

OpenGLWindow::OpenGLWindow(QWindow *parent) :
    QWindow(parent),
    m_update_pending(false),
    m_animating(false),
    m_context(NULL),
    m_show_full_screen(false)
{
    // Sets the surfaceType of the window.
    //
    // Specifies whether the window is meant for raster rendering with QBackingStore,
    // or OpenGL rendering with QOpenGLContext.
    // Specifies whether the window is meant for raster rendering with QBackingStore, or OpenGL rendering with QOpenGLContext.
    //
    // The surfaceType will be used when the native surface is created in the create() function.
    // Calling this function after the native surface has been created requires calling destroy() and create()
    // to release the old native surface and create a new one.
    setSurfaceType(QWindow::OpenGLSurface);
    resize(640, 480);
}

OpenGLWindow::~OpenGLWindow()
{

}

void OpenGLWindow::render()
{

}

void OpenGLWindow::initialize()
{

}

void OpenGLWindow::resizeGL(int w, int h)
{
    if(h == 0)
    {
        h = 1;
    }
    if (m_context)
    {
        glViewport(0, 0, w, h);
    }
    m_projection.setToIdentity();
    m_projection.perspective(45, (float)w/float(h), 1, 1000);
    m_modelView.setToIdentity();
}

void OpenGLWindow::setAnimating(bool animating)
{
    m_animating = animating;
    if(animating)
    {
        renderLater();
    }
}

void OpenGLWindow::renderLater()
{
    if (!m_update_pending)
    {
        m_update_pending = true;
        QCoreApplication::postEvent(this, new QEvent(QEvent::UpdateRequest));
    }
}

void OpenGLWindow::renderNow()
{
    if (!isExposed())
        return;

    bool needsInitialize = false;

    if (!m_context)
    {
        m_context = new QOpenGLContext(this);
        m_context->setFormat(requestedFormat());
        m_context->create();
        needsInitialize = true;
    }

    // Makes the context current in the current thread, against the given surface.
    // Returns true if successful; otherwise returns false.
    // The latter may happen if the surface is not exposed,
    // or the graphics hardware is not available due to e.g. the application being suspended.
    m_context->makeCurrent(this);
    if (needsInitialize)
    {
        // Initializes OpenGL function resolution for the current context.
        //
        // After calling this function, the QOpenGLFunctions object can only be used with the current context and
        // other contexts that share with it. Call initializeOpenGLFunctions() again to
        // change the object's context association.
        initializeOpenGLFunctions();
        initialize();
        const qreal retinaScale = devicePixelRatio();
        resizeGL(width()*retinaScale, height()*retinaScale);
    }
    render();

    // Swap the back and front buffers of surface.
    //
    // Call this to finish a frame of OpenGL rendering, and make sure to call makeCurrent() again
    // before issuing any further OpenGL commands, for example as part of a new frame.
    m_context->swapBuffers(this);

    if (m_animating)
        renderLater();
}

bool OpenGLWindow::event(QEvent *event)
{
    switch (event->type())
    {
    case QEvent::UpdateRequest:
        m_update_pending = false;
        renderNow();
        return true;
    default:
        return QWindow::event(event);
    }
}

void OpenGLWindow::exposeEvent(QExposeEvent *event)
{
    if (isExposed())
    {
        renderNow();
    }
    QWindow::exposeEvent(event);
}

void OpenGLWindow::resizeEvent(QResizeEvent *event)
{
    int w = event->size().width();
    int h = event->size().height();
    const qreal retinaScale = devicePixelRatio();
    resizeGL(w*retinaScale, h*retinaScale);
    renderNow();
    QWindow::resizeEvent(event);
}

void OpenGLWindow::keyPressEvent(QKeyEvent *event)
{
    switch(event->key())
    {
        // 全屏顯示
        case Qt::Key_F1:
        {
            m_show_full_screen = !m_show_full_screen;
            if(m_show_full_screen)
            {
                showFullScreen();
            }
            else
            {
                showNormal();
            }
            break;
        }
        // 退出
        case Qt::Key_Escape:
        {
            qApp->exit();
            break;
        }
    }
    QWindow::keyPressEvent(event);
}
           

main.cpp

#include <QApplication>
#include <QSurfaceFormat>
#include "openglwindow.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    // QSurface是一個可渲染的抽象類,繼承自QOffscreenSurface和QWindow。
    QSurfaceFormat format;
    // Set the preferred number of samples per pixel when multisampling is enabled to numSamples.
    // By default, multisampling is disabled.
    format.setSamples(16);

    OpenGLWindow window;
    // Sets the window's surface format.
    // The format determines properties such as color depth, alpha, depth and stencil buffer size, etc.
    // For example, to give a window a transparent background (provided that the window system supports compositing,
    // and provided that other content in the window does not make it opaque again):
    //
    // QSurfaceFormat format;
    // format.setAlphaBufferSize(8);
    // window.setFormat(format);
    //
    window.setFormat(format);
    window.resize(640, 480);
    window.show();

    window.setAnimating(true);

    return app.exec();
}
           

這是工程代碼,加了注釋。遲點會上傳的。也可以到github上下載下傳。

運作結果:

NeHe-OpenGL-Qt5-Lesson01-注釋與學習-CreateWindow

相關:

QOpenGLFunctions

https://doc.qt.io/qt-5/qopenglfunctions.html#initializeOpenGLFunctions

QWindow

https://doc.qt.io/qt-5/qwindow.html#protected-functions

QSurfaceFormat

https://doc.qt.io/qt-5/qsurfaceformat.html#setSamples

QOpenGLWidget

https://doc.qt.io/qt-5/qopenglwidget.html

Qt OpenGL examples

https://doc.qt.io/qt-5/qtgui-openglwindow-example.html#example-opengl-rendering-sub-class

多謝,親愛的美美。

繼續閱讀