Skip to content

Instantly share code, notes, and snippets.

@propella
Last active July 16, 2024 00:32
Show Gist options
  • Select an option

  • Save propella/949261f89d83a6e184fb745a48de27c3 to your computer and use it in GitHub Desktop.

Select an option

Save propella/949261f89d83a6e184fb745a48de27c3 to your computer and use it in GitHub Desktop.

Revisions

  1. propella revised this gist Jul 5, 2017. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions triangle_simple.c
    Original file line number Diff line number Diff line change
    @@ -1,6 +1,9 @@
    /*
    * A simple Wayland EGL program to show a triangle
    *
    * cc -o triangle_simple triangle_simple.c -lwayland-client -lwayland-egl -lEGL -lGLESv2
    */

    #include <EGL/egl.h>
    #include <GLES2/gl2.h>
    #include <assert.h>
  2. propella created this gist Jul 5, 2017.
    222 changes: 222 additions & 0 deletions triangle_simple.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,222 @@
    /*
    * A simple Wayland EGL program to show a triangle
    */
    #include <EGL/egl.h>
    #include <GLES2/gl2.h>
    #include <assert.h>
    #include <string.h>
    #include <wayland-client.h>
    #include <wayland-egl.h>

    struct WaylandGlobals {
    struct wl_compositor* compositor;
    struct wl_shell* shell;
    };

    /*
    * Registry callbacks
    */
    static void registry_global(void* data, struct wl_registry* registry, uint32_t id, const char* interface, uint32_t version)
    {
    struct WaylandGlobals* globals = (struct WaylandGlobals *)data;
    if (strcmp(interface, "wl_compositor") == 0) {
    globals->compositor = wl_registry_bind(registry, id, &wl_compositor_interface, 1);
    } else if (strcmp(interface, "wl_shell") == 0) {
    globals->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
    }
    }

    static const struct wl_registry_listener registry_listener = { registry_global, NULL };

    /*
    * Connect to the Wayland display and return the display and the surface
    * output wlDisplay
    * output wlSurface
    */
    static void initWaylandDisplay(struct wl_display** wlDisplay, struct wl_surface** wlSurface)
    {
    struct WaylandGlobals globals = {0};

    *wlDisplay = wl_display_connect(NULL);
    assert(*wlDisplay != NULL);

    struct wl_registry* registry = wl_display_get_registry(*wlDisplay);
    wl_registry_add_listener(registry, &registry_listener, (void *) &globals);

    wl_display_dispatch(*wlDisplay);
    wl_display_roundtrip(*wlDisplay);
    assert(globals.compositor);
    assert(globals.shell);

    *wlSurface = wl_compositor_create_surface(globals.compositor);
    assert(*wlSurface != NULL);

    struct wl_shell_surface* shellSurface = wl_shell_get_shell_surface(globals.shell, *wlSurface);
    wl_shell_surface_set_toplevel(shellSurface);
    }

    /*
    * Configure EGL and return necessary resources
    * input nativeDisplay
    * input nativeWindow
    * output eglDisplay
    * output eglSurface
    */
    static void initEGLDisplay(EGLNativeDisplayType nativeDisplay, EGLNativeWindowType nativeWindow, EGLDisplay* eglDisplay, EGLSurface* eglSurface)
    {
    EGLint number_of_config;
    EGLint config_attribs[] = {
    EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
    EGL_RED_SIZE, 8,
    EGL_GREEN_SIZE, 8,
    EGL_BLUE_SIZE, 8,
    EGL_ALPHA_SIZE, 8,
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
    EGL_NONE
    };

    static const EGLint context_attribs[] = {
    EGL_CONTEXT_CLIENT_VERSION, 2,
    EGL_NONE
    };

    *eglDisplay = eglGetDisplay(nativeDisplay);
    assert(*eglDisplay != EGL_NO_DISPLAY);

    EGLBoolean initialized = eglInitialize(*eglDisplay, NULL, NULL);
    assert(initialized == EGL_TRUE);

    EGLConfig configs[1];

    eglChooseConfig(*eglDisplay, config_attribs, configs, 1, &number_of_config);
    assert(number_of_config);

    EGLContext eglContext = eglCreateContext(*eglDisplay, configs[0], EGL_NO_CONTEXT, context_attribs);

    *eglSurface = eglCreateWindowSurface(*eglDisplay, configs[0], nativeWindow, NULL);
    assert(*eglSurface != EGL_NO_SURFACE);

    EGLBoolean makeCurrent = eglMakeCurrent(*eglDisplay, *eglSurface, *eglSurface, eglContext);
    assert(makeCurrent == EGL_TRUE);
    }

    /*
    * Connect Wayland and make EGL
    * input width
    * input height
    * output wlDisplay
    * output eglDisplay
    * output eglSurface
    */
    static void initWindow(GLint width, GLint height, struct wl_display** wlDisplay, EGLDisplay* eglDisplay, EGLSurface* eglSurface)
    {
    struct wl_surface* wlSurface;
    initWaylandDisplay(wlDisplay, &wlSurface);

    struct wl_egl_window* wlEglWindow = wl_egl_window_create(wlSurface, width, height);
    assert(wlEglWindow != NULL);

    initEGLDisplay((EGLNativeDisplayType) *wlDisplay, (EGLNativeWindowType) wlEglWindow, eglDisplay, eglSurface);
    }

    /*
    * Return the loaded and compiled shader
    */
    GLuint LoadShader(GLenum type, const char* shaderSrc)
    {
    GLuint shader = glCreateShader(type);
    assert(shader);

    glShaderSource(shader, 1, &shaderSrc, NULL);
    glCompileShader(shader);

    GLint compiled;
    glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
    assert(compiled);

    return shader;
    }

    /*
    * Initialize the shaders and return the program object
    */
    GLuint initProgramObject()
    {
    char vShaderStr[] = "#version 300 es \n"
    "layout(location = 0) in vec4 vPosition; \n"
    "void main() \n"
    "{ \n"
    " gl_Position = vPosition; \n"
    "} \n";

    char fShaderStr[] = "#version 300 es \n"
    "precision mediump float; \n"
    "out vec4 fragColor; \n"
    "void main() \n"
    "{ \n"
    " fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n"
    "} \n";

    GLuint vertexShader = LoadShader(GL_VERTEX_SHADER, vShaderStr);
    GLuint fragmentShader = LoadShader(GL_FRAGMENT_SHADER, fShaderStr);

    GLuint programObject = glCreateProgram();
    assert(programObject);

    glAttachShader(programObject, vertexShader);
    glAttachShader(programObject, fragmentShader);

    glLinkProgram(programObject);

    GLint linked;
    glGetProgramiv(programObject, GL_LINK_STATUS, &linked);
    assert(linked);

    return programObject;
    }

    /*
    * Draw a triangle
    */
    void draw(GLuint programObject, GLint width, GLint height)
    {
    GLfloat vVertices[] = { 0.0f, 1.0f, 0.0f,
    -1.0f, -1.0f, 0.0f,
    1.0f, -1.0f, 0.0f };

    glViewport(0, 0, width, height);
    glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
    glClear(GL_COLOR_BUFFER_BIT);
    glUseProgram(programObject);
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, vVertices);
    glEnableVertexAttribArray(0);
    glDrawArrays(GL_TRIANGLES, 0, 3);
    }

    int main(int argc, char** argv)
    {
    int width = 320;
    int height = 240;

    struct wl_display* wlDisplay;
    EGLDisplay eglDisplay;
    EGLSurface eglSurface;

    initWindow(width, height, &wlDisplay, &eglDisplay, &eglSurface);

    GLuint programObject = initProgramObject();
    assert(programObject);

    draw(programObject, width, height);
    eglSwapBuffers(eglDisplay, eglSurface);

    while (wl_display_dispatch(wlDisplay) != -1) {
    }

    glDeleteProgram(programObject);

    wl_display_disconnect(wlDisplay);

    return 0;
    }