301 lines
6.8 KiB
C
301 lines
6.8 KiB
C
|
|
/* for nanosleep */
|
||
|
|
#define _POSIX_C_SOURCE 199309L
|
||
|
|
|
||
|
|
#include <time.h> /*nanosleep*/
|
||
|
|
#include <stdlib.h> /*malloc*/
|
||
|
|
#include <stdio.h> /*fprintf*/
|
||
|
|
#include <string.h>
|
||
|
|
|
||
|
|
#include <EGL/egl.h> /*graphic context*/
|
||
|
|
|
||
|
|
#include <wayland-egl.h>
|
||
|
|
#include <wayland-client.h>
|
||
|
|
|
||
|
|
#include "../headers/backend_resources/xdg-shell.h"
|
||
|
|
|
||
|
|
#include "../headers/glut_backend.h"
|
||
|
|
|
||
|
|
#include <my_device_handler.h>
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
struct client_state {
|
||
|
|
struct wl_display *display;
|
||
|
|
struct wl_registry *registry;
|
||
|
|
struct wl_compositor *compositor;
|
||
|
|
struct xdg_wm_base *xdg_wm_base;
|
||
|
|
|
||
|
|
struct wl_surface *surface;
|
||
|
|
struct xdg_surface *xdg_surface;
|
||
|
|
struct xdg_toplevel *xdg_toplevel;
|
||
|
|
/**/
|
||
|
|
struct wl_egl_window *egl_window;
|
||
|
|
|
||
|
|
EGLDisplay egl_display;
|
||
|
|
EGLConfig egl_config;
|
||
|
|
EGLContext egl_context;
|
||
|
|
EGLSurface egl_surface;
|
||
|
|
|
||
|
|
|
||
|
|
int32_t width;
|
||
|
|
int32_t height;
|
||
|
|
uint8_t running;
|
||
|
|
};
|
||
|
|
|
||
|
|
|
||
|
|
static struct client_state state;
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
static void global_registry(void *data, struct wl_registry *wl_registry,
|
||
|
|
uint32_t name, const char *interface, uint32_t version) {
|
||
|
|
struct client_state *state = data;
|
||
|
|
|
||
|
|
if(!strcmp(interface, wl_compositor_interface.name)) {
|
||
|
|
state->compositor = wl_registry_bind(wl_registry, name,
|
||
|
|
&wl_compositor_interface, version);
|
||
|
|
} else if(!strcmp(interface, xdg_wm_base_interface.name)) {
|
||
|
|
state->xdg_wm_base = wl_registry_bind(wl_registry, name,
|
||
|
|
&xdg_wm_base_interface, version);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void global_remove(void *data, struct wl_registry *wl_registry,
|
||
|
|
uint32_t name) {
|
||
|
|
(void) data;
|
||
|
|
(void) wl_registry;
|
||
|
|
(void) name;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct wl_registry_listener registry_listener = {
|
||
|
|
global_registry,
|
||
|
|
global_remove
|
||
|
|
};
|
||
|
|
|
||
|
|
static void wm_ping(void *data, struct xdg_wm_base *xdg_wm_base,
|
||
|
|
uint32_t serial) {
|
||
|
|
(void) data;
|
||
|
|
xdg_wm_base_pong(xdg_wm_base, serial);
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct xdg_wm_base_listener wm_base_listener = {
|
||
|
|
wm_ping
|
||
|
|
};
|
||
|
|
|
||
|
|
static void surface_configure(void *data, struct xdg_surface *xdg_surface,
|
||
|
|
uint32_t serial) {
|
||
|
|
(void) data;
|
||
|
|
|
||
|
|
xdg_surface_ack_configure(xdg_surface, serial);
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct xdg_surface_listener surface_listener = {
|
||
|
|
surface_configure
|
||
|
|
};
|
||
|
|
|
||
|
|
/******************************/
|
||
|
|
/********XDG Toplevel**********/
|
||
|
|
/******************************/
|
||
|
|
|
||
|
|
static void toplevel_configure(void *data, struct xdg_toplevel *xdg_toplevel,
|
||
|
|
int32_t width, int32_t height, struct wl_array *states) {
|
||
|
|
struct client_state *state = data;
|
||
|
|
(void) xdg_toplevel;
|
||
|
|
(void) states;
|
||
|
|
|
||
|
|
if(!width && !height) return;
|
||
|
|
|
||
|
|
if(state->width != width || state->height != height) {
|
||
|
|
state->width = width;
|
||
|
|
state->height = height;
|
||
|
|
|
||
|
|
wl_egl_window_resize(state->egl_window, width, height, 0, 0);
|
||
|
|
wl_surface_commit(state->surface);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
static void toplevel_close(void *data, struct xdg_toplevel *xdg_toplevel) {
|
||
|
|
(void) xdg_toplevel;
|
||
|
|
|
||
|
|
struct client_state *state = data;
|
||
|
|
|
||
|
|
state->running = 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
static const struct xdg_toplevel_listener toplevel_listener = {
|
||
|
|
toplevel_configure,
|
||
|
|
toplevel_close
|
||
|
|
};
|
||
|
|
|
||
|
|
static void wayland_connect(struct client_state *state) {
|
||
|
|
state->display = wl_display_connect(NULL);
|
||
|
|
if(!state->display) {
|
||
|
|
fprintf(stderr, "Couldn't connect to wayland display\n");
|
||
|
|
exit(EXIT_FAILURE);
|
||
|
|
}
|
||
|
|
|
||
|
|
state->registry = wl_display_get_registry(state->display);
|
||
|
|
wl_registry_add_listener(state->registry, ®istry_listener, state);
|
||
|
|
wl_display_roundtrip(state->display);
|
||
|
|
if(!state->compositor || !state->xdg_wm_base) {
|
||
|
|
fprintf(stderr, "Couldn't find compositor or xdg shell\n");
|
||
|
|
exit(EXIT_FAILURE);
|
||
|
|
}
|
||
|
|
|
||
|
|
xdg_wm_base_add_listener(state->xdg_wm_base, &wm_base_listener, NULL);
|
||
|
|
|
||
|
|
state->surface = wl_compositor_create_surface(state->compositor);
|
||
|
|
state->xdg_surface = xdg_wm_base_get_xdg_surface(state->xdg_wm_base,
|
||
|
|
state->surface);
|
||
|
|
xdg_surface_add_listener(state->xdg_surface, &surface_listener, NULL);
|
||
|
|
state->xdg_toplevel = xdg_surface_get_toplevel(state->xdg_surface);
|
||
|
|
xdg_toplevel_set_title(state->xdg_toplevel, "Hello World");
|
||
|
|
xdg_toplevel_add_listener(state->xdg_toplevel, &toplevel_listener, state);
|
||
|
|
wl_surface_commit(state->surface);
|
||
|
|
}
|
||
|
|
/**/
|
||
|
|
static void egl_init(struct client_state *state) {
|
||
|
|
EGLint major;
|
||
|
|
EGLint minor;
|
||
|
|
EGLint num_configs;
|
||
|
|
/*
|
||
|
|
replaced EGL_OPENGL_BIT with EGL_OPENGL_ES2_BIT
|
||
|
|
*/
|
||
|
|
EGLint attribs[] = {
|
||
|
|
EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
|
||
|
|
EGL_NONE
|
||
|
|
};
|
||
|
|
|
||
|
|
state->egl_window = wl_egl_window_create(state->surface, state->width,
|
||
|
|
state->height);
|
||
|
|
|
||
|
|
state->egl_display = eglGetDisplay((EGLNativeDisplayType) state->display);
|
||
|
|
if(state->display == EGL_NO_DISPLAY) {
|
||
|
|
fprintf(stderr, "Couldn't get EGL display\n");
|
||
|
|
exit(EXIT_FAILURE);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(eglInitialize(state->egl_display, &major, &minor) != EGL_TRUE) {
|
||
|
|
fprintf(stderr, "Couldnt initialize EGL\n");
|
||
|
|
exit(EXIT_FAILURE);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(eglChooseConfig(state->egl_display, attribs, &state->egl_config, 1,
|
||
|
|
&num_configs) != EGL_TRUE) {
|
||
|
|
fprintf(stderr, "CouldnÄt find matching EGL config\n");
|
||
|
|
exit(EXIT_FAILURE);
|
||
|
|
}
|
||
|
|
|
||
|
|
state->egl_surface = eglCreateWindowSurface(state->egl_display,
|
||
|
|
state->egl_config,
|
||
|
|
(EGLNativeWindowType) state->egl_window, NULL);
|
||
|
|
if(state->egl_surface == EGL_NO_SURFACE) {
|
||
|
|
fprintf(stderr, "Couldn't create EGL surface\n");
|
||
|
|
exit(EXIT_FAILURE);
|
||
|
|
}
|
||
|
|
|
||
|
|
/* added from
|
||
|
|
https://stackoverflow.com/questions/25843368/glgetstringgl-version-returns-opengl-es-cm-1-1-but-my-phone-supports-opengl
|
||
|
|
*/
|
||
|
|
const EGLint context_attrib_list[] = {
|
||
|
|
// request a context using Open GL ES 2.0
|
||
|
|
EGL_CONTEXT_CLIENT_VERSION, 2,
|
||
|
|
EGL_NONE
|
||
|
|
};
|
||
|
|
|
||
|
|
/*thanks to the dudes of stackoverflow for explaining how the attrib_list works*/
|
||
|
|
state->egl_context = eglCreateContext(state->egl_display, state->egl_config,
|
||
|
|
EGL_NO_CONTEXT, context_attrib_list);
|
||
|
|
if(state->egl_context == EGL_NO_CONTEXT) {
|
||
|
|
fprintf(stderr, "Couldn't create EGL context\n");
|
||
|
|
exit(EXIT_FAILURE);
|
||
|
|
}
|
||
|
|
|
||
|
|
if(!eglMakeCurrent(state->egl_display, state->egl_surface,
|
||
|
|
state->egl_surface, state->egl_context)) {
|
||
|
|
fprintf(stderr, "Couldn't make EGL context current\n");
|
||
|
|
exit(EXIT_FAILURE);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
|
||
|
|
/* refer to demo_2_egl */
|
||
|
|
void init_implementation( char **paths, int count){
|
||
|
|
device_handler_init();
|
||
|
|
for( int i = 0; i < count; i++){
|
||
|
|
device_handler_add(paths[i]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
int create_window_implementation( const char *title){
|
||
|
|
state.running = 1;
|
||
|
|
|
||
|
|
wayland_connect(&state);
|
||
|
|
/*
|
||
|
|
*/
|
||
|
|
egl_init(&state);
|
||
|
|
}
|
||
|
|
|
||
|
|
void init_window_size_implementation( int width, int height){
|
||
|
|
state.width = width;
|
||
|
|
state.height = height;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/* BAD implementation : perpetual malloc and free */
|
||
|
|
void sleep_implementation(){
|
||
|
|
/* the second field should be the remainder, in case of premature ending */
|
||
|
|
struct timespec *millisecond = malloc( sizeof( struct timespec));
|
||
|
|
millisecond->tv_sec=0;
|
||
|
|
millisecond->tv_nsec=1e6;
|
||
|
|
nanosleep( millisecond, NULL); /*won't compensate any delay due to the loop body*/
|
||
|
|
free(millisecond);
|
||
|
|
}
|
||
|
|
|
||
|
|
void swap_buffers_implementation(){
|
||
|
|
/* should not be here (glued) */
|
||
|
|
wl_display_dispatch_pending(state.display);
|
||
|
|
eglSwapBuffers( state.egl_display, state.egl_surface);
|
||
|
|
}
|