可以使用 eglGetConfig() 获取指定 display 支持的所有config
dsp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
EGLConfig xconfig[100];
EGLint xsize;
if (!eglGetConfigs(dsp, &xconfig, 100, &xsize)){
printf(" eglGetError() = 0x%x \n", eglGetError());
assert(0 && "eglGetConfigs failad");
}
printf(" xsize = %d \n", xsize);
for (int i = 0; i < xsize; ++i) {
EGLint value;
eglGetConfigAttrib(dsp, xconfig[i], EGL_RED_SIZE, &value);
printf("Config %d: Red Size = %d\n", i, value);
eglGetConfigAttrib(dsp, xconfig[i], EGL_GREEN_SIZE,&value);
printf("Config %d: Green Size = %d\n", i, value);
eglGetConfigAttrib(dsp, xconfig[i], EGL_BLUE_SIZE, &value);
printf("Config %d: Blue Size = %d\n", i, value);
eglGetConfigAttrib(dsp, xconfig[i], EGL_RENDERABLE_TYPE, &value);
printf("Config %d: EGL_RENDERABLE_TYPE = 0x%x\n", i, value);
eglGetConfigAttrib(dsp, xconfig[i], EGL_SURFACE_TYPE, &value);
printf("Config %d: EGL_SURFACE_TYPE = 0x%x\n", i, value);
}
非常好用的函数:eglGetError()/glGetError()
用来排错,只调用了 egl/gl 接口后,可以使用该函数来诊断调用有没有出错,用法:
eglInitialize(dsp, &majorVersion, &minorVersion);
printf(" eglGetError() = 0x%x \n", eglGetError());
position_loc = glGetAttribLocation((GLuint)program, "position");
printf(" eglGetError() = 0x%x \n", glGetError());
使用 EGL 创建上下文:
EGLDisplay display;
EGLContext context;
EGLSurface surface;
// 2. 配置 EGL 属性
const EGLint attribs[] = {
EGL_RED_SIZE, 8,
EGL_GREEN_SIZE, 8,
EGL_BLUE_SIZE, 8,
EGL_DEPTH_SIZE, 24,
EGL_SAMPLES, 0,
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES_BIT,
EGL_SURFACE_TYPE, EGL_PBUFFER_BIT,
EGL_ALPHA_SIZE, 0,
EGL_STENCIL_SIZE, 8,
EGL_NONE
};
// 1. 初始化 EGL 显示连接
display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
if (display == EGL_NO_DISPLAY)
{
assert(0 && "EGL get display failed!");
}
if (!eglInitialize(display, NULL, NULL))
{
assert(0 && "EGL initialize falledl");
}
if (!eglBindAPI(EGL_OPENGL_API))
{
assert(0 && "EGL bind API failed!");
}
EGLConfig config;
EGLint numConfigs;
if(!eglChooseConfig(display, attribs, &config, 1, &numConfigs)){
assert(0 && "eglchooseConfig failad");
}
if (numConfigs < 1)
{
assert(numConfigs < 1);
exit(0);
}
// 3. 创建 EGL 上下文
const EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
context = eglCreateContext(display, config, EGL_NO_CONTEXT, contextAttribs);
if (context == EGL_NO_CONTEXT)
{
assert(0 && "eglCreateContext failed");
}
// 4. 创建表面
const EGLint pbufferAttribs[] = {
EGL_WIDTH, SCREEN_WIDTH,
EGL_HEIGHT, SCREEN_HEIGHT,
EGL_NONE,
};
surface = eglCreatePbufferSurface(display, config, pbufferAttribs);
if ( surface == EGL_NO_SURFACE)
{
printf(" EGL_NO_SURFACE \n");
assert(0 && "glCreateWindowsurface failed");
}
// 5. 激活上下文
if (!eglMakeCurrent(display, surface, surface, context)){
assert(0 && "eglMakeCurrent failed");
}
创建完上下文之后,可以使用 gl 接口获取硬件&驱动信息:
printf(" GPU vendor : %s\n", glGetString(GL_VENDOR));
printf(" GL version : %s\n", glGetString(GL_VERSION));
使用 shader 创建着色器程序:
static const char vertex_shader[] =
"#version 300 es\n"
"in vec3 position;\n"
"in vec3 color;\n"
"out vec3 vertexColor;\n"
"void main()\n"
"{\n"
" gl_Position = vec4(position, 1.0);\n"
" vertexColor = color;\n"
"}\0";
static const char fragment_shader[] =
"#version 300 es\n"
"precision mediump float;\n"
"in vec3 vertexColor;\n"
"out vec4 fragmentColor;\n"
"void main()\n"
"{\n"
" fragmentColor = vec4(vertexColor, 1.0);\n"
"}\0";
GLuint gles2_api_create_program(const char *vs_src, const char *fs_src)
{
GLuint prog, vs, fs;
GLint compiled, linked, pos;
char *buffer;
if ((NULL == vs_src) || (NULL == fs_src))
{
printf("gles2_api_create_program: Invalid input parameters\n");
return 0;
}
buffer = (char *)malloc(GLES2_API_BUFFERSIZE);
if (NULL == buffer)
{
printf("gles2_api_create_program: Unable to allocate %i bytes.\n", GLES2_API_BUFFERSIZE);
return 0;
}
vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, &vs_src, NULL);
glCompileShader(vs);
glGetShaderiv(vs, GL_COMPILE_STATUS, &compiled);
if (GL_FALSE == compiled)
{
glGetShaderInfoLog(vs, GLES2_API_BUFFERSIZE - 1, NULL, buffer);
printf("gles2_api_create_program: Unable to compile vertex shader - reason: \n%s\n", buffer);
free(buffer);
return 0;
}
fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, &fs_src, NULL);
glCompileShader(fs);
glGetShaderiv(fs, GL_COMPILE_STATUS, &compiled);
if (GL_FALSE == compiled)
{
glGetShaderInfoLog(fs, GLES2_API_BUFFERSIZE - 1, NULL, buffer);
printf("gles2_api_create_program: Unable to compile fragment shader - reason: \n%s\n", buffer);
free(buffer);
return 0;
}
prog = glCreateProgram();
glAttachShader(prog, vs);
glAttachShader(prog, fs);
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &linked);
if (GL_FALSE == linked)
{
glGetProgramInfoLog(prog, GLES2_API_BUFFERSIZE - 1, NULL, buffer);
printf("gles2_api_create_program: Unable to link program - reason: \n%s\n\n", buffer);
free(buffer);
return 0;
}
glUseProgram(prog);
free(buffer);
return prog;
}
如果 glLinkProgram() 没有报错,则说明着色器程序创建成功。
使用创建的着色器程序绘制矩形:
{
GLint j, position_loc, color_loc, progs;
progs = create_program();
glGetIntegerv(GL_CURRENT_PROGRAM, &progs);
glUseProgram(progs);
GLfloat baseColors[] =
{(rand() % 256) / 255.0f, (rand() % 256) / 255.0f, (rand() % 256) / 255.0f};
// float baseVertices[] = {
// // 第一个三角形
// 0.5f, 0.5f, 0.0f, // 右上角
// 0.5f, -0.5f, 0.0f, // 右下角
// -0.5f, 0.5f, 0.0f, // 左上角
// // 第二个三角形
// 0.5f, -0.5f, 0.0f, // 右下角
// -0.5f, -0.5f, 0.0f, // 左下角
// -0.5f, 0.5f, 0.0f // 左上角
// };
float vertices[12];
GLfloat colors[12];
for (int i = 0; i < 12; i += 3) {
colors[i] = baseColors[0];
colors[i + 1] = baseColors[1];
colors[i + 2] = baseColors[2];
}
float ndcX1, ndcY1, ndcX2, ndcY2;
// glClear(GL_COLOR_BUFFER_BIT);
for (j = 0; j < PRIMSPERLIST; j++) {
// 更新顶点数据
// 生成随机位置
GLfloat cx = 0, cy = 0;
if (WIDTH < g_nScreenW) {
cx = rand() % (g_nScreenW - (GLint)WIDTH);
}
if (HEIGHT < g_nScreenH) {
cy = rand() % (g_nScreenH - (GLint)HEIGHT);
}
pixelToNDC(cx, cy, g_nScreenW, g_nScreenH, &ndcX1, &ndcY1);
pixelToNDC(cx + WIDTH, cy + HEIGHT, g_nScreenW, g_nScreenH, &ndcX2, &ndcY2);
float vertices[] = {
ndcX1, ndcY1, 0.0f, // 左下角
ndcX2, ndcY1, 0.0f, // 右下角
ndcX2, ndcY2, 0.0f, // 右上角
ndcX1, ndcY2, 0.0f // 左上角
};
position_loc = glGetAttribLocation((GLuint)progs, "position");
glEnableVertexAttribArray(position_loc);
glVertexAttribPointer((GLuint)position_loc, 3, GL_FLOAT, GL_FALSE, 0, vertices);
color_loc = glGetAttribLocation((GLuint)progs, "color");
glEnableVertexAttribArray(color_loc);
glVertexAttribPointer((GLuint)color_loc, 3, GL_FLOAT, GL_FALSE, 0, colors);
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
glDisableVertexAttribArray((GLuint)position_loc);
glDisableVertexAttribArray((GLuint)color_loc);
}
// glFinish();
glDeleteProgram(progs);
}
在使用着色器程序绘制顶点时,使用glVertexAttribPointer() 函数传入的 vertices[] 数组代表顶点的坐标,该坐标为标准化设备坐标(NDC),x, y, z 轴的坐标范围是 [-1.0, 1.0]。而不是像素坐标。使用标准化设备坐标的好处是提供一个与设备无关的坐标系统。在这个系统中,任何在屏幕上显示的点的坐标都需要在 -1.0 到 1.0 的范围内。
如果目标是绘制像素坐标,这需要进行 NDC坐标转换,将窗口中的像素坐标转换为 NDC 坐标:
参考函数:
void pixelToNDC(float pixelX, float pixelY, int windowWidth, int windowHeight, float *ndcX, float *ndcY) {
*ndcX = (pixelX / (float)windowWidth) * 2.0f - 1.0f;
*ndcY = (pixelY / (float)windowHeight) * 2.0f - 1.0f;
*ndcY = -*ndcY; // Y 轴在 OpenGL 中是倒置的
}
以后就跟博主混了