本文主要介绍在使用wayland 协议作为窗口系统的Linux系统中,如何使用 egl + opengles 绘制一个最简单的四边形,在阅读本篇文章之前,建议先读一下之前的文章 《wayland(xdg_wm_base) + egl + opengles 最简实例(一)》
软硬件环境:
硬件:PC
软件:ubuntu22.04 egl1.4 opengles2.0/3.0 weston9.0
使用opengles 绘制一个四边形需要有如下步骤:
其中对 VBO 的操作是可选的(即不使用VBO时 ,也能绘制四边形,但是效率比使用 VBO 时要低)
// Define the vertex positions of the quad
const GLfloat vertices[] = {
// x y z
-1.0f, -1.0f, 0.0f, // Bottom-left
1.0f, -1.0f, 0.0f, // Bottom-right
-1.0f, 1.0f, 0.0f, // Top-left
1.0f, 1.0f, 0.0f // Top-right
};
// Generate a vertex buffer object (VBO)
GLuint vbo;
glGenBuffers(1, &vbo);
// Bind the VBO to GL_ARRAY_BUFFER target
glBindBuffer(GL_ARRAY_BUFFER, vbo);
// Store vertex data in the VBO
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW);
// Enable vertex attribute array
glEnableVertexAttribArray(0);
// Set vertex attribute pointer
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, NULL);
// Draw the quad using glDrawArrays
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Disable the vertex attribute array
glDisableVertexAttribArray(0);
// Unbind the VBO
glBindBuffer(GL_ARRAY_BUFFER, 0);
// Delete the VBO
glDeleteBuffers(1, &vbo);
如下图所示,是实现绘制一个 640x480 的四边形,并且颜色由纯红色所填充(窗口大小是800x600, 窗口背景颜色是淡蓝色)的代码实例
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "xdg-shell-client-protocol.h"
#define WIDTH 800
#define HEIGHT 600
struct wl_display *display = NULL;
struct wl_compositor *compositor = NULL;
struct xdg_wm_base *wm_base = NULL;
struct wl_registry *registry = NULL;
struct window {
struct wl_surface *surface;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct wl_egl_window *egl_window;
};
// Index to bind the attributes to vertex shaders
const unsigned int VertexArray = 0;
static void
xdg_wm_base_ping(void *data, struct xdg_wm_base *shell, uint32_t serial)
{
xdg_wm_base_pong(shell, serial);
}
/*for xdg_wm_base listener*/
static const struct xdg_wm_base_listener wm_base_listener = {
xdg_wm_base_ping,
};
/*for registry listener*/
static void registry_add_object(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version)
{
if (!strcmp(interface, "wl_compositor")) {
compositor = wl_registry_bind(registry, name, &wl_compositor_interface, 1);
} else if (strcmp(interface, "xdg_wm_base") == 0) {
wm_base = wl_registry_bind(registry, name,
&xdg_wm_base_interface, 1);
xdg_wm_base_add_listener(wm_base, &wm_base_listener, NULL);
}
}
void registry_remove_object(void *data, struct wl_registry *registry, uint32_t name)
{
}
static struct wl_registry_listener registry_listener = {
registry_add_object, registry_remove_object};
static void
handle_surface_configure(void *data, struct xdg_surface *surface,
uint32_t serial)
{
xdg_surface_ack_configure(surface, serial);
}
static const struct xdg_surface_listener xdg_surface_listener = {
handle_surface_configure
};
static void
handle_toplevel_configure(void *data, struct xdg_toplevel *toplevel,
int32_t width, int32_t height,
struct wl_array *states)
{
}
static void
handle_toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel)
{
}
static const struct xdg_toplevel_listener xdg_toplevel_listener = {
handle_toplevel_configure,
handle_toplevel_close,
};
bool initWaylandConnection()
{
if ((display = wl_display_connect(NULL)) == NULL)
{
printf("Failed to connect to Wayland display!\n");
return false;
}
if ((registry = wl_display_get_registry(display)) == NULL)
{
printf("Faield to get Wayland registry!\n");
return false;
}
wl_registry_add_listener(registry, ®istry_listener, NULL);
wl_display_dispatch(display);
if (!compositor)
{
printf("Could not bind Wayland protocols!\n");
return false;
}
return true;
}
bool initializeWindow(struct window *window)
{
initWaylandConnection();
window->surface = wl_compositor_create_surface (compositor);
window->xdg_surface = xdg_wm_base_get_xdg_surface(wm_base, window->surface);
if (window->xdg_surface == NULL)
{
printf("Failed to get Wayland xdg surface\n");
return false;
} else {
xdg_surface_add_listener(window->xdg_surface, &xdg_surface_listener, window);
window->xdg_toplevel =
xdg_surface_get_toplevel(window->xdg_surface);
xdg_toplevel_add_listener(window->xdg_toplevel,
&xdg_toplevel_listener, window);
xdg_toplevel_set_title(window->xdg_toplevel, "egl_wayland_texture");
}
return true;
}
void releaseWaylandConnection(struct window *window)
{
if(window->xdg_toplevel)
xdg_toplevel_destroy(window->xdg_toplevel);
if(window->xdg_surface)
xdg_surface_destroy(window->xdg_surface);
wl_surface_destroy(window->surface);
xdg_wm_base_destroy(wm_base);
wl_compositor_destroy(compositor);
wl_registry_destroy(registry);
wl_display_disconnect(display);
}
bool createEGLSurface(EGLDisplay eglDisplay, EGLConfig eglConfig, EGLSurface *eglSurface, struct window *window)
{
window->egl_window = wl_egl_window_create(window->surface, WIDTH, HEIGHT);
if (window->egl_window == EGL_NO_SURFACE) {
printf("Can't create egl window\n");
return false;
} else {
printf("Created wl egl window\n");
}
*eglSurface = eglCreateWindowSurface(eglDisplay, eglConfig, window->egl_window, NULL);
return true;
}
bool opengles_init(GLuint *shaderProgram)
{
GLuint fragmentShader = 0;
GLuint vertexShader = 0;
char msg[1000];
GLsizei len;
const char* const fragmentShaderSource =
"precision mediump float;\n"
"void main()\n"
"{\n"
" gl_FragColor = vec4(1.0, 0.0, 0.0, 1.0);\n"
"}\n";
// Create a fragment shader object
fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
// Load the source code into it
glShaderSource(fragmentShader, 1, (const char**)&fragmentShaderSource, NULL);
// Compile the source code
glCompileShader(fragmentShader);
// Check that the shader compiled
GLint isShaderCompiled;
glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &isShaderCompiled);
if (!isShaderCompiled)
{
// If an error happened, first retrieve the length of the log message
glGetShaderInfoLog(fragmentShader, sizeof msg, &len, msg);
//glGetShaderiv(fragmentShader, GL_INFO_LOG_LENGTH, &infoLogLength);
// Allocate enough space for the message and retrieve it
//std::vector infoLog;
//infoLog.resize(infoLogLength);
//glGetShaderInfoLog(fragmentShader, infoLogLength, &charactersWritten, infoLog.data());
fprintf(stderr, "Error: compiling %s: %.*s\n", "fragment", len, msg);
return false;
}
// Vertex shader code
const char* const vertexShaderSource =
"attribute vec4 vPosition; \n"
"void main()\n"
"{\n"
" gl_Position = vPosition;\n"
"}\n";
// Create a vertex shader object
vertexShader = glCreateShader(GL_VERTEX_SHADER);
// Load the source code into the shader
glShaderSource(vertexShader, 1, (const char**)&vertexShaderSource, NULL);
// Compile the shader
glCompileShader(vertexShader);
// Check the shader has compiled
glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &isShaderCompiled);
if (!isShaderCompiled)
{
// If an error happened, first retrieve the length of the log message
//int infoLogLength, charactersWritten;
//glGetShaderiv(vertexShader, GL_INFO_LOG_LENGTH, &infoLogLength);
glGetShaderInfoLog(vertexShader, sizeof msg, &len, msg);
// Allocate enough space for the message and retrieve it
//std::vector infoLog;
//infoLog.resize(infoLogLength);
//glGetShaderInfoLog(vertexShader, infoLogLength, &charactersWritten, infoLog.data());
return false;
}
// Create the shader program
*shaderProgram = glCreateProgram();
// Attach the fragment and vertex shaders to it
glAttachShader(*shaderProgram, fragmentShader);
glAttachShader(*shaderProgram, vertexShader);
// Bind the vertex attribute "vPosition" to location VertexArray (0)
glBindAttribLocation(*shaderProgram, 0, "vPosition");
// Link the program
glLinkProgram(*shaderProgram);
// After linking the program, shaders are no longer necessary
glDeleteShader(vertexShader);
glDeleteShader(fragmentShader);
// Check if linking succeeded in the same way we checked for compilation success
GLint isLinked;
glGetProgramiv(*shaderProgram, GL_LINK_STATUS, &isLinked);
if (!isLinked)
{
// If an error happened, first retrieve the length of the log message
//nt infoLogLength, charactersWritten;
//glGetProgramiv(*shaderProgram, GL_INFO_LOG_LENGTH, &infoLogLength);
// Allocate enough space for the message and retrieve it
//std::vector infoLog;
//infoLog.resize(infoLogLength);
//glGetShaderInfoLog(shaderProgram, infoLogLength, &charactersWritten, infoLog.data());
glGetProgramInfoLog(*shaderProgram, sizeof msg, &len, msg);
fprintf(stderr, "Error: compiling %s: %.*s\n", "linkprogram", len, msg);
return false;
}
// Use the Program
glUseProgram(*shaderProgram);
return true;
}
bool renderScene(GLuint shaderProgram, EGLDisplay eglDisplay, EGLSurface eglSurface)
{
GLfloat vVertices[] = {
//vertex pointer
//x y z
-0.8f,0.8f,0.0f, //top left
0.8f,0.8f,0.0f, //top right
-0.8f,-0.8f,0.0f, //bottom left
0.8f,-0.8f,0.0f, //bottom right
};
glViewport(0, 0, WIDTH, HEIGHT); //set the view port
glClearColor(0.00f, 0.70f, 0.67f, 1.0f); //set rgba value for backgroud
glClear(GL_COLOR_BUFFER_BIT);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); //draw a quadrilateral
if (!eglSwapBuffers(eglDisplay, eglSurface))
{
return false;
}
return true;
}
bool render(GLuint shade