GL01-03:GLFW窗体
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校正的概念与使用
创建窗体
窗体对象
- 窗体对象的说明:
- 窗体对象GLFWwindow是一个结构体,封装了Window及其工作的上下文;
- 由于窗口和上下文是不可分割的链接,因此对象指针同时用作上下文和窗口句柄;
- 窗体的创建使用glfwCreateWindow函数;
- 窗体的释放使用glfwDestroyWindow函数, 或者粗暴的使用glfwTerminate函数结束一切;
GLFWwindow的定义
typedef struct GLFWwindow GLFWwindow;
创建窗体
- 函数说明
GLFWwindow* glfwCreateWindow (
int width, // 窗体宽度;
int height, // 窗体高度;
const char * title, // 窗体标题;
GLFWmonitor * monitor, // 用来指定全屏显示模式的对象,NULL就是普通窗体模式;
GLFWwindow * share // 需要共享窗体资源的窗体对象,NULL表示没有共享的窗体的对象;
)
释放窗体
- 函数说明
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
关闭操作标记获取
- glfwWindowShouldClose 函数定义说明
int glfwWindowShouldClose( GLFWwindow * window )
- 函数的返回值int是关闭标记,类型是逻辑类型
- GLFW_TRUE:关闭操作
- GLFW_FALSE:没有关闭操作
设置窗体关闭标记
- glfwSetWindowShouldClose函数说明
void glfwSetWindowShouldClose (
GLFWwindow * window,
int value // GLFW_TRUE或者GLFW_FALSE
)
通过关闭标记来阻止应用结束
- 可以通过对关闭标记的判定,来决定是否结束应用,编程方式就是根据关闭标记来做循环。
while (! glfwWindowShouldClose(window));
窗体的消息处理
- 通过窗体的关闭标记进入循环,主线程占用计算资源,窗体无法处理消息,需要调用函数来处理窗体的消息;
- 窗体的消息处理函数有三个:
-
glfwPollEvents
:处理消息 -
glfwWaitEvents
:等待消息 -
glfwWaitEventsTimeout
:延时等待消息
-
- glfwPollEvents函数定义
- 该函数只处理已经发生的在系统消息队列中的消息,消息处理完毕后马上返回。如果在循环中不调用该函数处理消息,所有的交互操作与事件都无法响应;
- 所谓消息处理,就是根据不同的消息,处理对应的函数调用;
- 有的平台在窗体移动,缩放的时候,会导致消息处理阻塞(glfwPollEvents函数需要等消息响应完毕才返回),这就需要单独处理。
void glfwPollEvents ( void )
- glfwWaitEvents函数定义
- 该函数释放运算资源,处于睡眠状态,直到有消息产生;与上面的不同的是,这种情况循环不是一直持续的,而是有消息发生才运行;
void glfwWaitEvents ( void )
- glfwWaitEventsTimeout函数定义
- 这个函数是glfwWaitEvents函数的延时版本,就是在指定时间内,没有消息发生,该函数也会返回。
- 参数是浮点数,单位是秒。
void glfwWaitEventsTimeout ( double timeout )
一个典型的消息处理与应用结束处理例子
- 方式一:
- 主动处理式
#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
- 方式二:
- 被动等待式。
#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
消息等待中的唤醒
- 使用
glfwWaitEvents
与glfwWaitEventsTimeout
, 在没有消息发生的时候,主线程就会一直阻塞,如果在循环中处理业务,则会导致业务无法执行; - 函数
glfwPostEmptyEvent
用来唤醒glfwWaitEvents
函数的阻塞。
- 函数glfwPostEmptyEvent定义
void glfwPostEmptyEvent (void)
监视器
监视器对象
- 全屏窗体是使用窗体创建函数
glfwCreateWindow
的时候,需要指定一个监视器对象。- 监视器也是一个结构体,定义如下:
typedef struct GLFWmonitor GLFWmonitor
- 监视器也是一个结构体,定义如下:
获取监视器对象
- 监视器对象通过函数获取,不用使用代码创建,获取监视器的函数有:
-
glfwGetPrimaryMonitor
: 获取主监视器; -
glfwGetMonitors
:获取所有监视器;
-
- glfwGetPrimaryMonitor函数说明
GLFWmonitor* glfwGetPrimaryMonitor (void)
- glfwGetMonitors函数说明
GLFWmonitor** glfwGetMonitors (int * count)
- 获取监视器例子代码
#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
:该函数设置一个回调函数,一旦监视器配置发生改变,则回调函数得到调用,并返回监视器配置改变的参数。
-
- glfwSetMonitorCallback函数说明:
GLFWmonitorfun glfwSetMonitorCallback ( GLFWmonitorfun cbfun )
- 监视器回调函数的原型定义:
-typedef void(* GLFWmonitorfun) (GLFWmonitor *, int)
- 参数GLFWmonitor *
返回变化的监视器;
- 参数int
返回监视器配置变化的事件类型:
- GLFW_CONNECTED
- GLFW_DISCONNECTED.
视频模式
- 监视器的视频模式,通过两个函数可以查询监视器的视频模式:
glfwGetVideoModes
glfwGetVideoMode
- glfwGetVideoModes函数定义
const GLFWvidmode* glfwGetVideoModes (
GLFWmonitor * monitor,
int * count // 返回视频模式的数量
)
// 返回视频模式对象数组
- glfwGetVideoMode函数定义
const GLFWvidmode* glfwGetVideoMode ( GLFWmonitor * monitor )
// 返回当前的视频模式
- 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;
- 视频模式的使用例子
#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
获取
- glfwGetMonitorPhysicalSize函数定义
void glfwGetMonitorPhysicalSize (
GLFWmonitor * monitor,
int * widthMM, // 返回宽度
int * heightMM // 返回高度
)
内容缩放
- 使用函数
glfwGetMonitorContentScale
获取
- glfwGetMonitorContentScale函数定义
void glfwGetMonitorContentScale (
GLFWmonitor * monitor,
float * xscale, // x方向缩放
float * yscale // y方向缩放
)
虚拟位置
- 使用函数
glfwGetMonitorPos
获取
- glfwGetMonitorPos函数说明
void glfwGetMonitorPos (
GLFWmonitor * monitor,
int * xpos, // x-位置
int * ypos // y-位置
)
- 屏幕坐标系
- 如果系统链接多个监视器,则使用虚拟屏幕的概念,如下图所示:
- 监视器对象的屏幕管理坐标系
- GLFW有两个主要的坐标系统:虚拟屏幕和窗口内容区域或内容区域。
- 两者都使用相同的单位:虚拟屏幕坐标,或者只是屏幕坐标,它们不一定使用像素单位。
工作区域
- 使用函数
glfwGetMonitorWorkarea
获取
- 函数
glfwGetMonitorWorkarea
定义
void glfwGetMonitorWorkarea (
GLFWmonitor * monitor,
int * xpos, // 区域原点
int * ypos,
int * width, // 区域大小
int * height
)
监视器可阅读的名字
- 使用函数
glfwGetMonitorName
获取
- 函数
glfwGetMonitorName
定义
const char* glfwGetMonitorName ( GLFWmonitor * monitor )
监视器用户指针
- 监视器用户指针,用来存放用户数据;包括存取函数:
- 存函数:
glfwSetMonitorUserPointer
- 取函数:
glfwGetMonitorUserPointer
- 存函数:
- 函数
glfwSetMonitorUserPointer
定义
void glfwSetMonitorUserPointer (
GLFWmonitor * monitor,
void * pointer
)
- 函数
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
- 获取gamma参数
- 函数
glfwGetGammaRamp
定义
const GLFWgammaramp* glfwGetGammaRamp ( GLFWmonitor * monitor )
- 函数
glfwSetGammaRamp
定义
void glfwSetGammaRamp (
GLFWmonitor * monitor,
const GLFWgammaramp * ramp
)
- 该函数设置Gamma斜面的时候,GLFW会保存原来的Gamma Ramp,并在环境退出的时候,会恢复。
- 结构体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;
- 函数
glfwSetGamma
定义- 没有对应的获取函数。
void glfwSetGamma (
GLFWmonitor * monitor,
float gamma
)
- 参数gamma必须是大于0的数。
监视器的属性使用例子代码
- 属性使用例子代码-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
-
属性使用例子代码-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
- 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,图像的红色丢失。
- 下面代码把64改成其他值试试
#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
函数任何时候改变窗体的监视器,实现全屏;
- 函数
glfwSetWindowMonitor
定义
void glfwSetWindowMonitor (
GLFWwindow * window,
GLFWmonitor * monitor,
int xpos,
int ypos,
int width,
int height,
int refreshRate
)
- 函数说明:
- 当参数monitor有效的时候,xpos与ypos没有作用;
- 当参数monitor无效的时候,refreshRate参数无用,窗体的位置与大小会改变;
- 设置窗体监视器的例子代码
#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
- 获取窗体的监视器函数定义:
GLFWmonitor* glfwGetWindowMonitor ( GLFWwindow * window )
窗体创建中的提示设置
- 通过窗体创建函数的参数对窗体设置的功能太简单,如果需要更多的窗体控制,则可以使用从窗体的提示设置;
- 提示设置一定在窗体创建前设置。
- 提示设置影响的对象:
- 窗体本身;
- 缓冲帧;
- 环境上下文;
提示设置函数
- 提示设置相关的函数三个:
-
glfwWindowHint
:设置提示:数据整数; -
glfwWindowHintString
:设置提示:数据字符串; -
glfwDefaultWindowHints
:重置缺省提示值;
-
- glfwWindowHint函数定义
void glfwWindowHint (
int hint,
int value
)
- glfwWindowHintString函数定义
void glfwWindowHintString (
int hint,
const char * value
)
- 这个函数用来设置字符串类型的Hint,字符串的Hint不多,比如下面的表格中GLFW_X11_CLASS_NAME就是字符串Hint
- glfwDefaultWindowHints函数定义
void glfwDefaultWindowHints ( void )
- 在创建窗体前调用,不要指望这个函数在创建窗体后调用,也会马上有效果。
Hint的硬约束与软约束
- 一些窗口提示是硬约束。这些功能必须与可用功能完全匹配,才能成功创建窗口和上下文。
- 非硬约束的提示尽可能匹配,但生成的上下文和帧缓冲区可能与这些提示请求的不同。
-
常见的硬约束
- GLFW_STEREO
- GLFW_DOUBLEBUFFER
- GLFW_CLIENT_API
- GLFW_CONTEXT_CREATION_API
-
只对OpenGL的硬约束提示,对OpenGL ES无效的硬约束提示
- GLFW_OPENGL_FORWARD_COMPAT
- GLFW_OPENGL_PROFILE
窗体的提示分类
- 窗体的提示类别有
- 窗体有关的提示:常用
- 缓冲帧相关的提示(Framebuffer):常用
- 监视器相关的提示;
- 上下文(Context)相关的提示;
- Mac OS独有的提示;
- 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 :获取用户数据指针;
- glfwSetWindowUserPointer函数说明
void glfwSetWindowUserPointer (
GLFWwindow * window,
void * pointer
)
- glfwGetWindowUserPointer函数说明
void* glfwGetWindowUserPointer ( GLFWwindow * window )
- 例子代码参考:监视器的用户指针;
窗体的关闭
- 提供三个函数处理窗体的关闭:
- glfwWindowShouldClose :获取关闭标志;
- glfwSetWindowShouldClose :设置关闭标志,手工关闭;
- glfwSetWindowCloseCallback:窗体关闭标志改变前的回调函数设置;
- glfwWindowShouldClose函数说明
int glfwWindowShouldClose ( GLFWwindow * window )
- glfwSetWindowShouldClose 函数说明
void glfwSetWindowShouldClose (
GLFWwindow * window,
int value // GLFW_TRUE 或者 GLFW_FALSE
)
- glfwSetWindowCloseCallback函数说明
GLFWwindowclosefun glfwSetWindowCloseCallback (
GLFWwindow * window,
GLFWwindowclosefun cbfun
)
- GLFWwindowclosefun回调函数原型定义
typedef void(* GLFWwindowclosefun) (GLFWwindow *)
- 控制窗体关闭的例子代码
- 下面代码使用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的大小混用;
- glfwSetWindowSize函数说明
void glfwSetWindowSize (
GLFWwindow * window,
int width,
int height
)
- glfwGetWindowSize函数说明
void glfwGetWindowSize (
GLFWwindow * window,
int * width,
int * height
)
- glfwSetWindowSizeCallback函数说明
GLFWwindowsizefun glfwSetWindowSizeCallback (
GLFWwindow * window,
GLFWwindowsizefun cbfun
)
- GLFWwindowsizefun回调函数说明
typedef void(* GLFWwindowsizefun) (GLFWwindow *, int, int)
- glfwGetWindowFrameSize函数说明
void glfwGetWindowFrameSize (
GLFWwindow * window,
int * left,
int * top,
int * right,
int * bottom
)
- glfwGetWindowSize获取的内容区的大小,这个函数glfwGetWindowFrameSize获取窗体的边狂大小,left、top、right、bottom表示的是内容区域边界到窗体边界的距离,所以这个值总是0或者 >0
- 一般标题栏方向为22,因为标题栏的宽度为22像素,其他方向都是0(就是内容区边缘与窗体的边缘重叠)
- 监控窗体大小改变的例子:
#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;
-
参考上面的例子代码。
- glfwGetFramebufferSize函数说明
void glfwGetFramebufferSize (
GLFWwindow * window,
int * width,
int * height
)
- glfwSetFramebufferSizeCallback函数说明
GLFWframebuffersizefun glfwSetFramebufferSizeCallback (
GLFWwindow * window,
GLFWframebuffersizefun cbfun
)
窗体内容缩放
-
窗体缩放也是两个函数
-
glfwGetWindowContentScale
:获取内容缩放; -
glfwSetWindowContentScaleCallback
:缩放比例改变的回调函数设置函数;
-
-
例子代码参考窗体大小的例子。
- glfwGetWindowContentScale函数说明:
void glfwGetWindowContentScale (
GLFWwindow * window,
float * xscale,
float * yscale
- glfwSetWindowContentScaleCallback函数说明:
GLFWwindowcontentscalefun glfwSetWindowContentScaleCallback (
GLFWwindow * window,
GLFWwindowcontentscalefun cbfun
)
- 回调函数GLFWwindowcontentscalefun的原型定义
typedef void(* GLFWwindowcontentscalefun) (GLFWwindow *, float, float)
窗体大小限制
- 窗体大小的最大值与最小值,提供如下函数管理:
-
glfwSetWindowSizeLimits
:设置窗体大小的最大与最小限制; -
glfwSetWindowAspectRatio
:设置窗体的高宽比例。
-
- glfwSetWindowSizeLimits函数说明
void glfwSetWindowSizeLimits (
GLFWwindow * window,
int minwidth,
int minheight,
int maxwidth,
int maxheight
)
- glfwSetWindowAspectRatio函数说明
void glfwSetWindowAspectRatio (
GLFWwindow * window,
int numer, //所需纵横比的分子
int denom //所需纵横比的分母
)
窗体位置
- 窗体位置提供三个函数管理:
-
glfwSetWindowPos
:设置窗体位置; -
glfwSetWindowPosCallback
:窗体位置变化的回调函数设置函数; -
glfwGetWindowPos
:获取窗体的位置;
-
- glfwSetWindowPos函数说明
void glfwSetWindowPos (
GLFWwindow * window,
int xpos,
int ypos
)
- glfwSetWindowPosCallback函数说明
GLFWwindowposfun glfwSetWindowPosCallback (
GLFWwindow * window,
GLFWwindowposfun cbfun
)
- GLFWwindowposfun原型说明
typedef void(* GLFWwindowposfun) (GLFWwindow *, int, int)
- glfwGetWindowPos函数说明
void glfwGetWindowSize (
GLFWwindow * window,
int * width,
int * height
)
窗体标题
- 只提供窗体标题设置函数
-
glfwSetWindowTitle
:设置窗体标题,C++11支持unicode:glfwSetWindowTitle(window, u8"This is always a UTF-8 string");
-
- glfwSetWindowTitle函数说明
void glfwSetWindowTitle (
GLFWwindow * window,
const char * title
)
窗体图标
- 图标只能设置:
-
glfwSetWindowIcon
:设置图标
-
- glfwSetWindowIcon函数说明
- 此函数设置指定窗口的图标。如果传递了一组候选图像,则会选择系统所需大小或最接近系统所需大小的图像。如果未指定图像,窗口将恢复为其默认图标。
- MAC 系统的glfw窗口没有图标,因为它不是文档窗口,所以此函数不起任何作用。Dock图标将与应用程序包的图标相同。
void glfwSetWindowIcon (
GLFWwindow * window,
int count, // 图像数量
const GLFWimage * images // 图像数据结构
)
- 图像结构体
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。
- 图标使用的例子
#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
:设置
-
-
例子参考前面使用监视器全屏化的例子。
- glfwGetWindowMonitor函数说明
GLFWmonitor* glfwGetWindowMonitor(GLFWwindow * window )
- glfwSetWindowMonitor函数说明
void glfwSetWindowMonitor(GLFWwindow * window,
GLFWmonitor * monitor,
int xpos,
int ypos,
int width,
int height,
int refreshRate
)
窗体图标化
- 提供管理函数如下
-
glfwIconifyWindow
:图标化窗体; -
glfwRestoreWindow
:从图标化恢复窗体; -
glfwSetWindowIconifyCallback
:窗体图标化的回调函数设置函数; -
glfwGetWindowAttrib
:获取当前图标化状态;
-
- glfwIconifyWindow函数说明
void glfwIconifyWindow ( GLFWwindow * window )
- glfwRestoreWindow函数说明
void glfwRestoreWindow ( GLFWwindow * window )
- glfwSetWindowIconifyCallback函数说明
GLFWwindowiconifyfun glfwSetWindowIconifyCallback (
GLFWwindow * window,
GLFWwindowiconifyfun cbfun
)
- 回调函数GLFWwindowiconifyfun原型说明
typedef void(* GLFWwindowiconifyfun) (GLFWwindow *, int)
- 其中第二个参数是图标化状态:
- GLFW_TRUE:图标化
- GLFW_FALSE:非图标化
- glfwGetWindowAttrib函数说明
int glfwGetWindowAttrib (
GLFWwindow * window,
int attrib
)
- 窗体特性
- 与窗体有关的特性包含:
- 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
:在创建窗体时设置最大化;
- glfwMaximizeWindow函数说明
void glfwMaximizeWindow ( GLFWwindow * window )
- glfwSetWindowMaximizeCallback函数说明
GLFWwindowmaximizefun glfwSetWindowMaximizeCallback (
GLFWwindow * window,
GLFWwindowmaximizefun cbfun
)
- GLFWwindowmaximizefun回调函数原型说明
typedef void(* GLFWwindowmaximizefun) (GLFWwindow *, int)
// 参数是逻辑值,GLFW_TRUE 与 GLFW_FALSE
窗体可见
-
glfwHideWindow
:隐藏窗体 -
glfwShowWindow
:显示窗体 -
glfwGetWindowAttrib
:获取窗体是否可见状态; -
glfwWindowHint
:在创建窗体设置窗体的可见状态;
- 函数说明
void glfwHideWindow ( GLFWwindow * window )
- 函数说明
void glfwShowWindow ( GLFWwindow * window )
窗体输入焦点
-
glfwFocusWindow
:使窗体获取焦点; -
glfwSetWindowFocusCallback
:焦点状态改变的回调函数设置; -
glfwGetWindowAttrib
:获取窗体的焦点状态特性; -
glfwWindowHint
:在创建窗体设置是否拥有焦点;
- 函数说明
void glfwFocusWindow ( GLFWwindow * window )
- 函数说明
GLFWwindowfocusfun glfwSetWindowFocusCallback (
GLFWwindow * window,
GLFWwindowfocusfun cbfun
)
- GLFWwindowfocusfun回调函数原型说明
typedef void(* GLFWwindowfocusfun) (GLFWwindow *, int)
// 第二个参数:焦点状态:GLFW_TRUE 或 GLFW_FALSE
窗体关注
glfwRequestWindowAttention
- glfwRequestWindowAttention函数说明
void glfwRequestWindowAttention ( GLFWwindow * window )
窗体刷新
-
glfwSetWindowRefreshCallback
:设置窗体刷新的回调机制;- 窗体刷新的机制通过回调函数获取是否需要刷新的信息。
- 一般窗体上发生像素破坏:比如窗体移动,最小化等;
- 刷新时候可以完成图形绘制,以及缓冲切换;
- 窗体刷新的机制通过回调函数获取是否需要刷新的信息。
- glfwSetWindowRefreshCallback函数说明
GLFWwindowrefreshfun glfwSetWindowRefreshCallback (
GLFWwindow * window,
GLFWwindowrefreshfun cbfun
)
- 回调函数GLFWwindowrefreshfun原型说明
typedef void(* GLFWwindowrefreshfun) (GLFWwindow *)
窗体透明
-
glfwSetWindowOpacity
:设置窗体的透明度; -
glfwGetWindowOpacity
:获取窗体的透明度; -
glfwGetWindowAttrib
:获取FrameBuffer是否支持透明;- GLFW_TRANSPARENT_FRAMEBUFFER
-
glfwWindowHint
:创建窗体时,设置FrameBuffer透明度;- GLFW_TRANSPARENT_FRAMEBUFFER
- glfwSetWindowOpacity函数说明:
void glfwSetWindowOpacity (
GLFWwindow * window,
float opacity
)
- 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有关的特性;(参考官方文档)
- glfwGetWindowAttrib函数说明
int glfwGetWindowAttrib (
GLFWwindow * window,
int attrib
)
- glfwSetWindowAttrib函数说明
void glfwSetWindowAttrib(
GLFWwindow * window,
int attrib,
int value
)
双缓冲与交换
-
因为双缓冲的目的是:
- 一个缓冲处理图像;
- 一个缓冲显示图像;
-
一但显示的图像绘制完成,可以调用函数切换前后缓冲
-
glfwSwapBuffers
:交换缓冲区 -
glfwSwapInterval
:有时,选择何时进行缓冲区交换可能很有用。使用函数glfwSwapInterval,从调用glfwSwapBuffer开始,可以选择驱动程序在交换缓冲区之前应等待的最小监视器刷新数。
-
- glfwSwapBuffers函数说明
void glfwSwapBuffers(GLFWwindow * window)
- glfwSwapInterval函数说明
void glfwSwapInterval(int interval)
- 如果间隔为零,则当调用glfwSwapBuffers而不等待刷新时,交换将立即发生。否则,缓冲区交换满足监视器刷新的最小数。
- 通过监视器的刷新最小数量设置,可以方式图像显示撕裂(显示部分,就刷新到下一帧图像)。
- 该函数可以在glfwSwapBuffers调用前设置。
- 经典的绘制刷新模式
#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
- 提示:
- 还可以通过刷新回调来实现图形绘制。
附录
宏定义
#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校正
说明
-
在场景中放置一个球,使用默认的Diffuse材质,打一个平行光;
-
在真实场景中看到的与在电脑上看见的是不一样的。
-
假设球上有一点B,它的法线和光线方向成60°,还有一点A,它的法线和光线方向成90°,计算输出的时候,会得出B的输出是(0.5, 0.5, 0.5),A的输出的(1.0, 1.0, 1.0)。
- 法向量就是垂直切面的向量(球面上的点到圆心直线的向量),按照sin求输出;
-
在第一张图中,没有进行伽马校正。因此,在把像素值转换到屏幕亮度时并不是线性关系,也就是说B点的亮度其实并不是A亮度的一半,在Mac显示器上,这个亮度只有A亮度的1/1.8呗,约为四分之一。在第二张图中,进行了伽马校正,此时的亮度才是真正跟像素值成正比的。
Gamma校正公式
- 当 就是恒等值线;
- 当 就是恒等直线的下半实线;
- ,在亮度较暗的区域y值活动范围大,对比度增强;
- , 在亮度较高的区域y值活动范围变小,对比度减弱;
- 当的时候,图像整体灰度变大。
- 当 就是恒等直线的上半虚线;
- 当 图像整体灰度减少;
- ,在亮度较暗的区域y值活动范围小,对比度减弱;
- , 在亮度较高的区域y值活动范围变大,对比度增强;
gamma校正的效果
不同gamma值得校正效果比较gamma校正算法
- 假设图像中有一个像素,值是 ,那么对这个像素进行校正必须执行如下步骤:
- 归一化 :将像素值转换为之间的实数。
- 算法如下 : 这里包含个除法和个加法操作。
- 对于像素而言 , 其对应的归一化值为 。
- 预补偿 :根据公式 , 求出像素归一化后的数据以为指数的对应值。
- 这一步包含一个求指数运算。若 值为, 则为;
- 对归一化后的A值进行预补偿的结果就是。
- 反归一化 :将经过预补偿的实数值反变换为0~255之间的整数值。
- 具体算法为 : 此步骤包含个乘法和个减法运算。
- 续前例 , 将的预补偿结果代入上式 , 得到预补偿后对应的像素值 , 这个就是最后送入显示器的数据。
- 归一化 :将像素值转换为之间的实数。