GL01-03:GLFW窗体

作者: 杨强AT南京 | 来源:发表于2019-07-28 08:58 被阅读0次

    OpenGL编程学习三个方面的知识:OpenGL + OpenGL扩展 + OpenGLUI载体:
      .1 OpenGL是3D的核心库,与显卡厂商关系密切,所以一般系统内置,或者系统开发工具内置,Linux一般使用开源,比如Mesa。
      2. OpenGL扩展,因为OpenGL与硬件的关系,所以调用需要考虑很多细节,这些细节被封装成OpenGL扩展,主要调用方便;同时提供一种硬件厂商使用自己独有功能的接口机制,只一点是OpenGL的特色;扩展很多,比如GLEW,GLAD等
      3. OpenGL载体,就是3D显示的GUI界面,事件交互,数据缓冲,显示性能呢等,这就是本文介绍的GLFW。当然OpenGL载体封装也有很多,比如glut,freeglut等。


    本文仅仅介绍glfw的窗体相关的知识:
       1. 窗体对象与窗体创建
      2. 窗体属性
      3. 窗体的双缓冲机制与缓冲交换、
    同时还在附录介绍了gamma校正的概念与使用


    创建窗体

    窗体对象

    • 窗体对象的说明:
      1. 窗体对象GLFWwindow是一个结构体,封装了Window及其工作的上下文;
      2. 由于窗口和上下文是不可分割的链接,因此对象指针同时用作上下文和窗口句柄;
      3. 窗体的创建使用glfwCreateWindow函数;
      4. 窗体的释放使用glfwDestroyWindow函数, 或者粗暴的使用glfwTerminate函数结束一切;

    GLFWwindow的定义

    typedef struct GLFWwindow GLFWwindow;
    
    

    创建窗体

    1. 函数说明
    
        GLFWwindow* glfwCreateWindow    (   
            int     width,                              // 窗体宽度;
            int     height,                             // 窗体高度;
            const char *    title,                    // 窗体标题;
            GLFWmonitor *   monitor,          // 用来指定全屏显示模式的对象,NULL就是普通窗体模式;
            GLFWwindow *    share             // 需要共享窗体资源的窗体对象,NULL表示没有共享的窗体的对象;
    )       
    
    

    释放窗体

    1. 函数说明
    
        void glfwDestroyWindow  (   GLFWwindow *    window  )   
    
    

    窗体创建的编程模式

    • 一般窗体的创建与释放应该成对出现,下面是经典代码:
    
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <GLFW/glfw3.h>
    
        int main(int argc, char const *argv[]){
            // 初始化
            int re = glfwInit();
            if(re == GLFW_FALSE){
                printf("初始化GLFW环境失败!\n");
                exit(-1);
            }
            ///////////////////////////////////////
            // 创建窗体
            GLFWwindow *window = glfwCreateWindow(
                800,
                600,
                "OpenGL的UI窗体",
                NULL,  //控制全屏;
                NULL  // 一起共享资源的窗体;
            );
    
            if(! window){
                printf("创建窗体失败!");
                glfwTerminate();
                exit(-1);
            }
            printf("创建窗体成功\n");   
            // 注意:创建窗体需要进入事件处理循环,防止程序结束;这里创建成功后,窗体会随着程序结束而释放。
            // 释放窗体
            glfwDestroyWindow(window);   
            printf("释放窗体!\n");
    
            ///////////////////////////////////////
            // 释放
            glfwTerminate();
            printf("环境释放退出!\n");
            return 0;
        }
    
        // 编译命令:g++ -omain  gl01_window_create_destroy.cpp  -lglfw -lglew -framework opengl
    
    

    窗体的关闭

    • 窗体的关闭操作一般是点击窗体上的关闭按钮,或者使用Alt + F4 关闭;
    • 判定窗体是否被关闭操作,使用函数:glfwWindowShouldClose
    • 可以设置窗体关闭的回调操作:glfwSetWindowCloseCallback
    • 修改窗体的关闭标记:glfwSetWindowShouldClose

    关闭操作标记获取

    1. glfwWindowShouldClose 函数定义说明
    int glfwWindowShouldClose(  GLFWwindow *    window  )   
    
    
    • 函数的返回值int是关闭标记,类型是逻辑类型
      • GLFW_TRUE:关闭操作
      • GLFW_FALSE:没有关闭操作

    设置窗体关闭标记

    1. glfwSetWindowShouldClose函数说明
        void glfwSetWindowShouldClose   (   
            GLFWwindow *    window,
            int     value     // GLFW_TRUE或者GLFW_FALSE
        )   
    

    通过关闭标记来阻止应用结束

    • 可以通过对关闭标记的判定,来决定是否结束应用,编程方式就是根据关闭标记来做循环。
        while (! glfwWindowShouldClose(window));
    

    窗体的消息处理

    • 通过窗体的关闭标记进入循环,主线程占用计算资源,窗体无法处理消息,需要调用函数来处理窗体的消息;
    • 窗体的消息处理函数有三个:
      • glfwPollEvents:处理消息
      • glfwWaitEvents:等待消息
      • glfwWaitEventsTimeout:延时等待消息
    1. glfwPollEvents函数定义
      • 该函数只处理已经发生的在系统消息队列中的消息,消息处理完毕后马上返回。如果在循环中不调用该函数处理消息,所有的交互操作与事件都无法响应;
      • 所谓消息处理,就是根据不同的消息,处理对应的函数调用;
      • 有的平台在窗体移动,缩放的时候,会导致消息处理阻塞(glfwPollEvents函数需要等消息响应完毕才返回),这就需要单独处理。
        void glfwPollEvents (   void        )   
    
    
    1. glfwWaitEvents函数定义
      • 该函数释放运算资源,处于睡眠状态,直到有消息产生;与上面的不同的是,这种情况循环不是一直持续的,而是有消息发生才运行;
    
        void glfwWaitEvents (   void )  
    
    
    1. glfwWaitEventsTimeout函数定义
      • 这个函数是glfwWaitEvents函数的延时版本,就是在指定时间内,没有消息发生,该函数也会返回。
      • 参数是浮点数,单位是秒。
        void glfwWaitEventsTimeout  (   double  timeout )   
    
    

    一个典型的消息处理与应用结束处理例子

    1. 方式一:
      • 主动处理式
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <GLFW/glfw3.h>
    
    int main(int argc, char const *argv[]){
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            printf("初始化GLFW环境失败!\n");
            exit(-1);
        }
        ///////////////////////////////////////
        // 创建窗体
        GLFWwindow *window = glfwCreateWindow(
            800,
            600,
            "OpenGL的UI窗体",
            NULL,  //控制全屏;
            NULL  // 一起共享资源的窗体;
        );
    
        if(! window){
            printf("创建窗体失败!");
            glfwTerminate();
            exit(-1);
        }
        printf("创建窗体成功\n");   
        // 应用循环,直到用户关闭窗体
        // 方式一:
        while (! glfwWindowShouldClose(window)){
            // 这类可以处理自己的业务(比如OpenGL的3D对象绘制等)
            glfwPollEvents();  // 有消息处理消息,处理完毕直接返回,没有消息就直接返回。
        }
    
        // 释放窗体
        glfwDestroyWindow(window);   
        printf("释放窗体!\n");
    
        ///////////////////////////////////////
        // 释放
        glfwTerminate();
        printf("环境释放退出!\n");
        return 0;
    }
    
    // 编译命令:g++ -omain  gl02_window_loop.cpp  -lglfw -lglew -framework opengl
    
    
    
    1. 方式二:
      • 被动等待式。
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <GLFW/glfw3.h>
    
    int main(int argc, char const *argv[]){
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            printf("初始化GLFW环境失败!\n");
            exit(-1);
        }
        ///////////////////////////////////////
        // 创建窗体
        GLFWwindow *window = glfwCreateWindow(
            800,
            600,
            "OpenGL的UI窗体",
            NULL,  //控制全屏;
            NULL  // 一起共享资源的窗体;
        );
    
        if(! window){
            printf("创建窗体失败!");
            glfwTerminate();
            exit(-1);
        }
        printf("创建窗体成功\n");   
        // 应用循环,直到用户关闭窗体
        // 方式二:
        while (! glfwWindowShouldClose(window)){
            // 这类可以处理自己的业务(比如OpenGL的3D对象绘制等)
            glfwWaitEvents();  // 释放资源,直到有消息发生,处理后返回
        }
        // 释放窗体
        glfwDestroyWindow(window);   
        printf("释放窗体!\n");
    
        ///////////////////////////////////////
        // 释放
        glfwTerminate();
        printf("环境释放退出!\n");
        return 0;
    }
    
    // 编译命令:g++ -omain  gl02_window_loop.cpp  -lglfw -lglew -framework opengl
    
    

    消息等待中的唤醒

    • 使用glfwWaitEventsglfwWaitEventsTimeout, 在没有消息发生的时候,主线程就会一直阻塞,如果在循环中处理业务,则会导致业务无法执行;
    • 函数glfwPostEmptyEvent用来唤醒glfwWaitEvents函数的阻塞。
    1. 函数glfwPostEmptyEvent定义
    
        void glfwPostEmptyEvent (void)  
    
    

    监视器

    监视器对象

    1. 全屏窗体是使用窗体创建函数glfwCreateWindow的时候,需要指定一个监视器对象。
      • 监视器也是一个结构体,定义如下:
        • typedef struct GLFWmonitor GLFWmonitor

    获取监视器对象

    • 监视器对象通过函数获取,不用使用代码创建,获取监视器的函数有:
      • glfwGetPrimaryMonitor : 获取主监视器;
      • glfwGetMonitors:获取所有监视器;
    1. glfwGetPrimaryMonitor函数说明
        GLFWmonitor* glfwGetPrimaryMonitor  (void)  
    
    1. glfwGetMonitors函数说明
        GLFWmonitor** glfwGetMonitors   (int * count)   
    
    1. 获取监视器例子代码
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <GLFW/glfw3.h>
    
        int main(int argc, char const *argv[]){
            // 初始化
            int re = glfwInit();
            if(re == GLFW_FALSE){
                printf("初始化GLFW环境失败!\n");
                exit(-1);
            }
            ////////////////////////////////////
            // 得到监视器
            GLFWmonitor* primary = glfwGetPrimaryMonitor();
            if (! primary){
                printf("获取监视器失败!\n");
                glfwTerminate();
                exit(-1);
            }
            // 获取监视器可阅读的名字
            const char* name = glfwGetMonitorName(primary);
            printf("获取的监视器是:%s\n", name);
    
    
            // 获取所有的监视器(包含接入的投影仪等)
            int count;  //用来返回监视器数量
            GLFWmonitor** monitors = glfwGetMonitors(&count);
            printf("目前支持的监视器数量:%d\n",count);
            // 循环打印所有的监视器
            // -------下面代码存在问题,因为最后一个监视器对象不存在,没有提供NULL结尾的约定,监视器指针移动容易产生段错误
            // while (*monitors){
            //     printf("监视器:%s\n", glfwGetMonitorName(*monitors));
            //     monitors ++;
            // }
            // 使用下标访问比较好。
            for(int id = 0; id < count; id++){
                printf("监视器:%s\n", glfwGetMonitorName(monitors[id]));
            }
            ////////////////////////////////////
            glfwTerminate();
            return 0;
        }
    
        // 编译命令:g++ -omain  gl03_window_monitor.cpp  -lglfw -lglew -framework opengl
    
    

    监视器配置改变监控

    • 如果监视器配置改变处理,则可以通过如下回调函数处理:
      • glfwSetMonitorCallback:该函数设置一个回调函数,一旦监视器配置发生改变,则回调函数得到调用,并返回监视器配置改变的参数。
    1. glfwSetMonitorCallback函数说明:
    
        GLFWmonitorfun glfwSetMonitorCallback   (   GLFWmonitorfun  cbfun   )   
    
    
    1. 监视器回调函数的原型定义:
      - typedef void(* GLFWmonitorfun) (GLFWmonitor *, int)
      - 参数GLFWmonitor *返回变化的监视器;
      - 参数int返回监视器配置变化的事件类型:
      - GLFW_CONNECTED
      - GLFW_DISCONNECTED.

    视频模式

    • 监视器的视频模式,通过两个函数可以查询监视器的视频模式:
      • glfwGetVideoModes
      • glfwGetVideoMode
    1. glfwGetVideoModes函数定义
        const GLFWvidmode* glfwGetVideoModes    (   
            GLFWmonitor *   monitor,
            int *   count         // 返回视频模式的数量
        )       
            
            
        // 返回视频模式对象数组
    
    
    1. glfwGetVideoMode函数定义
        const GLFWvidmode* glfwGetVideoMode (   GLFWmonitor *   monitor )   
        // 返回当前的视频模式
    
    
    1. GLFWvidmode结构体说明
    
        typedef struct GLFWvidmode
        {
            /*! The width, in screen coordinates, of the video mode.
             */
            int width;
            /*! The height, in screen coordinates, of the video mode.
             */
            int height;
            /*! The bit depth of the red channel of the video mode.
             */
            int redBits;
            /*! The bit depth of the green channel of the video mode.
             */
            int greenBits;
            /*! The bit depth of the blue channel of the video mode.
             */
            int blueBits;
            /*! The refresh rate, in Hz, of the video mode.
             */
            int refreshRate;
        } GLFWvidmode;
    
    
    1. 视频模式的使用例子
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <GLFW/glfw3.h>
    
        int main(int argc, char const *argv[]){
            // 初始化
            int re = glfwInit();
            if(re == GLFW_FALSE){
                printf("初始化GLFW环境失败!\n");
                exit(-1);
            }
            ////////////////////////////////////
            // 得到监视器
            GLFWmonitor* primary = glfwGetPrimaryMonitor();
            if (! primary){
                printf("获取监视器失败!\n");
                glfwTerminate();
                exit(-1);
            }
    
            // 得到监视器当前视频模式
            const GLFWvidmode* mode = glfwGetVideoMode(primary);
            printf("当前视频模式参数:\n");
            printf("\t高宽:(%d,%d)\n", mode->height, mode->width);
            printf("\t颜色位数:(R:%d,G:%d,B:%d)\n", mode->redBits, mode->greenBits, mode->blueBits);
            printf("\t刷新频率:%d\n", mode->refreshRate);
    
            // 得到监视器所有支持的视频模式
            int count;
            const GLFWvidmode* modes = glfwGetVideoModes(primary, &count);
            // 数组循环方式
            for (int id = 0; id < count; id++){
                printf("当前视频模式-%02d:\n", id + 1);
                printf("\t高宽:(%d,%d)\n", modes[id].height, modes[id].width);
                printf("\t颜色位数:(R:%d,G:%d,B:%d)\n", modes[id].redBits, modes[id].greenBits, modes[id].blueBits);
                printf("\t刷新频率:%d\n", modes[id].refreshRate);
            }
            printf("---------------------------------------\n");
            // 指针循环方式(注意初始位置被改变)
            for (int id = 0; id < count; id++){
                printf("当前视频模式-%02d:\n", id + 1);
                printf("\t高宽:(%d,%d)\n", modes->height, modes->width);
                printf("\t颜色位数:(R:%d,G:%d,B:%d)\n", modes->redBits, modes->greenBits, modes->blueBits);
                printf("\t刷新频率:%d\n", modes->refreshRate);
                modes++;
            }
    
            ////////////////////////////////////
            glfwTerminate();
            return 0;
        }
    
        // 编译命令:g++ -omain  gl04_window_video_mode.cpp  -lglfw -lglew -framework opengl
    
    

    监视器物理大小

    • 使用函数glfwGetMonitorPhysicalSize获取
    1. glfwGetMonitorPhysicalSize函数定义
    void glfwGetMonitorPhysicalSize (   
        GLFWmonitor *   monitor,
        int *   widthMM,     // 返回宽度
        int *   heightMM    // 返回高度
    )   
    

    内容缩放

    • 使用函数glfwGetMonitorContentScale获取
    1. glfwGetMonitorContentScale函数定义
    void glfwGetMonitorContentScale (   
        GLFWmonitor *   monitor,
        float *     xscale,    // x方向缩放
        float *     yscale     // y方向缩放
    )   
    

    虚拟位置

    • 使用函数glfwGetMonitorPos获取
    1. glfwGetMonitorPos函数说明
    void glfwGetMonitorPos  (   
        GLFWmonitor *   monitor,
        int *   xpos,    // x-位置
        int *   ypos     // y-位置
    )   
    
    1. 屏幕坐标系
      • 如果系统链接多个监视器,则使用虚拟屏幕的概念,如下图所示:
      • 监视器对象的屏幕管理坐标系
    • GLFW有两个主要的坐标系统:虚拟屏幕和窗口内容区域或内容区域。
      • 两者都使用相同的单位:虚拟屏幕坐标,或者只是屏幕坐标,它们不一定使用像素单位。

    工作区域

    • 使用函数glfwGetMonitorWorkarea获取
    1. 函数glfwGetMonitorWorkarea定义
    void glfwGetMonitorWorkarea (   
        GLFWmonitor *   monitor,
        int *   xpos,       // 区域原点
        int *   ypos,
        int *   width,      // 区域大小
        int *   height 
    )       
    
    

    监视器可阅读的名字

    • 使用函数glfwGetMonitorName获取
    1. 函数glfwGetMonitorName定义
        const char* glfwGetMonitorName  (   GLFWmonitor *   monitor )   
    
    

    监视器用户指针

    • 监视器用户指针,用来存放用户数据;包括存取函数:
      • 存函数:glfwSetMonitorUserPointer
      • 取函数:glfwGetMonitorUserPointer
    1. 函数glfwSetMonitorUserPointer定义
        void glfwSetMonitorUserPointer  (   
            GLFWmonitor *   monitor,
            void *  pointer 
        )   
    
    1. 函数glfwGetMonitorUserPointer定义
        void* glfwGetMonitorUserPointer (   GLFWmonitor *   monitor )   
    
    

    监视器的Gamma设置

    • Gamma矫正是用来矫正屏幕(监视器)显示亮度的;

      • 关于Gamma校正是因为历史上CRT(阴极射线显像管)的电压与现实亮度不是线性关系;为了保持这种线性关系,就需要做gamma校正。
      • 这种现象在人眼也照样存在,就是人眼对不同亮度的敏感度不同,比如人眼对暗色比较敏感:0->0.1之间的亮度差异,人眼可以感觉,但是0.99->1.0之间的亮度,人眼就感知不出来,为了利用存储空间有效存储更多人眼敏感的像素,所以现在视频处理技术中也采用gamma矫正。
    • 与gamma参数有关的函数一共3个:

      • 获取gamma参数 glfwGetGammaRamp
      • 设置gamma参数glfwSetGammaRamp
      • 设置gamma值glfwSetGamma
    1. 函数glfwGetGammaRamp定义
        const GLFWgammaramp* glfwGetGammaRamp   (   GLFWmonitor *   monitor )   
    
    
    1. 函数glfwSetGammaRamp定义
        void glfwSetGammaRamp   (   
            GLFWmonitor *   monitor,
            const GLFWgammaramp *   ramp 
        )       
    
    
    • 该函数设置Gamma斜面的时候,GLFW会保存原来的Gamma Ramp,并在环境退出的时候,会恢复。
    1. 结构体GLFWgammaramp定义
    typedef struct GLFWgammaramp
    {
        /*! An array of value describing the response of the red channel.*/
        unsigned short* red;
        /*! An array of value describing the response of the green channel.*/
        unsigned short* green;
        /*! An array of value describing the response of the blue channel. */
        unsigned short* blue;
        /*! The number of elements in each array.*/
        unsigned int size;
    } GLFWgammaramp;
    
    1. 函数glfwSetGamma定义
      • 没有对应的获取函数。
        void glfwSetGamma   (   
            GLFWmonitor *   monitor,
            float   gamma 
        )   
    
    • 参数gamma必须是大于0的数。

    监视器的属性使用例子代码

    1. 属性使用例子代码-1
    
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <GLFW/glfw3.h>
    
        int main(int argc, char const *argv[]){
            // 初始化
            int re = glfwInit();
            if(re == GLFW_FALSE){
                printf("初始化GLFW环境失败!\n");
                exit(-1);
            }
            ////////////////////////////////////
            // 得到监视器
            GLFWmonitor* primary = glfwGetPrimaryMonitor();
            if (! primary){
                printf("获取监视器失败!\n");
                glfwTerminate();
                exit(-1);
            }
            // 物理大小
            int width_mm, height_mm;
            glfwGetMonitorPhysicalSize(primary, &width_mm, &height_mm);
            printf("物理大小:(%d,%d)\n", width_mm, height_mm);
    
            // 内容缩放
            float xscale, yscale;
            glfwGetMonitorContentScale(primary, &xscale, &yscale);
            printf("内容缩放:(%f,%f)\n", xscale, yscale);
    
            // 虚拟位置
            int xpos, ypos;
            glfwGetMonitorPos(primary, &xpos, &ypos);
            printf("虚拟位置:(%d,%d)\n", xpos, ypos);
    
            // 工作区域
            int w_xpos, w_ypos, w_width, w_height;
            glfwGetMonitorWorkarea(primary, &w_xpos, &w_ypos, &w_width, &w_height);
            printf("工作区域(%d, %d, %d, %d)\n", w_xpos, w_xpos, w_width, w_height);
    
            // 监视器名
            const char* name = glfwGetMonitorName(primary);
            printf("监视器:%s\n", name);
    
            // 用户指针(用来存放用户任意数据)
            const char* my_name = "Louis";
            // 设置用户指针
            glfwSetMonitorUserPointer(primary, (void *)my_name);    
            // 获取用户指针
            const char *data =  (const char*)glfwGetMonitorUserPointer(primary);
            printf("获取存储的数据:%s\n", data);
    
            ////////////////////////////////////
            glfwTerminate();
            return 0;
        }
    
        // 编译命令:g++ -omain  gl05_window_monitor_property.cpp  -lglfw -lglew -framework opengl
    
    
    1. 属性使用例子代码-2(gamma校正)

      • 下面代码可以自己调整gamma值,观察效果,截图截不到效果。因为gamma的值影响到监视器;图像数据本身不受影响。
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <GLFW/glfw3.h>
    
        int main(int argc, char const *argv[]){
            // 初始化
            int re = glfwInit();
            if(re == GLFW_FALSE){
                printf("初始化GLFW环境失败!\n");
                exit(-1);
            }
            // 创建窗体
            GLFWwindow *window = glfwCreateWindow(
                800,
                600,
                "OpenGL的UI窗体",
                NULL,  //控制全屏;
                NULL  // 一起共享资源的窗体;
            );
    
            if(! window){
                printf("创建窗体失败!");
                glfwTerminate();
                exit(-1);
            }
            ////////////////////////////////////////
            // 得到监视器
            GLFWmonitor* primary = glfwGetPrimaryMonitor();
            if (! primary){
                printf("获取监视器失败!\n");
                glfwTerminate();
                exit(-1);
            }
            //设置gamma值
            glfwSetGamma(primary, 10.0);      // 调整gamma值;
            ////////////////////////////////////////
            while (! glfwWindowShouldClose(window)){
                // 这类可以处理自己的业务(比如OpenGL的3D对象绘制等)
                glfwWaitEvents();  // 释放资源,直到有消息发生,处理后返回
            }
            // 释放窗体
            glfwDestroyWindow(window);  
            // 释放
            glfwTerminate();
            printf("环境释放退出!\n");
            return 0;
        }
    
        // 编译命令:g++ -omain  gl06_window_monitor_gamma.cpp  -lglfw -lglew -framework opengl
    
    
    1. Gamma Ramp(Gamma斜面)的使用离子
      • 下面代码把64改成其他值试试
        • 取64的原因是,Gamma的颜色通道使用unsigned int,一共16位,表示的数值为0-65535 ;一般Ramp斜面的大小为1024,则每个值的间隔就是65536/1024,这样才能均匀填充0-65535之间的值。
      • Gamma Ramp实际是一种颜色的表示机制,类似调色板,任何绘制的图像的像素分成RGB三通道,每个通道的值在Ramp中存在一个接近的映射;
        • 如果Ramp的Red数组全部为0,则图像像素的红色通道都映射为0,图像的红色丢失。
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <GLFW/glfw3.h>
    
        int main(int argc, char const *argv[]){
            // 初始化
            int re = glfwInit();
            if(re == GLFW_FALSE){
                printf("初始化GLFW环境失败!\n");
                exit(-1);
            }
            // 创建窗体
            GLFWwindow *window = glfwCreateWindow(
                800,
                600,
                "OpenGL的UI窗体",
                NULL,  //控制全屏;
                NULL  // 一起共享资源的窗体;
            );
    
            if(! window){
                printf("创建窗体失败!");
                glfwTerminate();
                exit(-1);
            }
            ////////////////////////////////////////
            // 得到监视器
            GLFWmonitor* primary = glfwGetPrimaryMonitor();
            if (! primary){
                printf("获取监视器失败!\n");
                glfwTerminate();
                exit(-1);
            }
            //获取Gamma Ramp值
    
            const GLFWgammaramp* ramp = glfwGetGammaRamp(primary);
            printf("Ramp的size:%d\n", ramp->size);
    
            // 获取每个值显示
            printf("Ramp的Red:\n");
            for(int i = 0; i < ramp->size; i++){
                ramp->red[i] = 64 * i;   // 修改gamma斜面的红色通道值(默认的都是64的间隔距离,效果最正常)
            }
    
            // 使用新的Gamma Ramp值
            glfwSetGammaRamp(primary, ramp);
            ////////////////////////////////////////
            while (! glfwWindowShouldClose(window)){
                // 这类可以处理自己的业务(比如OpenGL的3D对象绘制等)
                glfwWaitEvents();  // 释放资源,直到有消息发生,处理后返回
            }
            // 释放窗体
            glfwDestroyWindow(window);  
            // 释放
            glfwTerminate();
            printf("环境释放退出!\n");
            return 0;
        }
    
        // 编译命令:g++ -omain  gl07_window_monitor_gamma_ramp.cpp  -lglfw -lglew -framework opengl
    
    

    全屏窗体

    • 如果想全屏显示窗体,则只需要指定窗体显示在整个监视器上即可。
    • 如果窗体大小与监视器大小差距太大,会导致窗体拉抻显示(就是分辨率的问题)。
      • 窗体大小与监视器大小一致的情况,就不会导致分辨率的变化。

    全屏方式1

    • 在glfwCreateWindow函数中直接指定窗体显示的监视器,从而全屏。
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <GLFW/glfw3.h>
    
        int main(int argc, char const *argv[]){
            // 初始化
            int re = glfwInit();
            if(re == GLFW_FALSE){
                printf("初始化GLFW环境失败!\n");
                exit(-1);
            }
            ///////////////////////////////////////
            // 获取监视器
            GLFWmonitor* primary = glfwGetPrimaryMonitor();
             // 得到监视器当前视频模式
            const GLFWvidmode* mode = glfwGetVideoMode(primary);
            // 创建窗体
            GLFWwindow *window = glfwCreateWindow(
                mode->width,
                mode->height,
                "OpenGL的UI窗体",
                primary,  //控制全屏;
                NULL  // 一起共享资源的窗体;
            );
    
            if(! window){
                printf("创建窗体失败!");
                glfwTerminate();
                exit(-1);
            }
            printf("创建窗体成功\n");   
    
    
            while (! glfwWindowShouldClose(window)){
                glfwPollEvents();  
            }
            glfwDestroyWindow(window);   // 如果有glfwTerminate,则敢函数可以省略。
            glfwTerminate();
            return 0;
        }
    
        // 编译命令:g++ -omain  gl08_window_fullscreen.cpp  -lglfw -lglew -framework opengl
    
    

    全屏方式2-设置窗体的监视器

    • 使用glfwSetWindowMonitor函数任何时候改变窗体的监视器,实现全屏;
    1. 函数glfwSetWindowMonitor定义
    
    void glfwSetWindowMonitor   (   
        GLFWwindow *    window,
        GLFWmonitor *   monitor,
        int     xpos,
        int     ypos,
        int     width,
        int     height,
        int     refreshRate 
    )   
    
    • 函数说明:
      1. 当参数monitor有效的时候,xpos与ypos没有作用;
      2. 当参数monitor无效的时候,refreshRate参数无用,窗体的位置与大小会改变;
    1. 设置窗体监视器的例子代码
        #include <stdio.h>
        #include <stdlib.h>
        #include <unistd.h>
        #include <GLFW/glfw3.h>
    
        int main(int argc, char const *argv[]){
            // 初始化
            int re = glfwInit();
            if(re == GLFW_FALSE){
                printf("初始化GLFW环境失败!\n");
                exit(-1);
            }
            ///////////////////////////////////////
            // 获取监视器
            GLFWmonitor* primary = glfwGetPrimaryMonitor();
             // 得到监视器当前视频模式
            const GLFWvidmode* mode = glfwGetVideoMode(primary);
            // 创建窗体
            GLFWwindow *window = glfwCreateWindow(
                200,
                200,
                "OpenGL的UI窗体",
                NULL,  //控制全屏;
                NULL  // 一起共享资源的窗体;
            );
    
            if(! window){
                printf("创建窗体失败!");
                glfwTerminate();
                exit(-1);
            }
    
            ///////////////////////////
            // 设置窗体的监视器
            //  全屏方式
            // glfwSetWindowMonitor(window, primary, 10, 10,mode->width,mode->height,59);
            // 不全屏,改变窗体的位置与大小。
            glfwSetWindowMonitor(window, NULL, 100, 100,600,400,0);
            ////////////////////
            while (! glfwWindowShouldClose(window)){
                glfwPollEvents();  
            }
            glfwDestroyWindow(window);   // 如果有glfwTerminate,则敢函数可以省略。
            glfwTerminate();
            return 0;
        }
    
        // 编译命令:g++ -omain  gl09_window_fullscreen_set_monitor.cpp  -lglfw -lglew -framework opengl
    
    
    1. 获取窗体的监视器函数定义:
        GLFWmonitor* glfwGetWindowMonitor   (   GLFWwindow *    window  )   
    
    

    窗体创建中的提示设置

    • 通过窗体创建函数的参数对窗体设置的功能太简单,如果需要更多的窗体控制,则可以使用从窗体的提示设置;
    • 提示设置一定在窗体创建前设置。
    • 提示设置影响的对象:
      • 窗体本身;
      • 缓冲帧;
      • 环境上下文;

    提示设置函数

    • 提示设置相关的函数三个:
      • glfwWindowHint:设置提示:数据整数;
      • glfwWindowHintString:设置提示:数据字符串;
      • glfwDefaultWindowHints:重置缺省提示值;
    1. glfwWindowHint函数定义
    
        void glfwWindowHint (   
            int     hint,
            int     value 
        )       
    
    1. glfwWindowHintString函数定义
    void glfwWindowHintString   (   
        int     hint,
        const char *    value 
    )   
    
    • 这个函数用来设置字符串类型的Hint,字符串的Hint不多,比如下面的表格中GLFW_X11_CLASS_NAME就是字符串Hint
    1. glfwDefaultWindowHints函数定义
        void glfwDefaultWindowHints (   void        )   
    
    
    • 在创建窗体前调用,不要指望这个函数在创建窗体后调用,也会马上有效果。

    Hint的硬约束与软约束

    • 一些窗口提示是硬约束。这些功能必须与可用功能完全匹配,才能成功创建窗口和上下文。
    • 非硬约束的提示尽可能匹配,但生成的上下文和帧缓冲区可能与这些提示请求的不同。
    1. 常见的硬约束

      • GLFW_STEREO
      • GLFW_DOUBLEBUFFER
      • GLFW_CLIENT_API
      • GLFW_CONTEXT_CREATION_API
    2. 只对OpenGL的硬约束提示,对OpenGL ES无效的硬约束提示

      • GLFW_OPENGL_FORWARD_COMPAT
      • GLFW_OPENGL_PROFILE

    窗体的提示分类

    • 窗体的提示类别有
      1. 窗体有关的提示:常用
      2. 缓冲帧相关的提示(Framebuffer):常用
      3. 监视器相关的提示;
      4. 上下文(Context)相关的提示;
      5. Mac OS独有的提示;
      6. X11独有的提示;

    窗体提示的缺省值

    Window hint Default value Supported values
    GLFW_RESIZABLE GLFW_TRUE GLFW_TRUE or GLFW_FALSE
    GLFW_VISIBLE GLFW_TRUE GLFW_TRUE or GLFW_FALSE
    GLFW_DECORATED GLFW_TRUE GLFW_TRUE or GLFW_FALSE
    GLFW_FOCUSED GLFW_TRUE GLFW_TRUE or GLFW_FALSE
    GLFW_AUTO_ICONIFY GLFW_TRUE GLFW_TRUE or GLFW_FALSE
    GLFW_FLOATING GLFW_FALSE GLFW_TRUE or GLFW_FALSE
    GLFW_MAXIMIZED GLFW_FALSE GLFW_TRUE or GLFW_FALSE
    GLFW_CENTER_CURSOR GLFW_TRUE GLFW_TRUE or GLFW_FALSE
    GLFW_TRANSPARENT_FRAMEBUFFER GLFW_FALSE GLFW_TRUE or GLFW_FALSE
    GLFW_FOCUS_ON_SHOW GLFW_TRUE GLFW_TRUE or GLFW_FALSE
    GLFW_SCALE_TO_MONITOR GLFW_FALSE GLFW_TRUE or GLFW_FALSE
    GLFW_RED_BITS 8 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_GREEN_BITS 8 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_BLUE_BITS 8 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_ALPHA_BITS 8 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_DEPTH_BITS 24 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_STENCIL_BITS 8 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_ACCUM_RED_BITS 0 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_ACCUM_GREEN_BITS 0 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_ACCUM_BLUE_BITS 0 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_ACCUM_ALPHA_BITS 0 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_AUX_BUFFERS 0 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_SAMPLES 0 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_REFRESH_RATE GLFW_DONT_CARE 0 to INT_MAX or GLFW_DONT_CARE
    GLFW_STEREO GLFW_FALSE GLFW_TRUE or GLFW_FALSE
    GLFW_SRGB_CAPABLE GLFW_FALSE GLFW_TRUE or GLFW_FALSE
    GLFW_DOUBLEBUFFER GLFW_TRUE GLFW_TRUE or GLFW_FALSE
    GLFW_CLIENT_API GLFW_OPENGL_API GLFW_OPENGL_API, GLFW_OPENGL_ES_API or GLFW_NO_API
    GLFW_CONTEXT_CREATION_API GLFW_NATIVE_CONTEXT_API GLFW_NATIVE_CONTEXT_API, GLFW_EGL_CONTEXT_API or GLFW_OSMESA_CONTEXT_API
    GLFW_CONTEXT_VERSION_MAJOR 1 Any valid major version number of the chosen client API
    GLFW_CONTEXT_VERSION_MINOR 0 Any valid minor version number of the chosen client API
    GLFW_CONTEXT_ROBUSTNESS GLFW_NO_ROBUSTNESS GLFW_NO_ROBUSTNESS, GLFW_NO_RESET_NOTIFICATION or GLFW_LOSE_CONTEXT_ON_RESET
    GLFW_CONTEXT_RELEASE_BEHAVIOR GLFW_ANY_RELEASE_BEHAVIOR GLFW_ANY_RELEASE_BEHAVIOR, GLFW_RELEASE_BEHAVIOR_FLUSH or GLFW_RELEASE_BEHAVIOR_NONE
    GLFW_OPENGL_FORWARD_COMPAT GLFW_FALSE GLFW_TRUE or GLFW_FALSE
    GLFW_OPENGL_DEBUG_CONTEXT GLFW_FALSE GLFW_TRUE or GLFW_FALSE
    GLFW_OPENGL_PROFILE GLFW_OPENGL_ANY_PROFILE GLFW_OPENGL_ANY_PROFILE, GLFW_OPENGL_COMPAT_PROFILE or GLFW_OPENGL_CORE_PROFILE
    GLFW_COCOA_RETINA_FRAMEBUFFER GLFW_TRUE GLFW_TRUE or GLFW_FALSE
    GLFW_COCOA_FRAME_NAME "" A UTF-8 encoded frame autosave name
    GLFW_COCOA_GRAPHICS_SWITCHING GLFW_FALSE GLFW_TRUE or GLFW_FALSE
    GLFW_X11_CLASS_NAME "" An ASCII encoded WM_CLASS class name
    GLFW_X11_INSTANCE_NAME "" An ASCII encoded WM_CLASS instance name

    窗体创建的提示例子代码

    • 创建的时候与监视器一样大小。
      • GLFW_SCALE_TO_MONITOR:平台有关的Hint;
      • GLFW_DECORATED:没有边框的窗体,逻辑值;
      • GLFW_RESIZABLE:大小不能变化的窗体,逻辑值;
      • GLFW_COCOA_FRAME_NAME:设置Frame名字,字符串值。
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <png.h>
    #include <GLFW/glfw3.h>
    
    int main(int argc, char const *argv[]){
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            printf("初始化GLFW环境失败!\n");
            exit(-1);
        }
        ///////////////////////////////////////
        //窗体创建的提示
        /*
            与监视器一样大小:此提示仅对屏幕坐标和像素始终映射为1:1(如Windows和x11)的平台有效。
            在像MacOS这样的平台上,帧缓冲区的分辨率与窗口大小无关。
         */
        glfwWindowHint(GLFW_SCALE_TO_MONITOR,GLFW_TRUE);   
        // 窗体装饰(GLFW_FALSE:表示去掉边框,标题栏,系统按钮等)
        // glfwWindowHint(GLFW_DECORATED, GLFW_FALSE);  
        // 窗体大小变化(是否可以使用鼠标拖拽改变大小)
    
        glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);    // 整数方式
    
        glfwWindowHintString(GLFW_COCOA_FRAME_NAME, "Louis");    // 字符串方式,只用于字符串数据的Hint。
          
        ///////////////////////////////////////
        // 创建窗体
        GLFWwindow *window = glfwCreateWindow(
            800,
            600,
            "OpenGL的UI窗体",
            NULL, 
            NULL  
        );
    
        if(! window){
            exit(-1);
        }
        //////////////////////////////////////
        // 恢复Window的缺省提示
        glfwDefaultWindowHints();
        ///////////////////////////////////////
        while (! glfwWindowShouldClose(window)){
            glfwWaitEvents();  
        }
    
        glfwDestroyWindow(window);   
        glfwTerminate();
        return 0;
    }
    
    // 编译命令:g++ -omain  gl10_window_hint.cpp  -lglfw -lglew -framework opengl
    
    

    窗体属性

    窗体的用户指针

    • 用户指针与监视器指针一样,用来存储用户数据;两个函数:
      • glfwSetWindowUserPointer : 存储用户数据指针
      • glfwGetWindowUserPointer :获取用户数据指针;
    1. glfwSetWindowUserPointer函数说明
    void glfwSetWindowUserPointer   (   
        GLFWwindow *    window,
        void *  pointer 
    )   
    
    1. glfwGetWindowUserPointer函数说明
        void* glfwGetWindowUserPointer  (   GLFWwindow *    window  )   
    
    • 例子代码参考:监视器的用户指针;

    窗体的关闭

    • 提供三个函数处理窗体的关闭:
      • glfwWindowShouldClose :获取关闭标志;
      • glfwSetWindowShouldClose :设置关闭标志,手工关闭;
      • glfwSetWindowCloseCallback:窗体关闭标志改变前的回调函数设置;
    1. glfwWindowShouldClose函数说明
        int glfwWindowShouldClose   (   GLFWwindow *    window  )   
    
    1. glfwSetWindowShouldClose 函数说明
    void glfwSetWindowShouldClose   (   
        GLFWwindow *    window,
        int     value     // GLFW_TRUE 或者 GLFW_FALSE
    )   
    
    1. glfwSetWindowCloseCallback函数说明
    GLFWwindowclosefun glfwSetWindowCloseCallback   (   
        GLFWwindow *    window,
        GLFWwindowclosefun  cbfun 
    )   
    
    1. GLFWwindowclosefun回调函数原型定义
        typedef void(* GLFWwindowclosefun) (GLFWwindow *)
    
    1. 控制窗体关闭的例子代码
      • 下面代码使用kill -9 进程ID关闭;其他方式不能关闭并退出。
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <png.h>
    #include <GLFW/glfw3.h>
    
     void cb_close(GLFWwindow * win){
         // 关闭操作的回调函数
         printf("关闭操作\n");
    
         // 防止退出,可以在回调函数中修改关闭状态为GLFW_FALSE
         glfwSetWindowShouldClose(win, GLFW_FALSE);    
     }
    
    
    int main(int argc, char const *argv[]){
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            exit(-1);
        }
        // 创建窗体
        GLFWwindow *window = glfwCreateWindow(
            800,
            600,
            "OpenGL的UI窗体",
            NULL, 
            NULL  
        );
    
        if(! window){
            exit(-1);
        }
        // 设置窗体关闭按钮的回调操作
        GLFWwindowclosefun old_callback = glfwSetWindowCloseCallback(window, cb_close);
        // 设置窗体的关闭标记 (设置标记后,下面的循环无法进去)
        //glfwSetWindowShouldClose(window, GLFW_TRUE);    
    
        while (! glfwWindowShouldClose(window)){
            glfwWaitEvents();  
        }
    
        glfwDestroyWindow(window);   
        glfwTerminate();
        return 0;
    }
    
    // 编译命令:g++ -omain  gl11_window_close.cpp  -lglfw -lglew -framework opengl
    
    

    窗体大小

    • 提供三个函数管理窗体大小

      • glfwSetWindowSize:设置窗体大小;
      • glfwGetWindowSize:获取窗体大小;
      • glfwSetWindowSizeCallback:设置窗体变化的回调函数;
      • glfwGetWindowFrameSize:获取窗体框架大小;
    • 注意:

      • 窗体大小的单位不是像素,不能与缓冲与OpenGL的大小混用;
    1. glfwSetWindowSize函数说明
    
    void glfwSetWindowSize  (   
        GLFWwindow *    window,
        int     width,
        int     height 
    )   
    
    1. glfwGetWindowSize函数说明
    void glfwGetWindowSize  (   
        GLFWwindow *    window,
        int *   width,
        int *   height 
    )   
    
    1. glfwSetWindowSizeCallback函数说明
    
    GLFWwindowsizefun glfwSetWindowSizeCallback (   
        GLFWwindow *    window,
        GLFWwindowsizefun   cbfun 
    )   
    
    1. GLFWwindowsizefun回调函数说明
        typedef void(* GLFWwindowsizefun) (GLFWwindow *, int, int)
    
    1. glfwGetWindowFrameSize函数说明
    void glfwGetWindowFrameSize (   
        GLFWwindow *    window,
        int *   left,
        int *   top,
        int *   right,
        int *   bottom 
    )   
    
    • glfwGetWindowSize获取的内容区的大小,这个函数glfwGetWindowFrameSize获取窗体的边狂大小,left、top、right、bottom表示的是内容区域边界到窗体边界的距离,所以这个值总是0或者 >0
      • 一般标题栏方向为22,因为标题栏的宽度为22像素,其他方向都是0(就是内容区边缘与窗体的边缘重叠)
    1. 监控窗体大小改变的例子:
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <png.h>
    #include <GLFW/glfw3.h>
    
     void cb_size(GLFWwindow * win, int width, int height){
         // 窗体大小改变操作的回调函数
         int left, top, right, bottom;
        glfwGetWindowFrameSize(win, &left, &top, &right, &bottom);
         printf("窗体大小改变:(%d,%d),Framesize(%d, %d, %d, %d)\n", width, height, left, top, right, bottom);  
     }
    
    
    int main(int argc, char const *argv[]){
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            exit(-1);
        }
        // 创建窗体
        GLFWwindow *window = glfwCreateWindow(
            800,
            600,
            "OpenGL的UI窗体",
            NULL, 
            NULL  
        );
    
        if(! window){
            exit(-1);
        }
    
        // 设置窗体的大小改变的回调函数
        GLFWwindowsizefun old_cb =  glfwSetWindowSizeCallback(window, cb_size);
    
        while (! glfwWindowShouldClose(window)){
            glfwWaitEvents();  
        }
    
        glfwDestroyWindow(window);   
        glfwTerminate();
        return 0;
    }
    
    // 编译命令:g++ -omain  gl12_window_size.cpp  -lglfw -lglew -framework opengl
    
    

    FrameBuffer大小

    • 缓冲管理一共2个函数:

      • glfwGetFramebufferSize:获取缓冲大小;
      • glfwSetFramebufferSizeCallback:设置缓冲大小变化的回调函数;
    • 一般在OpenGL中使用FrameBuffer的size,因为都是像素单位;

      • X11与Window的BufferSize与WindowSize的比率是1:1;
      • Mac的BufferSize与WindowSize的比率是2:1;
    • 参考上面的例子代码。

    1. glfwGetFramebufferSize函数说明
    void glfwGetFramebufferSize (   
        GLFWwindow *    window,
        int *   width,
        int *   height 
    )   
    
    1. glfwSetFramebufferSizeCallback函数说明
    GLFWframebuffersizefun glfwSetFramebufferSizeCallback   (   
        GLFWwindow *    window,
        GLFWframebuffersizefun  cbfun 
    )   
    

    窗体内容缩放

    • 窗体缩放也是两个函数

      • glfwGetWindowContentScale:获取内容缩放;
      • glfwSetWindowContentScaleCallback:缩放比例改变的回调函数设置函数;
    • 例子代码参考窗体大小的例子。

    1. glfwGetWindowContentScale函数说明:
    
    void glfwGetWindowContentScale  (   
        GLFWwindow *    window,
        float *     xscale,
        float *     yscale 
    
    
    1. glfwSetWindowContentScaleCallback函数说明:
    
    GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback (   
        GLFWwindow *    window,
        GLFWwindowcontentscalefun   cbfun 
    )   
    
    1. 回调函数GLFWwindowcontentscalefun的原型定义
        typedef void(* GLFWwindowcontentscalefun) (GLFWwindow *, float, float)
    

    窗体大小限制

    • 窗体大小的最大值与最小值,提供如下函数管理:
      • glfwSetWindowSizeLimits:设置窗体大小的最大与最小限制;
      • glfwSetWindowAspectRatio:设置窗体的高宽比例。
    1. glfwSetWindowSizeLimits函数说明
    
    void glfwSetWindowSizeLimits    (   
        GLFWwindow *    window,
        int     minwidth,
        int     minheight,
        int     maxwidth,
        int     maxheight 
    )   
    
    1. glfwSetWindowAspectRatio函数说明
    
    void glfwSetWindowAspectRatio   (   
        GLFWwindow *    window,
        int     numer,       //所需纵横比的分子
        int     denom       //所需纵横比的分母
    )   
    

    窗体位置

    • 窗体位置提供三个函数管理:
      • glfwSetWindowPos:设置窗体位置;
      • glfwSetWindowPosCallback:窗体位置变化的回调函数设置函数;
      • glfwGetWindowPos:获取窗体的位置;
    1. glfwSetWindowPos函数说明
    void glfwSetWindowPos   (   
        GLFWwindow *    window,
        int     xpos,
        int     ypos 
    )   
    
    1. glfwSetWindowPosCallback函数说明
    
    GLFWwindowposfun glfwSetWindowPosCallback   (   
        GLFWwindow *    window,
        GLFWwindowposfun    cbfun 
    )   
    
    1. GLFWwindowposfun原型说明
        typedef void(* GLFWwindowposfun) (GLFWwindow *, int, int)
    
    1. glfwGetWindowPos函数说明
    void glfwGetWindowSize  (   
        GLFWwindow *    window,
        int *   width,
        int *   height 
    )   
    

    窗体标题

    • 只提供窗体标题设置函数
      • glfwSetWindowTitle:设置窗体标题,C++11支持unicode:
        • glfwSetWindowTitle(window, u8"This is always a UTF-8 string");
    1. glfwSetWindowTitle函数说明
    void glfwSetWindowTitle (   
        GLFWwindow *    window,
        const char *    title 
    )   
    

    窗体图标

    • 图标只能设置:
      • glfwSetWindowIcon:设置图标
    1. glfwSetWindowIcon函数说明
      • 此函数设置指定窗口的图标。如果传递了一组候选图像,则会选择系统所需大小或最接近系统所需大小的图像。如果未指定图像,窗口将恢复为其默认图标。
      • MAC 系统的glfw窗口没有图标,因为它不是文档窗口,所以此函数不起任何作用。Dock图标将与应用程序包的图标相同。
    
    void glfwSetWindowIcon  (   
        GLFWwindow *    window,
        int     count,                                  // 图像数量
        const GLFWimage *   images          // 图像数据结构
    )   
    
    1. 图像结构体
        typedef struct GLFWimage
        {
            /*! The width, in pixels, of this image.
             */
            int width;
            /*! The height, in pixels, of this image.
             */
            int height;
            /*! The pixel data of this image, arranged left-to-right, top-to-bottom.
             */
            unsigned char* pixels;
        } GLFWimage;
    
    • 图像格式是:
      • RGBA格式的小端字节序。
      • 像素为32位,即每个通道8位,首先是红色通道。从左上角开始,它们按规范排列为压缩的连续行。
      • 所需的图像大小因平台和系统设置而异。所选图像将根据需要重新缩放。建议尺寸包括16x16、32x32和48x48。
    1. 图标使用的例子
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <png.h>
    #include <GLFW/glfw3.h>
    
    int main(int argc, char const *argv[]){
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            exit(-1);
        }
    
        GLFWwindow *window = glfwCreateWindow(
            800,
            600,
            "OpenGL的UI窗体",
            NULL, 
            NULL  
        );
    
        if(! window){
            exit(-1);
        }
    
        /////////////////////////
        /*
        - RGBA格式的小端字节序。
        - 像素为32位,即每个通道8位,首先是红色通道。从左上角开始,它们按规范排列为压缩的连续行。
        - 所需的图像大小因平台和系统设置而异。所选图像将根据需要重新缩放。好尺寸包括16x16、32x32和48x48。
         */
        // 构造一个图像格式数据(黑图像)
        GLFWimage img;
        img.width = 48;
        img.height = 48;
        // 分配内存空间
        size_t buff_size = img.width * img.height * 4; // 字节
        unsigned char *buff = (unsigned char *)malloc(buff_size);
        // 初始化空间
        bzero(buff,buff_size);
        // 设置图标的数据缓存
        img.pixels = buff;
        
        // 设置图标
        printf("设置图标");
        glfwSetWindowIcon(window, 1, &img); 
        /////////////////////////
    
        while (! glfwWindowShouldClose(window)){
            glfwWaitEvents();  
        }
    
        glfwDestroyWindow(window);   
        glfwTerminate();
        return 0;
    }
    
    // 编译命令:g++ -omain  gl13_window_icon.cpp  -lglfw -lglew -framework opengl
    
    

    窗体监视器

    • 提供2个函数管理窗体的监视器

      • glfwGetWindowMonitor:获取
      • glfwSetWindowMonitor:设置
    • 例子参考前面使用监视器全屏化的例子。

    1. glfwGetWindowMonitor函数说明
    
    GLFWmonitor* glfwGetWindowMonitor(GLFWwindow *  window  )   
    
    
    1. glfwSetWindowMonitor函数说明
    void glfwSetWindowMonitor(GLFWwindow *  window,
        GLFWmonitor *   monitor,
        int     xpos,
        int     ypos,
        int     width,
        int     height,
        int     refreshRate 
    )   
    

    窗体图标化

    • 提供管理函数如下
      • glfwIconifyWindow:图标化窗体;
      • glfwRestoreWindow:从图标化恢复窗体;
      • glfwSetWindowIconifyCallback:窗体图标化的回调函数设置函数;
      • glfwGetWindowAttrib:获取当前图标化状态;
    1. glfwIconifyWindow函数说明
    
    void glfwIconifyWindow  (   GLFWwindow *    window  )   
    
    
    1. glfwRestoreWindow函数说明
    void glfwRestoreWindow  (   GLFWwindow *    window  )   
    
    
    1. glfwSetWindowIconifyCallback函数说明
    GLFWwindowiconifyfun glfwSetWindowIconifyCallback   (   
        GLFWwindow *    window,
        GLFWwindowiconifyfun    cbfun 
    )   
    
    1. 回调函数GLFWwindowiconifyfun原型说明
    
    typedef void(* GLFWwindowiconifyfun) (GLFWwindow *, int)
    
    
    • 其中第二个参数是图标化状态:
      • GLFW_TRUE:图标化
      • GLFW_FALSE:非图标化
    1. glfwGetWindowAttrib函数说明
    int glfwGetWindowAttrib (   
        GLFWwindow *    window,
        int     attrib 
    )   
    
    1. 窗体特性
      • 与窗体有关的特性包含:
        • GLFW_FOCUSED
        • GLFW_ICONIFIED
        • GLFW_MAXIMIZED
        • GLFW_HOVERED
        • GLFW_VISIBLE
        • GLFW_RESIZABLE
        • GLFW_DECORATED
        • GLFW_AUTO_ICONIFY
        • GLFW_FLOATING
        • GLFW_TRANSPARENT_FRAMEBUFFER
        • GLFW_FOCUS_ON_SHOW
      • 与上下文有关的特性;(参考官方文档)
      • 与FrameBuffer有关的特性;(参考官方文档)

    窗体最大化

    • glfwMaximizeWindow : 最大化窗体
    • glfwRestoreWindow : 恢复窗体上次状态
    • glfwSetWindowMaximizeCallback:窗体最大化状态改变回调函数设置
    • glfwGetWindowAttrib : 获取窗体最大化特性
    • glfwWindowHint:在创建窗体时设置最大化;
    1. glfwMaximizeWindow函数说明
    void glfwMaximizeWindow (   GLFWwindow *    window  )   
    
    
    1. glfwSetWindowMaximizeCallback函数说明
    GLFWwindowmaximizefun glfwSetWindowMaximizeCallback (   
        GLFWwindow *    window,
        GLFWwindowmaximizefun   cbfun 
    )   
    
    1. GLFWwindowmaximizefun回调函数原型说明
    
    typedef void(* GLFWwindowmaximizefun) (GLFWwindow *, int)  
        // 参数是逻辑值,GLFW_TRUE 与 GLFW_FALSE
    
    

    窗体可见

    • glfwHideWindow:隐藏窗体
    • glfwShowWindow:显示窗体
    • glfwGetWindowAttrib:获取窗体是否可见状态;
    • glfwWindowHint:在创建窗体设置窗体的可见状态;
    1. 函数说明
    void glfwHideWindow (   GLFWwindow *    window  )   
    
    1. 函数说明
    void glfwShowWindow (   GLFWwindow *    window  )   
    
    

    窗体输入焦点

    • glfwFocusWindow:使窗体获取焦点;
    • glfwSetWindowFocusCallback:焦点状态改变的回调函数设置;
    • glfwGetWindowAttrib:获取窗体的焦点状态特性;
    • glfwWindowHint:在创建窗体设置是否拥有焦点;
    1. 函数说明
    void glfwFocusWindow    (   GLFWwindow *    window  )   
    
    
    1. 函数说明
    GLFWwindowfocusfun glfwSetWindowFocusCallback   (   
        GLFWwindow *    window,
        GLFWwindowfocusfun  cbfun 
    )   
    
    1. GLFWwindowfocusfun回调函数原型说明
    
    typedef void(* GLFWwindowfocusfun) (GLFWwindow *, int)
            // 第二个参数:焦点状态:GLFW_TRUE 或 GLFW_FALSE
    
    

    窗体关注

    • glfwRequestWindowAttention
    1. glfwRequestWindowAttention函数说明
        void glfwRequestWindowAttention (   GLFWwindow *    window  )
    

    窗体刷新

    • glfwSetWindowRefreshCallback:设置窗体刷新的回调机制;

      • 窗体刷新的机制通过回调函数获取是否需要刷新的信息。
        • 一般窗体上发生像素破坏:比如窗体移动,最小化等;
        • 刷新时候可以完成图形绘制,以及缓冲切换;
    1. glfwSetWindowRefreshCallback函数说明
    GLFWwindowrefreshfun glfwSetWindowRefreshCallback   (   
        GLFWwindow *    window,
        GLFWwindowrefreshfun    cbfun 
    )   
    
    1. 回调函数GLFWwindowrefreshfun原型说明
    typedef void(* GLFWwindowrefreshfun) (GLFWwindow *)
    
    

    窗体透明

    • glfwSetWindowOpacity:设置窗体的透明度;
    • glfwGetWindowOpacity:获取窗体的透明度;
    • glfwGetWindowAttrib:获取FrameBuffer是否支持透明;
      • GLFW_TRANSPARENT_FRAMEBUFFER
    • glfwWindowHint:创建窗体时,设置FrameBuffer透明度;
      • GLFW_TRANSPARENT_FRAMEBUFFER
    1. glfwSetWindowOpacity函数说明:
    
    void glfwSetWindowOpacity   (   
        GLFWwindow *    window,
        float   opacity 
    )   
    
    1. glfwGetWindowOpacity函数说明:
    
    float glfwGetWindowOpacity  (   GLFWwindow *    window  )   
    
    

    窗体特性

    • glfwGetWindowAttrib

    • glfwSetWindowAttrib

    • 与窗体有关的特性包含:

      • GLFW_FOCUSED
      • GLFW_ICONIFIED
      • GLFW_MAXIMIZED
      • GLFW_HOVERED
      • GLFW_VISIBLE
      • GLFW_RESIZABLE
      • GLFW_DECORATED
      • GLFW_AUTO_ICONIFY
      • GLFW_FLOATING
      • GLFW_TRANSPARENT_FRAMEBUFFER
      • GLFW_FOCUS_ON_SHOW
    • 与上下文有关的特性;(参考官方文档)

    • 与FrameBuffer有关的特性;(参考官方文档)

    1. glfwGetWindowAttrib函数说明
    
    int glfwGetWindowAttrib (   
        GLFWwindow *    window,
        int     attrib 
    )   
    
    1. glfwSetWindowAttrib函数说明
    void glfwSetWindowAttrib(   
        GLFWwindow *    window,
        int     attrib,
        int     value 
    )       
    
    

    双缓冲与交换

    • 因为双缓冲的目的是:

      • 一个缓冲处理图像;
      • 一个缓冲显示图像;
    • 一但显示的图像绘制完成,可以调用函数切换前后缓冲

      • glfwSwapBuffers:交换缓冲区
      • glfwSwapInterval:有时,选择何时进行缓冲区交换可能很有用。使用函数glfwSwapInterval,从调用glfwSwapBuffer开始,可以选择驱动程序在交换缓冲区之前应等待的最小监视器刷新数。
    1. glfwSwapBuffers函数说明
        void glfwSwapBuffers(GLFWwindow *   window) 
    
    
    1. glfwSwapInterval函数说明
        void glfwSwapInterval(int interval) 
    
    
    • 如果间隔为零,则当调用glfwSwapBuffers而不等待刷新时,交换将立即发生。否则,缓冲区交换满足监视器刷新的最小数。
    • 通过监视器的刷新最小数量设置,可以方式图像显示撕裂(显示部分,就刷新到下一帧图像)。
    • 该函数可以在glfwSwapBuffers调用前设置。
    1. 经典的绘制刷新模式
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <string.h>
    #include <png.h>
    #include <GLFW/glfw3.h>
    
    int main(int argc, char const *argv[]){
        // 初始化
        int re = glfwInit();
        if(re == GLFW_FALSE){
            exit(-1);
        }
    
        GLFWwindow *window = glfwCreateWindow(
            800,
            600,
            "OpenGL的UI窗体",
            NULL, 
            NULL  
        );
    
        if(! window){
            exit(-1);
        }
    
        while (! glfwWindowShouldClose(window)){
            // 完成图形绘制
            // ......
            // 设置监视器的最低刷新数
            glfwSwapInterval(2);
            // 交换缓冲区
            glfwSwapBuffers(window);
            
            glfwWaitEvents();  
        }
    
        glfwDestroyWindow(window);   
        glfwTerminate();
        return 0;
    }
    
    // 编译命令:g++ -omain  gl13_window_icon.cpp  -lglfw -lglew -framework opengl
    
    
    1. 提示:
      • 还可以通过刷新回调来实现图形绘制。

    附录

    宏定义

    #define GLFW_FOCUSED 0x00020001

    #define GLFW_ICONIFIED 0x00020002

    #define GLFW_RESIZABLE 0x00020003

    #define GLFW_VISIBLE 0x00020004

    #define GLFW_DECORATED 0x00020005

    #define GLFW_AUTO_ICONIFY 0x00020006

    #define GLFW_FLOATING 0x00020007

    #define GLFW_MAXIMIZED 0x00020008

    #define GLFW_CENTER_CURSOR 0x00020009

    #define GLFW_TRANSPARENT_FRAMEBUFFER 0x0002000A

    #define GLFW_HOVERED 0x0002000B

    #define GLFW_FOCUS_ON_SHOW 0x0002000C

    #define GLFW_RED_BITS 0x00021001

    #define GLFW_GREEN_BITS 0x00021002

    #define GLFW_BLUE_BITS 0x00021003

    #define GLFW_ALPHA_BITS 0x00021004

    #define GLFW_DEPTH_BITS 0x00021005

    #define GLFW_STENCIL_BITS 0x00021006

    #define GLFW_ACCUM_RED_BITS 0x00021007

    #define GLFW_ACCUM_GREEN_BITS 0x00021008

    #define GLFW_ACCUM_BLUE_BITS 0x00021009

    #define GLFW_ACCUM_ALPHA_BITS 0x0002100A

    #define GLFW_AUX_BUFFERS 0x0002100B

    #define GLFW_STEREO 0x0002100C

    #define GLFW_SAMPLES 0x0002100D

    #define GLFW_SRGB_CAPABLE 0x0002100E

    #define GLFW_REFRESH_RATE 0x0002100F

    #define GLFW_DOUBLEBUFFER 0x00021010

    #define GLFW_CLIENT_API 0x00022001

    #define GLFW_CONTEXT_VERSION_MAJOR 0x00022002

    #define GLFW_CONTEXT_VERSION_MINOR 0x00022003

    #define GLFW_CONTEXT_REVISION 0x00022004

    #define GLFW_CONTEXT_ROBUSTNESS 0x00022005

    #define GLFW_OPENGL_FORWARD_COMPAT 0x00022006

    #define GLFW_OPENGL_DEBUG_CONTEXT 0x00022007

    #define GLFW_OPENGL_PROFILE 0x00022008

    #define GLFW_CONTEXT_RELEASE_BEHAVIOR 0x00022009

    #define GLFW_CONTEXT_NO_ERROR 0x0002200A

    #define GLFW_CONTEXT_CREATION_API 0x0002200B

    #define GLFW_SCALE_TO_MONITOR 0x0002200C

    #define GLFW_COCOA_RETINA_FRAMEBUFFER 0x00023001

    #define GLFW_COCOA_FRAME_NAME 0x00023002

    #define GLFW_COCOA_GRAPHICS_SWITCHING 0x00023003

    #define GLFW_X11_CLASS_NAME 0x00024001

    #define GLFW_X11_INSTANCE_NAME 0x00024002

    类型定义

    typedef struct GLFWwindow GLFWwindow

    typedef void(* GLFWwindowposfun) (GLFWwindow *, int, int)

    typedef void(* GLFWwindowsizefun) (GLFWwindow *, int, int)

    typedef void(* GLFWwindowclosefun) (GLFWwindow *)

    typedef void(* GLFWwindowrefreshfun) (GLFWwindow *)

    typedef void(* GLFWwindowfocusfun) (GLFWwindow *, int)

    typedef void(* GLFWwindowiconifyfun) (GLFWwindow *, int)

    typedef void(* GLFWwindowmaximizefun) (GLFWwindow *, int)

    typedef void(* GLFWframebuffersizefun) (GLFWwindow *, int, int)

    typedef void(* GLFWwindowcontentscalefun) (GLFWwindow *, float, float)

    typedef struct GLFWimage GLFWimage

    函数定义

    void glfwDefaultWindowHints (void)

    void glfwWindowHint (int hint, int value)

    void glfwWindowHintString (int hint, const char *value)

    GLFWwindow * glfwCreateWindow (int width, int height, const char *title, GLFWmonitor *monitor, GLFWwindow *share)

    void glfwDestroyWindow (GLFWwindow *window)

    int glfwWindowShouldClose (GLFWwindow *window)

    void glfwSetWindowShouldClose (GLFWwindow *window, int value)

    void glfwSetWindowTitle (GLFWwindow *window, const char *title)

    void glfwSetWindowIcon (GLFWwindow *window, int count, const GLFWimage *images)

    void glfwGetWindowPos (GLFWwindow *window, int *xpos, int *ypos)

    void glfwSetWindowPos (GLFWwindow *window, int xpos, int ypos)

    void glfwGetWindowSize (GLFWwindow *window, int *width, int *height)

    void glfwSetWindowSizeLimits (GLFWwindow *window, int minwidth, int minheight, int maxwidth, int maxheight)

    void glfwSetWindowAspectRatio (GLFWwindow *window, int numer, int denom)

    void glfwSetWindowSize (GLFWwindow *window, int width, int height)

    void glfwGetFramebufferSize (GLFWwindow *window, int *width, int *height)

    void glfwGetWindowFrameSize (GLFWwindow *window, int *left, int *top, int *right, int *bottom)

    void glfwGetWindowContentScale (GLFWwindow *window, float *xscale, float *yscale)

    float glfwGetWindowOpacity (GLFWwindow *window)

    void glfwSetWindowOpacity (GLFWwindow *window, float opacity)

    void glfwIconifyWindow (GLFWwindow *window)

    void glfwRestoreWindow (GLFWwindow *window)

    void glfwMaximizeWindow (GLFWwindow *window)

    void glfwShowWindow (GLFWwindow *window)

    void glfwHideWindow (GLFWwindow *window)

    void glfwFocusWindow (GLFWwindow *window)

    void glfwRequestWindowAttention (GLFWwindow *window)

    GLFWmonitor * glfwGetWindowMonitor (GLFWwindow *window)

    void glfwSetWindowMonitor (GLFWwindow *window, GLFWmonitor *monitor, int xpos, int ypos, int width, int height, int refreshRate)

    int glfwGetWindowAttrib (GLFWwindow *window, int attrib)

    void glfwSetWindowAttrib (GLFWwindow *window, int attrib, int value)

    void glfwSetWindowUserPointer (GLFWwindow *window, void *pointer)

    void * glfwGetWindowUserPointer (GLFWwindow *window)

    GLFWwindowposfun glfwSetWindowPosCallback (GLFWwindow *window, GLFWwindowposfun cbfun)

    GLFWwindowsizefun glfwSetWindowSizeCallback (GLFWwindow *window, GLFWwindowsizefun cbfun)

    GLFWwindowclosefun glfwSetWindowCloseCallback (GLFWwindow *window, GLFWwindowclosefun cbfun)

    GLFWwindowrefreshfun glfwSetWindowRefreshCallback (GLFWwindow *window, GLFWwindowrefreshfun cbfun)

    GLFWwindowfocusfun glfwSetWindowFocusCallback (GLFWwindow *window, GLFWwindowfocusfun cbfun)

    GLFWwindowiconifyfun glfwSetWindowIconifyCallback (GLFWwindow *window, GLFWwindowiconifyfun cbfun)

    GLFWwindowmaximizefun glfwSetWindowMaximizeCallback (GLFWwindow *window, GLFWwindowmaximizefun cbfun)

    GLFWframebuffersizefun glfwSetFramebufferSizeCallback (GLFWwindow *window, GLFWframebuffersizefun cbfun)

    GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback (GLFWwindow *window, GLFWwindowcontentscalefun cbfun)

    void glfwPollEvents (void)

    void glfwWaitEvents (void)

    void glfwWaitEventsTimeout (double timeout)

    void glfwPostEmptyEvent (void)

    void glfwSwapBuffers (GLFWwindow *window)

    关于Gamma校正

    比较两幅图像

    图一:没有gamma校正


    没有gamma校正

    图二:gamma校正


    gamma校正

    说明

    1. 在场景中放置一个球,使用默认的Diffuse材质,打一个平行光;

    2. 在真实场景中看到的与在电脑上看见的是不一样的。

    3. 假设球上有一点B,它的法线和光线方向成60°,还有一点A,它的法线和光线方向成90°,计算输出的时候,会得出B的输出是(0.5, 0.5, 0.5),A的输出的(1.0, 1.0, 1.0)。

      • 法向量就是垂直切面的向量(球面上的点到圆心直线的向量),按照sin求输出;
    4. 在第一张图中,没有进行伽马校正。因此,在把像素值转换到屏幕亮度时并不是线性关系,也就是说B点的亮度其实并不是A亮度的一半,在Mac显示器上,这个亮度只有A亮度的1/1.8呗,约为四分之一。在第二张图中,进行了伽马校正,此时的亮度才是真正跟像素值成正比的。

    Gamma校正公式

    • f(x)= x^{\gamma}
    gamma校正公式与原理示意图
    • \gamma = 1 就是恒等值线;
    • \gamma < 1 就是恒等直线的下半实线;
      • x \in [0, 0.22],y \in [0, 0.5],在亮度较暗的区域y值活动范围大,对比度增强;
      • x \in [0.8, 1],y \in [0.9, 1], 在亮度较高的区域y值活动范围变小,对比度减弱;
      • \gamma > 1的时候,图像整体灰度变大。
    • \gamma > 1 就是恒等直线的上半虚线;
      • \gamma > 1 图像整体灰度减少;
      • x \in [0, 0.72],y \in [0, 0.5],在亮度较暗的区域y值活动范围小,对比度减弱;
      • x \in [0.9, 1],y \in [0.8, 1], 在亮度较高的区域y值活动范围变大,对比度增强;

    gamma校正的效果

    不同gamma值得校正效果比较

    gamma校正算法

    • 假设图像中有一个像素A,值是200 ,那么对这个像素进行校正必须执行如下步骤:
      1. 归一化 :将像素值转换为0~1之间的实数。
        • 算法如下 : \dfrac{( A + 0. 5)}{256} 这里包含1个除法和1个加法操作。
        • 对于像素A而言 , 其对应的归一化值为0. 783203
      2. 预补偿 :根据公式 , 求出像素归一化后的数据以\dfrac{1}{\gamma}为指数的对应值。
        • 这一步包含一个求指数运算。若\gamma 值为2.2, 则\dfrac{1}{\gamma}0.454545
        • 对归一化后的A值进行预补偿的结果就是{0.783203}^{0.454545} = 0. 894872
      3. 反归一化 :将经过预补偿的实数值反变换为0~255之间的整数值。
        • 具体算法为 : f \times 256 - 0.5 此步骤包含1个乘法和1个减法运算。
        • 续前例 , 将A的预补偿结果0.894872代入上式 , 得到A预补偿后对应的像素值228 , 这个228就是最后送入显示器的数据。

    相关文章

      网友评论

        本文标题:GL01-03:GLFW窗体

        本文链接:https://www.haomeiwen.com/subject/zskvrctx.html