feat(opengles): multiple windows and embed user opengl textures (#6600)

Co-authored-by: Dany Liu <dany.yang.liu@email.com>
This commit is contained in:
Liam
2024-08-14 23:06:59 -04:00
committed by GitHub
parent d2545c3ecf
commit 44eb318d54
16 changed files with 923 additions and 679 deletions

View File

@@ -26,8 +26,8 @@ Configure OpenGL driver
#define LV_USE_OPENGLES 1
Usage
-----
Basic usage
-----------
.. code:: c
@@ -35,31 +35,163 @@ Usage
#include "lvgl/examples/lv_examples.h"
#include "lvgl/demos/lv_demos.h"
#define WIDTH 640
#define HEIGHT 480
int main()
{
/* initialize lvgl */
lv_init();
lv_display_t * disp = lv_glfw_window_create(480, 272);
/* create a window and initialize OpenGL */
lv_glfw_window_t * window = lv_glfw_window_create(WIDTH, HEIGHT, true);
lv_indev_t * mouse = lv_glfw_mouse_create();
lv_indev_set_group(mouse, lv_group_get_default());
lv_indev_set_display(mouse, disp);
/* create a display that flushes to a texture */
lv_display_t * texture = lv_opengles_texture_create(WIDTH, HEIGHT);
lv_display_set_default(texture);
lv_display_set_default(disp);
/* add the texture to the window */
unsigned int texture_id = lv_opengles_texture_get_texture_id(texture);
lv_glfw_texture_t * window_texture = lv_glfw_window_add_texture(window, texture_id, WIDTH, HEIGHT);
LV_IMAGE_DECLARE(mouse_cursor_icon); /*Declare the image file.*/
lv_obj_t * cursor_obj;
cursor_obj = lv_image_create(lv_screen_active()); /*Create an image object for the cursor */
lv_image_set_src(cursor_obj, &mouse_cursor_icon); /*Set the image source*/
lv_indev_set_cursor(mouse, cursor_obj); /*Connect the image object to the driver*/
/* get the mouse indev of the window texture */
lv_indev_t * mouse = lv_glfw_texture_get_mouse_indev(window_texture);
/* add a cursor to the mouse indev */
LV_IMAGE_DECLARE(mouse_cursor_icon);
lv_obj_t * cursor_obj = lv_image_create(lv_screen_active());
lv_image_set_src(cursor_obj, &mouse_cursor_icon);
lv_indev_set_cursor(mouse, cursor_obj);
/* create objects on the screen */
lv_demo_widgets();
while (1)
{
uint32_t time_till_next = lv_timer_handler();
lv_delay_ms(time_till_next);
uint32_t time_until_next = lv_timer_handler();
lv_delay_ms(time_until_next);
}
return 0;
}
Advanced usage
--------------
The OpenGL driver can draw textures from the user. A third-party library could be
used to add content to a texture and the driver will draw the texture in the window.
.. code:: c
#include "lvgl/lvgl.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#define WIDTH 640
#define HEIGHT 480
void custom_texture_example(void)
{
/*****************
* MAIN WINDOW
*****************/
/* create a window and initialize OpenGL */
/* multiple windows can be created */
lv_glfw_window_t * window = lv_glfw_window_create(WIDTH, HEIGHT, true);
/****************************
* OPTIONAL MAIN TEXTURE
****************************/
/* create a main display that flushes to a texture */
lv_display_t * main_texture = lv_opengles_texture_create(WIDTH, HEIGHT);
lv_display_set_default(main_texture);
/* add the main texture to the window */
unsigned int main_texture_id = lv_opengles_texture_get_texture_id(main_texture);
lv_glfw_texture_t * window_main_texture = lv_glfw_window_add_texture(window, main_texture_id, WIDTH, HEIGHT);
/* get the mouse indev of this main texture */
lv_indev_t * main_texture_mouse = lv_glfw_texture_get_mouse_indev(window_main_texture);
/* add a cursor to the mouse indev */
LV_IMAGE_DECLARE(mouse_cursor_icon);
lv_obj_t * cursor_obj = lv_image_create(lv_screen_active());
lv_image_set_src(cursor_obj, &mouse_cursor_icon);
lv_indev_set_cursor(main_texture_mouse, cursor_obj);
/* create objects on the screen of the main texture */
lv_demo_widgets();
/**********************
* ANOTHER TEXTURE
**********************/
/* create a sub display that flushes to a texture */
const int32_t sub_texture_w = 300;
const int32_t sub_texture_h = 300;
lv_display_t * sub_texture = lv_opengles_texture_create(sub_texture_w, sub_texture_h);
/* add the sub texture to the window */
unsigned int sub_texture_id = lv_opengles_texture_get_texture_id(sub_texture);
lv_glfw_texture_t * window_sub_texture = lv_glfw_window_add_texture(window, sub_texture_id, sub_texture_w, sub_texture_h);
/* create objects on the screen of the sub texture */
lv_display_set_default(sub_texture);
lv_obj_set_style_bg_color(lv_screen_active(), lv_color_black(), 0);
lv_example_anim_2();
lv_display_set_default(main_texture);
/* position the sub texture within the window */
lv_glfw_texture_set_x(window_sub_texture, 250);
lv_glfw_texture_set_y(window_sub_texture, 150);
/* optionally change the opacity of the sub texture */
lv_glfw_texture_set_opa(window_sub_texture, LV_OPA_80);
/*********************************************
* USE AN EXTERNAL OPENGL TEXTURE IN LVGL
*********************************************/
unsigned int external_texture_id;
glGenTextures(1, &external_texture_id);
glBindTexture(GL_TEXTURE_2D, external_texture_id);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
LV_IMAGE_DECLARE(img_cogwheel_argb);
#if LV_COLOR_DEPTH == 8
const int texture_format = GL_R8;
#elif LV_COLOR_DEPTH == 16
const int texture_format = GL_RGB565;
#elif LV_COLOR_DEPTH == 24
const int texture_format = GL_RGB;
#elif LV_COLOR_DEPTH == 32
const int texture_format = GL_RGBA;
#else
#error("Unsupported color format")
#endif
glTexImage2D(GL_TEXTURE_2D, 0, texture_format, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h, 0, GL_BGRA, GL_UNSIGNED_BYTE, img_cogwheel_argb.data);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
/* add the external texture to the window */
lv_glfw_texture_t * window_external_texture = lv_glfw_window_add_texture(window, external_texture_id, img_cogwheel_argb.header.w, img_cogwheel_argb.header.h);
/* set the position and opacity of the external texture within the window */
lv_glfw_texture_set_x(window_external_texture, 20);
lv_glfw_texture_set_y(window_external_texture, 20);
lv_glfw_texture_set_opa(window_external_texture, LV_OPA_70);
/*********************************************
* USE AN LVGL TEXTURE IN ANOTHER LIBRARY
*********************************************/
lv_refr_now(sub_texture);
/* the texture is drawn on by LVGL and can be used by anything that uses OpenGL textures */
third_party_lib_use_texture(sub_texture_id);
}

View File

@@ -1,87 +0,0 @@
/**
* @file lv_glfw_mouse.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_glfw_mouse.h"
#include "lv_glfw_mouse_private.h"
#if LV_USE_OPENGLES
#include <stdint.h>
#include <stdbool.h>
#include "../../core/lv_group.h"
#include "../../stdlib/lv_string.h"
/*********************
* DEFINES
*********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void opengles_mouse_read(lv_indev_t * indev, lv_indev_data_t * data);
static void release_indev_cb(lv_event_t * e);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_indev_t * lv_glfw_mouse_create(void)
{
lv_glfw_mouse_t * dsc = lv_malloc_zeroed(sizeof(lv_glfw_mouse_t));
LV_ASSERT_MALLOC(dsc);
if(dsc == NULL) return NULL;
lv_indev_t * indev = lv_indev_create();
LV_ASSERT_MALLOC(indev);
if(indev == NULL) {
lv_free(dsc);
return NULL;
}
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, opengles_mouse_read);
lv_indev_set_driver_data(indev, dsc);
lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT);
lv_indev_add_event_cb(indev, release_indev_cb, LV_EVENT_DELETE, indev);
return indev;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void opengles_mouse_read(lv_indev_t * indev, lv_indev_data_t * data)
{
lv_glfw_mouse_t * dsc = lv_indev_get_driver_data(indev);
/*Store the collected data*/
data->point.x = dsc->last_x;
data->point.y = dsc->last_y;
data->state = dsc->left_button_down ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
data->enc_diff = dsc->diff;
dsc->diff = 0;
}
static void release_indev_cb(lv_event_t * e)
{
lv_indev_t * indev = (lv_indev_t *) lv_event_get_user_data(e);
lv_glfw_mouse_t * dsc = lv_indev_get_driver_data(indev);
if(dsc) {
lv_indev_set_driver_data(indev, NULL);
lv_indev_set_read_cb(indev, NULL);
lv_free(dsc);
LV_LOG_INFO("done");
}
}
#endif /* LV_USE_OPENGLES */

View File

@@ -1,43 +0,0 @@
/**
* @file lv_glfw_mouse.h
*
*/
#ifndef LV_GLFW_MOUSE_H
#define LV_GLFW_MOUSE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_glfw_window.h"
#if LV_USE_OPENGLES
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
lv_indev_t * lv_glfw_mouse_create(void);
/**********************
* MACROS
**********************/
#endif /*LV_USE_OPENGLES*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV_GLFW_MOUSE_H */

View File

@@ -1,89 +0,0 @@
/**
* @file lv_glfw_mouse_private.c
*
*/
/*********************
* INCLUDES
*********************/
#include "../../display/lv_display.h"
#include "../../indev/lv_indev.h"
#include "lv_glfw_mouse_private.h"
#if LV_USE_OPENGLES
#include <stdint.h>
#include <stdbool.h>
#include "../../core/lv_group.h"
#include "../../stdlib/lv_string.h"
/*********************
* DEFINES
*********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_glfw_mouse_move_handler(lv_display_t * disp, int x, int y)
{
if(disp == NULL) {
return;
}
/*Find a suitable indev*/
lv_indev_t * indev = lv_indev_get_next(NULL);
while(indev) {
if(lv_indev_get_display(indev) == disp && lv_indev_get_type(indev) == LV_INDEV_TYPE_POINTER) {
break;
}
indev = lv_indev_get_next(indev);
}
if(indev == NULL) return;
lv_glfw_mouse_t * indev_dev = lv_indev_get_driver_data(indev);
if(indev_dev == NULL) return;
indev_dev->last_x = x;
indev_dev->last_y = y;
lv_indev_read(indev);
}
void lv_glfw_mouse_btn_handler(lv_display_t * disp, int btn_down)
{
if(disp == NULL) {
return;
}
/*Find a suitable indev*/
lv_indev_t * indev = lv_indev_get_next(NULL);
while(indev) {
if(lv_indev_get_display(indev) == disp && lv_indev_get_type(indev) == LV_INDEV_TYPE_POINTER) {
break;
}
indev = lv_indev_get_next(indev);
}
if(indev == NULL) return;
lv_glfw_mouse_t * indev_dev = lv_indev_get_driver_data(indev);
if(indev_dev == NULL) return;
indev_dev->left_button_down = btn_down;
lv_indev_read(indev);
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /* LV_USE_OPENGLES */

View File

@@ -1,52 +0,0 @@
/**
* @file lv_glfw_mouse_private.h
*
*/
#ifndef LV_GLFW_MOUSE_PRIVATE_H
#define LV_GLFW_MOUSE_PRIVATE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#if LV_USE_OPENGLES
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
int16_t last_x;
int16_t last_y;
bool left_button_down;
int32_t diff;
} lv_glfw_mouse_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
void lv_glfw_mouse_move_handler(lv_display_t * disp, int x, int y);
void lv_glfw_mouse_btn_handler(lv_display_t * disp, int btn_down);
/**********************
* MACROS
**********************/
#endif /*LV_USE_OPENGLES*/
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* LV_GLFW_MOUSE_PRIVATE_H */

View File

@@ -6,23 +6,22 @@
/*********************
* INCLUDES
*********************/
#include "lv_glfw_window.h"
#include "lv_glfw_mouse_private.h"
#include "lv_glfw_window_private.h"
#if LV_USE_OPENGLES
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <memory.h>
#include "../../core/lv_refr.h"
#include "../../stdlib/lv_string.h"
#include "../../core/lv_global.h"
#include "../../display/lv_display_private.h"
#include "../../indev/lv_indev.h"
#include "../../lv_init.h"
#include "../../misc/lv_area_private.h"
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "lv_opengles_driver.h"
#include "lv_opengles_texture.h"
/*********************
* DEFINES
@@ -31,45 +30,34 @@
/**********************
* TYPEDEFS
**********************/
typedef struct {
GLFWwindow * window;
uint8_t * fb1;
uint8_t * fb2;
uint8_t * fb_act;
uint8_t * buf1;
uint8_t * buf2;
uint8_t * rotated_buf;
size_t rotated_buf_size;
uint8_t zoom;
uint8_t ignore_size_chg;
} lv_glfw_window_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * color_p);
static int window_create(lv_display_t * disp);
static void window_update(lv_display_t * disp);
static void texture_resize(lv_display_t * disp);
static void window_update_handler(lv_timer_t * t);
static void window_event_handler(lv_timer_t * t);
static void release_disp_cb(lv_event_t * e);
static void res_chg_event_cb(lv_event_t * e);
static uint32_t lv_glfw_tick_count_callback(void);
/***********************
* GLOBAL PROTOTYPES
***********************/
static bool inited = false;
bool deiniting = false;
static lv_glfw_window_t * lv_glfw_get_lv_window_from_window(GLFWwindow * window);
static void glfw_error_cb(int error, const char * description);
static int lv_glfw_init(void);
static int lv_glew_init(void);
static void lv_glfw_timer_init(void);
static void lv_glfw_window_config(GLFWwindow * window, bool use_mouse_indev);
static void lv_glfw_window_quit(void);
static void window_close_callback(GLFWwindow * window);
static void key_callback(GLFWwindow * window, int key, int scancode, int action, int mods);
static void mouse_button_callback(GLFWwindow * window, int button, int action, int mods);
static void mouse_move_callback(GLFWwindow * window, double xpos, double ypos);
static void proc_mouse(lv_glfw_window_t * window);
static void indev_read_cb(lv_indev_t * indev, lv_indev_data_t * data);
static void framebuffer_size_callback(GLFWwindow * window, int width, int height);
/**********************
* STATIC VARIABLES
**********************/
static bool glfw_inited;
static bool glew_inited;
static lv_timer_t * update_handler_timer;
static lv_timer_t * event_handler_timer;
static lv_ll_t glfw_window_ll;
/**********************
* MACROS
@@ -79,301 +67,325 @@ static lv_timer_t * event_handler_timer;
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res)
lv_glfw_window_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res, bool use_mouse_indev)
{
if(!inited) {
update_handler_timer = lv_timer_create(window_update_handler, 5, NULL);
event_handler_timer = lv_timer_create(window_event_handler, 5, NULL);
lv_tick_set_cb(lv_glfw_tick_count_callback);
inited = true;
}
lv_glfw_window_t * dsc = lv_malloc_zeroed(sizeof(lv_glfw_window_t));
LV_ASSERT_MALLOC(dsc);
if(dsc == NULL) return NULL;
lv_display_t * disp = lv_display_create(hor_res, ver_res);
if(disp == NULL) {
lv_free(dsc);
if(lv_glfw_init() != 0) {
return NULL;
}
lv_display_add_event_cb(disp, release_disp_cb, LV_EVENT_DELETE, disp);
lv_glfw_window_t * window = lv_ll_ins_tail(&glfw_window_ll);
LV_ASSERT_MALLOC(window);
if(window == NULL) return NULL;
lv_memzero(window, sizeof(*window));
lv_display_set_driver_data(disp, dsc);
int ret = window_create(disp);
if(ret != 0) {
lv_display_send_event(disp, LV_EVENT_DELETE, NULL);
/* Create window with graphics context */
lv_glfw_window_t * existing_window = lv_ll_get_head(&glfw_window_ll);
window->window = glfwCreateWindow(hor_res, ver_res, "LVGL Simulator", NULL,
existing_window ? existing_window->window : NULL);
if(window->window == NULL) {
LV_LOG_ERROR("glfwCreateWindow fail.");
lv_ll_remove(&glfw_window_ll, window);
lv_free(window);
return NULL;
}
lv_display_set_flush_cb(disp, flush_cb);
uint32_t stride = lv_draw_buf_width_to_stride(lv_display_get_horizontal_resolution(disp),
lv_display_get_color_format(disp));
lv_display_set_buffers(disp, dsc->fb1, dsc->fb2, stride * disp->ver_res,
LV_DISPLAY_RENDER_MODE_DIRECT);
lv_display_add_event_cb(disp, res_chg_event_cb, LV_EVENT_RESOLUTION_CHANGED, NULL);
window->hor_res = hor_res;
window->ver_res = ver_res;
lv_ll_init(&window->textures, sizeof(lv_glfw_texture_t));
window->use_indev = use_mouse_indev;
lv_opengles_init(dsc->fb1, hor_res, ver_res);
glfwSetWindowUserPointer(window->window, window);
lv_glfw_timer_init();
lv_glfw_window_config(window->window, use_mouse_indev);
lv_glew_init();
glfwMakeContextCurrent(window->window);
lv_opengles_init();
return disp;
return window;
}
void lv_glfw_window_delete(lv_glfw_window_t * window)
{
glfwDestroyWindow(window->window);
if(window->use_indev) {
lv_glfw_texture_t * texture;
LV_LL_READ(&window->textures, texture) {
lv_indev_delete(texture->indev);
}
}
lv_ll_clear(&window->textures);
lv_ll_remove(&glfw_window_ll, window);
lv_free(window);
if(lv_ll_is_empty(&glfw_window_ll)) {
lv_glfw_window_quit();
}
}
lv_glfw_texture_t * lv_glfw_window_add_texture(lv_glfw_window_t * window, unsigned int texture_id, int32_t w, int32_t h)
{
lv_glfw_texture_t * texture = lv_ll_ins_tail(&window->textures);
LV_ASSERT_MALLOC(texture);
if(texture == NULL) return NULL;
lv_memzero(texture, sizeof(*texture));
texture->window = window;
texture->texture_id = texture_id;
lv_area_set(&texture->area, 0, 0, w - 1, h - 1);
texture->opa = LV_OPA_COVER;
if(window->use_indev) {
lv_display_t * texture_disp = lv_opengles_texture_get_from_texture_id(texture_id);
if(texture_disp != NULL) {
lv_indev_t * indev = lv_indev_create();
if(indev == NULL) {
lv_ll_remove(&window->textures, texture);
lv_free(texture);
return NULL;
}
texture->indev = indev;
lv_indev_set_type(indev, LV_INDEV_TYPE_POINTER);
lv_indev_set_read_cb(indev, indev_read_cb);
lv_indev_set_driver_data(indev, texture);
lv_indev_set_mode(indev, LV_INDEV_MODE_EVENT);
lv_indev_set_display(indev, texture_disp);
}
}
return texture;
}
void lv_glfw_texture_remove(lv_glfw_texture_t * texture)
{
if(texture->indev != NULL) {
lv_indev_delete(texture->indev);
}
lv_ll_remove(&texture->window->textures, texture);
lv_free(texture);
}
void lv_glfw_texture_set_x(lv_glfw_texture_t * texture, int32_t x)
{
lv_area_set_pos(&texture->area, x, texture->area.y1);
}
void lv_glfw_texture_set_y(lv_glfw_texture_t * texture, int32_t y)
{
lv_area_set_pos(&texture->area, texture->area.x1, y);
}
void lv_glfw_texture_set_opa(lv_glfw_texture_t * texture, lv_opa_t opa)
{
texture->opa = opa;
}
lv_indev_t * lv_glfw_texture_get_mouse_indev(lv_glfw_texture_t * texture)
{
return texture->indev;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_glfw_window_quit(lv_display_t * disp)
static int lv_glfw_init(void)
{
lv_glfw_window_t * dsc = lv_display_get_driver_data(disp);
if(inited) {
lv_timer_delete(update_handler_timer);
update_handler_timer = NULL;
if(glfw_inited) {
return 0;
}
glfwDestroyWindow(dsc->window);
glfwTerminate();
glfwSetErrorCallback(glfw_error_cb);
inited = false;
int ret = glfwInit();
if(ret == 0) {
LV_LOG_ERROR("glfwInit fail.");
return 1;
}
lv_ll_init(&glfw_window_ll, sizeof(lv_glfw_window_t));
glfw_inited = true;
return 0;
}
static int lv_glew_init(void)
{
if(glew_inited) {
return 0;
}
GLenum ret = glewInit();
if(ret != GLEW_OK) {
LV_LOG_ERROR("glewInit fail: %d.", ret);
return ret;
}
LV_LOG_INFO("GL version: %s", glGetString(GL_VERSION));
LV_LOG_INFO("GLSL version: %s", glGetString(GL_SHADING_LANGUAGE_VERSION));
glew_inited = true;
return 0;
}
static void lv_glfw_timer_init(void)
{
if(update_handler_timer == NULL) {
update_handler_timer = lv_timer_create(window_update_handler, LV_DEF_REFR_PERIOD, NULL);
lv_tick_set_cb(lv_glfw_tick_count_callback);
}
}
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
static void lv_glfw_window_config(GLFWwindow * window, bool use_mouse_indev)
{
LV_UNUSED(area);
LV_UNUSED(px_map);
if(lv_display_flush_is_last(disp)) {
window_update(disp);
glfwMakeContextCurrent(window);
glfwSwapInterval(1);
glfwSetFramebufferSizeCallback(window, framebuffer_size_callback);
if(use_mouse_indev) {
glfwSetMouseButtonCallback(window, mouse_button_callback);
glfwSetCursorPosCallback(window, mouse_move_callback);
}
/*IMPORTANT! It must be called to tell the system the flush is ready*/
lv_display_flush_ready(disp);
glfwSetKeyCallback(window, key_callback);
glfwSetWindowCloseCallback(window, window_close_callback);
}
/**
* Handler for glfw events
*/
static void window_event_handler(lv_timer_t * t)
static void lv_glfw_window_quit(void)
{
LV_UNUSED(t);
if(deiniting == false) {
return;
}
lv_timer_delete(update_handler_timer);
update_handler_timer = NULL;
lv_display_t * disp = lv_display_get_default();
if(disp == NULL) {
return;
}
lv_glfw_window_t * dsc = lv_display_get_driver_data(disp);
if(dsc == NULL) {
return;
}
glfwTerminate();
glfw_inited = false;
glfwSetWindowShouldClose(dsc->window, GLFW_TRUE);
lv_display_send_event(disp, LV_EVENT_DELETE, NULL);
lv_deinit();
exit(0);
}
/**
* Handler to update texture
*/
static void window_update_handler(lv_timer_t * t)
{
LV_UNUSED(t);
lv_display_t * disp = lv_display_get_default();
if(disp == NULL) {
return;
}
lv_glfw_window_t * dsc = lv_display_get_driver_data(disp);
if(dsc == NULL) {
return;
lv_glfw_window_t * window;
glfwPollEvents();
/* delete windows that are ready to close */
window = lv_ll_get_head(&glfw_window_ll);
while(window) {
lv_glfw_window_t * window_to_delete = window->closing ? window : NULL;
window = lv_ll_get_next(&glfw_window_ll, window);
if(window_to_delete) {
glfwSetWindowShouldClose(window_to_delete->window, GLFW_TRUE);
lv_glfw_window_delete(window_to_delete);
}
}
if(!glfwWindowShouldClose(dsc->window)) {
lv_opengles_update(dsc->fb1, disp->hor_res, disp->ver_res);
/* render each window */
LV_LL_READ(&glfw_window_ll, window) {
glfwMakeContextCurrent(window->window);
lv_opengles_viewport(0, 0, window->hor_res, window->ver_res);
lv_opengles_render_clear();
/* render each texture in the window */
lv_glfw_texture_t * texture;
LV_LL_READ(&window->textures, texture) {
/* if the added texture is an LVGL opengles texture display, refresh it before rendering it */
lv_display_t * texture_disp = lv_opengles_texture_get_from_texture_id(texture->texture_id);
if(texture_disp != NULL) {
lv_refr_now(texture_disp);
}
lv_opengles_render_texture(texture->texture_id, &texture->area, texture->opa, window->hor_res, window->ver_res);
}
/* Swap front and back buffers */
glfwSwapBuffers(dsc->window);
glfwPollEvents();
glfwSwapBuffers(window->window);
}
}
static void glfw_error_cb(int error, const char * description)
{
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
LV_LOG_ERROR("GLFW Error %d: %s", error, description);
}
static lv_glfw_window_t * lv_glfw_get_lv_window_from_window(GLFWwindow * window)
{
return glfwGetWindowUserPointer(window);
}
static void window_close_callback(GLFWwindow * window)
{
LV_UNUSED(window);
deiniting = true;
lv_glfw_window_t * lv_window = lv_glfw_get_lv_window_from_window(window);
lv_window->closing = 1;
}
static void key_callback(GLFWwindow * window, int key, int scancode, int action, int mods)
{
LV_UNUSED(window);
LV_UNUSED(scancode);
LV_UNUSED(mods);
if(key == GLFW_KEY_ESCAPE && action == GLFW_PRESS) {
deiniting = true;
lv_glfw_window_t * lv_window = lv_glfw_get_lv_window_from_window(window);
lv_window->closing = 1;
}
}
static void mouse_button_callback(GLFWwindow * window, int button, int action, int mods)
{
LV_UNUSED(window);
LV_UNUSED(mods);
if(button == GLFW_MOUSE_BUTTON_LEFT) {
lv_display_t * disp = lv_display_get_default();
if(action == GLFW_PRESS) {
lv_glfw_mouse_btn_handler(disp, 1);
}
else if(action == GLFW_RELEASE) {
lv_glfw_mouse_btn_handler(disp, 0);
}
lv_glfw_window_t * lv_window = lv_glfw_get_lv_window_from_window(window);
lv_window->mouse_last_state = action == GLFW_PRESS ? LV_INDEV_STATE_PRESSED : LV_INDEV_STATE_RELEASED;
proc_mouse(lv_window);
}
}
static void mouse_move_callback(GLFWwindow * window, double xpos, double ypos)
{
LV_UNUSED(window);
lv_display_t * disp = lv_display_get_default();
lv_glfw_mouse_move_handler(disp, (int)xpos, (int)ypos);
lv_glfw_window_t * lv_window = lv_glfw_get_lv_window_from_window(window);
lv_window->mouse_last_point.x = (int32_t)xpos;
lv_window->mouse_last_point.y = (int32_t)ypos;
proc_mouse(lv_window);
}
static void proc_mouse(lv_glfw_window_t * window)
{
/* mouse activity will affect the topmost LVGL display texture */
lv_glfw_texture_t * texture;
LV_LL_READ_BACK(&window->textures, texture) {
if(lv_area_is_point_on(&texture->area, &window->mouse_last_point, 0)) {
/* adjust the mouse pointer coordinates so that they are relative to the texture */
texture->indev_last_point.x = window->mouse_last_point.x - texture->area.x1;
texture->indev_last_point.y = window->mouse_last_point.y - texture->area.y1;
texture->indev_last_state = window->mouse_last_state;
lv_indev_read(texture->indev);
break;
}
}
}
static void indev_read_cb(lv_indev_t * indev, lv_indev_data_t * data)
{
lv_glfw_texture_t * texture = lv_indev_get_driver_data(indev);
data->point = texture->indev_last_point;
data->state = texture->indev_last_state;
}
static void framebuffer_size_callback(GLFWwindow * window, int width, int height)
{
LV_UNUSED(window);
glViewport(0, 0, width, height);
lv_display_t * disp = lv_display_get_default();
if(disp == NULL) {
return;
}
lv_glfw_window_t * dsc = lv_display_get_driver_data(disp);
dsc->ignore_size_chg = 1;
lv_display_set_resolution(disp, width / dsc->zoom, height / dsc->zoom);
dsc->ignore_size_chg = 0;
lv_refr_now(disp);
}
static void texture_resize(lv_display_t * disp)
{
int32_t hor_res = lv_display_get_horizontal_resolution(disp);
int32_t ver_res = lv_display_get_vertical_resolution(disp);
uint32_t stride = lv_draw_buf_width_to_stride(hor_res, lv_display_get_color_format(disp));
lv_glfw_window_t * dsc = lv_display_get_driver_data(disp);
dsc->fb1 = realloc(dsc->fb1, stride * ver_res);
lv_memzero(dsc->fb1, stride * ver_res);
lv_display_set_buffers(disp, dsc->fb1, dsc->fb2, stride * ver_res, LV_DISPLAY_RENDER_MODE_DIRECT);
}
static int window_create(lv_display_t * disp)
{
lv_glfw_window_t * dsc = lv_display_get_driver_data(disp);
dsc->zoom = 1;
glfwSetErrorCallback(glfw_error_cb);
if(!glfwInit()) {
LV_LOG_ERROR("glfwInit fail.\n");
return 1;
}
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 0);
int32_t hor_res = disp->hor_res;
int32_t ver_res = disp->ver_res;
/* Create window with graphics context */
dsc->window = glfwCreateWindow(hor_res * dsc->zoom, ver_res * dsc->zoom, "LVGL Simulator", NULL, NULL);
if(dsc->window == NULL) {
LV_LOG_ERROR("glfwCreateWindow fail.\n");
return 2;
}
glfwMakeContextCurrent(dsc->window);
if(glewInit() != GLEW_OK) {
LV_LOG_ERROR("glewInit fail.\n");
return 3;
}
LV_LOG_INFO("GL version: %s\n", glGetString(GL_VERSION));
LV_LOG_INFO("GLSL version: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
glfwSwapInterval(1);
glfwSetFramebufferSizeCallback(dsc->window, framebuffer_size_callback);
glfwSetMouseButtonCallback(dsc->window, mouse_button_callback);
glfwSetCursorPosCallback(dsc->window, mouse_move_callback);
glfwSetKeyCallback(dsc->window, key_callback);
glfwSetWindowCloseCallback(dsc->window, window_close_callback);
texture_resize(disp);
uint32_t px_size = lv_color_format_get_size(lv_display_get_color_format(disp));
lv_memset(dsc->fb1, 0xff, hor_res * ver_res * px_size);
return 0;
}
static void window_update(lv_display_t * disp)
{
lv_glfw_window_t * dsc = lv_display_get_driver_data(disp);
if(dsc->fb_act) {
LV_LOG_INFO("current pixel: %d\n", ((uint16_t *)(dsc->fb_act))[0]);
}
if(dsc->fb1) {
LV_LOG_INFO("fb1 pixel: %d\n", ((uint16_t *)(dsc->fb1))[0]);
}
}
static void res_chg_event_cb(lv_event_t * e)
{
lv_display_t * disp = lv_event_get_current_target(e);
texture_resize(disp);
}
static void release_disp_cb(lv_event_t * e)
{
lv_display_t * disp = (lv_display_t *) lv_event_get_user_data(e);
lv_glfw_window_t * dsc = lv_display_get_driver_data(disp);
lv_glfw_window_quit(disp);
if(dsc->fb1) {
free(dsc->fb1);
dsc->fb1 = NULL;
}
if(dsc->fb2) {
free(dsc->fb2);
dsc->fb2 = NULL;
}
if(dsc->buf1) {
free(dsc->buf1);
dsc->buf1 = NULL;
}
if(dsc->buf2) {
free(dsc->buf2);
dsc->buf2 = NULL;
}
lv_deinit();
lv_free(dsc);
exit(0);
lv_glfw_window_t * lv_window = lv_glfw_get_lv_window_from_window(window);
lv_window->hor_res = width;
lv_window->ver_res = height;
}
static uint32_t lv_glfw_tick_count_callback(void)
{
int milliseconds = (int)(glfwGetTime() * 1000);
return milliseconds;
double tick = glfwGetTime() * 1000.0;
return (uint32_t)tick;
}
#endif /*LV_USE_OPENGLES*/

View File

@@ -14,11 +14,12 @@ extern "C" {
* INCLUDES
*********************/
#include "../../display/lv_display.h"
#include "../../indev/lv_indev.h"
#include "../../lv_conf_internal.h"
#if LV_USE_OPENGLES
#include "../../misc/lv_types.h"
#include "../../display/lv_display.h"
/*********************
* DEFINES
*********************/
@@ -31,7 +32,68 @@ extern "C" {
* GLOBAL PROTOTYPES
**********************/
lv_display_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res);
/**
* Create a GLFW window with no textures and initialize OpenGL
* @param hor_res width in pixels of the window
* @param ver_res height in pixels of the window
* @param use_mouse_indev send pointer indev input to LVGL display textures
* @return the new GLFW window handle
*/
lv_glfw_window_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res, bool use_mouse_indev);
/**
* Delete a GLFW window. If it is the last one, the process will exit
* @param window GLFW window to delete
*/
void lv_glfw_window_delete(lv_glfw_window_t * window);
/**
* Add a texture to the GLFW window. It can be an LVGL display texture, or any OpenGL texture
* @param window GLFW window
* @param texture_id OpenGL texture ID
* @param w width in pixels of the texture
* @param h height in pixels of the texture
* @return the new texture handle
*/
lv_glfw_texture_t * lv_glfw_window_add_texture(lv_glfw_window_t * window, unsigned int texture_id, int32_t w,
int32_t h);
/**
* Remove a texture from its GLFW window and delete it
* @param texture handle of a GLFW window texture
*/
void lv_glfw_texture_remove(lv_glfw_texture_t * texture);
/**
* Set the x position of a texture within its GLFW window
* @param texture handle of a GLFW window texture
* @param x new x position of the texture
*/
void lv_glfw_texture_set_x(lv_glfw_texture_t * texture, int32_t x);
/**
* Set the y position of a texture within its GLFW window
* @param texture handle of a GLFW window texture
* @param y new y position of the texture
*/
void lv_glfw_texture_set_y(lv_glfw_texture_t * texture, int32_t y);
/**
* Set the opacity of a texture in a GLFW window
* @param texture handle of a GLFW window texture
* @param opa new opacity of the texture
*/
void lv_glfw_texture_set_opa(lv_glfw_texture_t * texture, lv_opa_t opa);
/**
* Get the mouse indev associated with a texture in a GLFW window, if it exists
* @param texture handle of a GLFW window texture
* @return the indev or `NULL`
* @note there will only be an indev if the texture is based on an
* LVGL display texture and the window was created with
* `use_mouse_indev` as `true`
*/
lv_indev_t * lv_glfw_texture_get_mouse_indev(lv_glfw_texture_t * texture);
/**********************
* MACROS

View File

@@ -0,0 +1,70 @@
/**
* @file lv_glfw_window_private.h
*
*/
#ifndef LV_GLFW_WINDOW_PRIVATE_H
#define LV_GLFW_WINDOW_PRIVATE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_glfw_window.h"
#if LV_USE_OPENGLES
#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include "../../misc/lv_area.h"
#include "../../display/lv_display.h"
#include "../../indev/lv_indev.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
struct lv_glfw_window_t {
GLFWwindow * window;
int32_t hor_res;
int32_t ver_res;
lv_ll_t textures;
lv_point_t mouse_last_point;
lv_indev_state_t mouse_last_state;
uint8_t use_indev : 1;
uint8_t closing : 1;
};
struct lv_glfw_texture_t {
lv_glfw_window_t * window;
unsigned int texture_id;
lv_area_t area;
lv_opa_t opa;
lv_indev_t * indev;
lv_point_t indev_last_point;
lv_indev_state_t indev_last_state;
};
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_OPENGLES*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_GLFW_WINDOW_PRIVATE_H*/

View File

@@ -6,11 +6,12 @@
/*********************
* INCLUDES
*********************/
#include "../../display/lv_display.h"
#include "lv_opengles_debug.h"
#include "lv_opengles_debug.h"
#if LV_USE_OPENGLES
#include "../../misc/lv_log.h"
/*********************
* DEFINES
*********************/
@@ -23,10 +24,6 @@
* STATIC PROTOTYPES
**********************/
/***********************
* GLOBAL PROTOTYPES
***********************/
/**********************
* STATIC VARIABLES
**********************/
@@ -48,10 +45,14 @@ bool GLLogCall(const char * function, const char * file, int line)
{
GLenum error;
while((error = glGetError()) != GL_NO_ERROR) {
LV_LOG_ERROR("[OpenGL Error] (%d) %s %s:%d\n", error, function, file, line);
LV_LOG_ERROR("[OpenGL Error] (%d) %s %s:%d", error, function, file, line);
return false;
}
return true;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /* LV_USE_OPENGLES */

View File

@@ -10,10 +10,10 @@
extern "C" {
#endif
#include <stdbool.h>
#include "../../lv_conf_internal.h"
#if LV_USE_OPENGLES
#include <stdbool.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>

View File

@@ -10,10 +10,6 @@
#if LV_USE_OPENGLES
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
#include "lv_opengles_debug.h"
#include "lv_opengles_driver.h"
@@ -28,6 +24,7 @@
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_opengles_enable_blending(void);
static void lv_opengles_vertex_buffer_init(const void * data, unsigned int size);
static void lv_opengles_vertex_buffer_deinit(void);
static void lv_opengles_vertex_buffer_bind(void);
@@ -42,7 +39,6 @@ static void lv_opengles_index_buffer_deinit(void);
static unsigned int lv_opengles_index_buffer_get_count(void);
static void lv_opengles_index_buffer_bind(void);
static void lv_opengles_index_buffer_unbind(void);
static void lv_opengles_render_clear(void);
static unsigned int lv_opengles_shader_compile(unsigned int type, const char * source);
static unsigned int lv_opengles_shader_create(const char * vertexShader, const char * fragmentShader);
static void lv_opengles_shader_init(void);
@@ -51,12 +47,9 @@ static void lv_opengles_shader_bind(void);
static void lv_opengles_shader_unbind(void);
static int lv_opengles_shader_get_uniform_location(const char * name);
static void lv_opengles_shader_set_uniform1i(const char * name, int value);
static void lv_opengles_shader_set_uniform4f(const char * name, float v0, float v1, float v2, float v3);
static void lv_opengles_shader_set_uniformmatrix3fv(const char * name, int count, bool transpose, const float * values);
static void lv_opengles_shader_set_uniform1f(const char * name, float value);
static void lv_opengles_render_draw(void);
static void lv_opengles_texture_init(void * buffer, int width, int height);
static void lv_opengles_texture_deinit(void);
static void lv_opengles_texture_bind(unsigned int slot);
static void lv_opengles_texture_update(void * buffer, int width, int height);
/***********************
* GLOBAL PROTOTYPES
@@ -65,6 +58,8 @@ static void lv_opengles_texture_update(void * buffer, int width, int height);
/**********************
* STATIC VARIABLES
**********************/
static bool is_init;
static unsigned int vertex_buffer_id = 0;
static unsigned int vertex_array_id = 0;
@@ -72,12 +67,10 @@ static unsigned int vertex_array_id = 0;
static unsigned int index_buffer_id = 0;
static unsigned int index_buffer_count = 0;
static unsigned int texture_id = 0;
static unsigned int shader_id;
static const char * shader_names[] = { "u_Color", "u_Texture", "u_ColorDepth" };
static int shader_location[] = { 0, 0, 0 };
static const char * shader_names[] = { "u_Texture", "u_ColorDepth", "u_VertexTransform", "u_Opa" };
static int shader_location[] = { 0, 0, 0, 0 };
static const char * vertex_shader =
"#version 300 es\n"
@@ -87,9 +80,11 @@ static const char * vertex_shader =
"\n"
"out vec2 v_TexCoord;\n"
"\n"
"uniform mat3 u_VertexTransform;\n"
"\n"
"void main()\n"
"{\n"
" gl_Position = position;\n"
" gl_Position = vec4((u_VertexTransform * vec3(position.xy, 1)).xy, position.zw);\n"
" v_TexCoord = texCoord;\n"
"};\n";
@@ -102,18 +97,18 @@ static const char * fragment_shader =
"\n"
"in vec2 v_TexCoord;\n"
"\n"
"uniform vec4 u_Color;\n"
"uniform sampler2D u_Texture;\n"
"uniform int u_ColorDepth;\n"
"uniform float u_Opa;\n"
"\n"
"void main()\n"
"{\n"
" vec4 texColor = texture(u_Texture, v_TexCoord);\n"
" if (u_ColorDepth == 8) {\n"
" float gray = texColor.r;\n"
" color = vec4(gray, gray, gray, 1.0);\n"
" color = vec4(gray, gray, gray, u_Opa);\n"
" } else {\n"
" color = texColor;\n"
" color = vec4(texColor.rgb, texColor.a * u_Opa);\n"
" }\n"
"};\n";
@@ -125,8 +120,12 @@ static const char * fragment_shader =
* GLOBAL FUNCTIONS
**********************/
void lv_opengles_init(uint8_t * frame_buffer, int32_t hor, int32_t ver)
void lv_opengles_init(void)
{
if(is_init) return;
lv_opengles_enable_blending();
float positions[] = {
-1.0f, 1.0f, 0.0f, 0.0f,
1.0f, 1.0f, 1.0f, 0.0f,
@@ -139,7 +138,7 @@ void lv_opengles_init(uint8_t * frame_buffer, int32_t hor, int32_t ver)
2, 3, 0
};
lv_opengles_vertex_buffer_init(positions, 4 * 4 * sizeof(float));
lv_opengles_vertex_buffer_init(positions, sizeof(positions));
lv_opengles_vertex_array_init();
lv_opengles_vertex_array_add_buffer();
@@ -148,46 +147,72 @@ void lv_opengles_init(uint8_t * frame_buffer, int32_t hor, int32_t ver)
lv_opengles_shader_init();
lv_opengles_shader_bind();
lv_opengles_shader_set_uniform1i("u_ColorDepth", LV_COLOR_DEPTH);
lv_opengles_shader_set_uniform4f("u_Color", 0.8f, 0.3f, 0.8f, 1.0f);
int slot = 0;
lv_opengles_texture_init(frame_buffer, hor, ver);
lv_opengles_texture_bind(slot);
lv_opengles_shader_set_uniform1i("u_Texture", slot);
/* unbound everything */
/* unbind everything */
lv_opengles_vertex_array_unbind();
lv_opengles_vertex_buffer_unbind();
lv_opengles_index_buffer_unbind();
lv_opengles_shader_unbind();
is_init = true;
}
void lv_opengles_deinit(void)
{
lv_opengles_texture_deinit();
if(!is_init) return;
lv_opengles_shader_deinit();
lv_opengles_index_buffer_deinit();
lv_opengles_vertex_buffer_deinit();
lv_opengles_vertex_array_deinit();
is_init = false;
}
void lv_opengles_update(uint8_t * frame_buffer, int32_t hor, int32_t ver)
void lv_opengles_render_texture(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa, int32_t disp_w,
int32_t disp_h)
{
lv_opengles_render_clear();
lv_opengles_texture_update(frame_buffer, hor, ver);
GL_CALL(glActiveTexture(GL_TEXTURE0));
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture));
float hor_scale = (float)lv_area_get_width(texture_area) / (float)disp_w;
float ver_scale = (float)lv_area_get_height(texture_area) / (float)disp_h;
float hor_translate = (float)texture_area->x1 / (float)disp_w * 2.0f - (1.0f - hor_scale);
float ver_translate = -((float)texture_area->y1 / (float)disp_h * 2.0f - (1.0f - ver_scale));
float matrix[9] = {
hor_scale, 0.0f, hor_translate,
0.0f, ver_scale, ver_translate,
0.0f, 0.0f, 1.0f
};
lv_opengles_shader_bind();
lv_opengles_shader_set_uniform1i("u_ColorDepth", LV_COLOR_DEPTH);
lv_opengles_shader_set_uniform4f("u_Color", 0.0f, 0.3f, 0.8f, 1.0f);
lv_opengles_shader_set_uniform1i("u_Texture", 0);
lv_opengles_shader_set_uniformmatrix3fv("u_VertexTransform", 1, true, matrix);
lv_opengles_shader_set_uniform1f("u_Opa", (float)opa / (float)LV_OPA_100);
lv_opengles_render_draw();
}
void lv_opengles_render_clear(void)
{
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
}
void lv_opengles_viewport(int32_t x, int32_t y, int32_t w, int32_t h)
{
glViewport(x, y, w, h);
}
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_opengles_enable_blending(void)
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
}
static void lv_opengles_vertex_buffer_init(const void * data, unsigned int size)
{
GL_CALL(glGenBuffers(1, &vertex_buffer_id));
@@ -195,42 +220,42 @@ static void lv_opengles_vertex_buffer_init(const void * data, unsigned int size)
GL_CALL(glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW));
}
static void lv_opengles_vertex_buffer_deinit()
static void lv_opengles_vertex_buffer_deinit(void)
{
GL_CALL(glDeleteBuffers(1, &vertex_buffer_id));
}
static void lv_opengles_vertex_buffer_bind()
static void lv_opengles_vertex_buffer_bind(void)
{
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id));
}
static void lv_opengles_vertex_buffer_unbind()
static void lv_opengles_vertex_buffer_unbind(void)
{
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
}
static void lv_opengles_vertex_array_init()
static void lv_opengles_vertex_array_init(void)
{
GL_CALL(glGenVertexArrays(1, &vertex_array_id));
}
static void lv_opengles_vertex_array_deinit()
static void lv_opengles_vertex_array_deinit(void)
{
GL_CALL(glDeleteVertexArrays(1, &vertex_array_id));
}
static void lv_opengles_vertex_array_bind()
static void lv_opengles_vertex_array_bind(void)
{
GL_CALL(glBindVertexArray(vertex_array_id));
}
static void lv_opengles_vertex_array_unbind()
static void lv_opengles_vertex_array_unbind(void)
{
GL_CALL(glBindVertexArray(0));
}
static void lv_opengles_vertex_array_add_buffer()
static void lv_opengles_vertex_array_add_buffer(void)
{
lv_opengles_vertex_buffer_bind();
intptr_t offset = 0;
@@ -253,31 +278,26 @@ static void lv_opengles_index_buffer_init(const unsigned int * data, unsigned in
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(GLuint), data, GL_STATIC_DRAW));
}
static void lv_opengles_index_buffer_deinit()
static void lv_opengles_index_buffer_deinit(void)
{
GL_CALL(glDeleteBuffers(1, &index_buffer_id));
}
static unsigned int lv_opengles_index_buffer_get_count()
static unsigned int lv_opengles_index_buffer_get_count(void)
{
return index_buffer_count;
}
static void lv_opengles_index_buffer_bind()
static void lv_opengles_index_buffer_bind(void)
{
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_id));
}
static void lv_opengles_index_buffer_unbind()
static void lv_opengles_index_buffer_unbind(void)
{
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0));
}
static void lv_opengles_render_clear()
{
GL_CALL(glClear(GL_COLOR_BUFFER_BIT));
}
static unsigned int lv_opengles_shader_compile(unsigned int type, const char * source)
{
GL_CALL(unsigned int id = glCreateShader(type));
@@ -292,8 +312,8 @@ static unsigned int lv_opengles_shader_compile(unsigned int type, const char * s
GL_CALL(glGetShaderiv(id, GL_INFO_LOG_LENGTH, &length));
char * message = lv_malloc_zeroed(length * sizeof(char));
GL_CALL(glGetShaderInfoLog(id, length, &length, message));
LV_LOG_ERROR("Failed to compile %s shader!\n", type == GL_VERTEX_SHADER ? "vertex" : "fragment");
LV_LOG_ERROR("%s\n", message);
LV_LOG_ERROR("Failed to compile %s shader!", type == GL_VERTEX_SHADER ? "vertex" : "fragment");
LV_LOG_ERROR("%s", message);
GL_CALL(glDeleteShader(id));
return 0;
}
@@ -318,22 +338,22 @@ static unsigned int lv_opengles_shader_create(const char * vertexShader, const c
return program;
}
static void lv_opengles_shader_init()
static void lv_opengles_shader_init(void)
{
shader_id = lv_opengles_shader_create(vertex_shader, fragment_shader);
}
static void lv_opengles_shader_deinit()
static void lv_opengles_shader_deinit(void)
{
GL_CALL(glDeleteProgram(shader_id));
}
static void lv_opengles_shader_bind()
static void lv_opengles_shader_bind(void)
{
GL_CALL(glUseProgram(shader_id));
}
static void lv_opengles_shader_unbind()
static void lv_opengles_shader_unbind(void)
{
GL_CALL(glUseProgram(0));
}
@@ -342,7 +362,7 @@ static int lv_opengles_shader_get_uniform_location(const char * name)
{
int id = -1;
for(size_t i = 0; i < sizeof(shader_location) / sizeof(int); i++) {
if(strcmp(shader_names[i], name) == 0) {
if(lv_strcmp(shader_names[i], name) == 0) {
id = i;
}
}
@@ -356,7 +376,7 @@ static int lv_opengles_shader_get_uniform_location(const char * name)
GL_CALL(int location = glGetUniformLocation(shader_id, name));
if(location == -1)
LV_LOG_WARN("Warning: uniform '%s' doesn't exist!\n", name);
LV_LOG_WARN("Warning: uniform '%s' doesn't exist!", name);
shader_location[id] = location;
return location;
@@ -367,12 +387,17 @@ static void lv_opengles_shader_set_uniform1i(const char * name, int value)
GL_CALL(glUniform1i(lv_opengles_shader_get_uniform_location(name), value));
}
static void lv_opengles_shader_set_uniform4f(const char * name, float v0, float v1, float v2, float v3)
static void lv_opengles_shader_set_uniformmatrix3fv(const char * name, int count, bool transpose, const float * values)
{
GL_CALL(glUniform4f(lv_opengles_shader_get_uniform_location(name), v0, v1, v2, v3));
GL_CALL(glUniformMatrix3fv(lv_opengles_shader_get_uniform_location(name), count, transpose, values));
}
static void lv_opengles_render_draw()
static void lv_opengles_shader_set_uniform1f(const char * name, float value)
{
GL_CALL(glUniform1f(lv_opengles_shader_get_uniform_location(name), value));
}
static void lv_opengles_render_draw(void)
{
lv_opengles_shader_bind();
lv_opengles_vertex_array_bind();
@@ -381,67 +406,4 @@ static void lv_opengles_render_draw()
GL_CALL(glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, NULL));
}
static void lv_opengles_texture_init(void * buffer, int width, int height)
{
if(buffer == NULL) {
return;
}
GL_CALL(glGenTextures(1, &texture_id));
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture_id));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
/*Color depth: 8 (A8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888)*/
#if LV_COLOR_DEPTH == 8
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, buffer));
#elif LV_COLOR_DEPTH == 16
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, buffer));
#elif LV_COLOR_DEPTH == 24
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, buffer));
#elif LV_COLOR_DEPTH == 32
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer));
#else
#error("Unsupported color format")
#endif
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
}
static void lv_opengles_texture_deinit()
{
GL_CALL(glDeleteTextures(1, &texture_id));
texture_id = 0;
}
static void lv_opengles_texture_bind(unsigned int slot)
{
GL_CALL(glActiveTexture(GL_TEXTURE0 + slot));
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture_id));
}
static void lv_opengles_texture_update(void * buffer, int width, int height)
{
GL_CALL(glBindTexture(GL_TEXTURE_2D, texture_id));
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
/*Color depth: 8 (A8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888)*/
#if LV_COLOR_DEPTH == 8
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, width, height, 0, GL_RED, GL_UNSIGNED_BYTE, buffer));
#elif LV_COLOR_DEPTH == 16
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, buffer));
#elif LV_COLOR_DEPTH == 24
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_BGR, GL_UNSIGNED_BYTE, buffer));
#elif LV_COLOR_DEPTH == 32
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, buffer));
#else
#error("Unsupported color format")
#endif
}
#endif /* LV_USE_OPENGLES */

View File

@@ -10,14 +10,69 @@
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_OPENGLES
void lv_opengles_init(uint8_t * frame_buffer, int32_t hor, int32_t ver);
#include "../../misc/lv_area.h"
#include "../../misc/lv_color.h"
void lv_opengles_update(uint8_t * frame_buffer, int32_t hor, int32_t ver);
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize OpenGL
* @note it is not necessary to call this if you use `lv_glfw_window_create`
*/
void lv_opengles_init(void);
/**
* Deinitialize OpenGL
* @note it is not necessary to call this if you use `lv_glfw_window_create`
*/
void lv_opengles_deinit(void);
/**
* Render a texture
* @param texture OpenGL texture ID
* @param texture_area the area in the window to render the texture in
* @param opa opacity to blend the texture with existing contents
* @param disp_w width of the window being rendered to
* @param disp_h height of the window being rendered to
*/
void lv_opengles_render_texture(unsigned int texture, const lv_area_t * texture_area, lv_opa_t opa, int32_t disp_w,
int32_t disp_h);
/**
* Clear the window/display
*/
void lv_opengles_render_clear(void);
/**
* Set the OpenGL viewport
* @param x x position of the viewport
* @param y y position of the viewport
* @param w width of the viewport
* @param h height of the viewport
*/
void lv_opengles_viewport(int32_t x, int32_t y, int32_t w, int32_t h);
/**********************
* MACROS
**********************/
#endif /* LV_USE_OPENGLES */
#ifdef __cplusplus

View File

@@ -0,0 +1,151 @@
/**
* @file lv_opengles_texture.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_opengles_texture.h"
#if LV_USE_OPENGLES
#include "lv_opengles_debug.h"
#include "../../display/lv_display_private.h"
#include <stdlib.h>
#include <GL/glew.h>
#include <GLFW/glfw3.h>
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
unsigned int texture_id;
uint8_t * fb1;
} lv_opengles_texture_t;
/**********************
* STATIC PROTOTYPES
**********************/
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map);
static void release_disp_cb(lv_event_t * e);
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_display_t * lv_opengles_texture_create(int32_t w, int32_t h)
{
lv_display_t * disp = lv_display_create(w, h);
if(disp == NULL) {
return NULL;
}
lv_opengles_texture_t * dsc = lv_malloc_zeroed(sizeof(lv_opengles_texture_t));
LV_ASSERT_MALLOC(dsc);
if(dsc == NULL) {
lv_display_delete(disp);
return NULL;
}
uint32_t stride = lv_draw_buf_width_to_stride(w, lv_display_get_color_format(disp));
uint32_t buf_size = stride * w;
dsc->fb1 = malloc(buf_size);
if(dsc->fb1 == NULL) {
lv_free(dsc);
lv_display_delete(disp);
return NULL;
}
GL_CALL(glGenTextures(1, &dsc->texture_id));
GL_CALL(glBindTexture(GL_TEXTURE_2D, dsc->texture_id));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
lv_display_set_buffers(disp, dsc->fb1, NULL, buf_size, LV_DISPLAY_RENDER_MODE_DIRECT);
lv_display_set_flush_cb(disp, flush_cb);
lv_display_set_driver_data(disp, dsc);
lv_display_add_event_cb(disp, release_disp_cb, LV_EVENT_DELETE, disp);
return disp;
}
unsigned int lv_opengles_texture_get_texture_id(lv_display_t * disp)
{
if(disp->flush_cb != flush_cb) {
return 0;
}
lv_opengles_texture_t * dsc = lv_display_get_driver_data(disp);
return dsc->texture_id;
}
lv_display_t * lv_opengles_texture_get_from_texture_id(unsigned int texture_id)
{
lv_display_t * disp = NULL;
while(NULL != (disp = lv_display_get_next(disp))) {
unsigned int disp_texture_id = lv_opengles_texture_get_texture_id(disp);
if(disp_texture_id == texture_id) {
return disp;
}
}
return NULL;
}
/**********************
* STATIC FUNCTIONS
**********************/
static void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
{
LV_UNUSED(area);
LV_UNUSED(px_map);
if(lv_display_flush_is_last(disp)) {
lv_opengles_texture_t * dsc = lv_display_get_driver_data(disp);
GL_CALL(glBindTexture(GL_TEXTURE_2D, dsc->texture_id));
GL_CALL(glPixelStorei(GL_UNPACK_ALIGNMENT, 1));
/*Color depth: 8 (A8), 16 (RGB565), 24 (RGB888), 32 (XRGB8888)*/
#if LV_COLOR_DEPTH == 8
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, disp->hor_res, disp->ver_res, 0, GL_RED, GL_UNSIGNED_BYTE, dsc->fb1));
#elif LV_COLOR_DEPTH == 16
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB565, disp->hor_res, disp->ver_res, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5,
dsc->fb1));
#elif LV_COLOR_DEPTH == 24
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, disp->hor_res, disp->ver_res, 0, GL_BGR, GL_UNSIGNED_BYTE, dsc->fb1));
#elif LV_COLOR_DEPTH == 32
GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, disp->hor_res, disp->ver_res, 0, GL_BGRA, GL_UNSIGNED_BYTE, dsc->fb1));
#else
#error("Unsupported color format")
#endif
}
lv_display_flush_ready(disp);
}
static void release_disp_cb(lv_event_t * e)
{
lv_display_t * disp = lv_event_get_user_data(e);
lv_opengles_texture_t * dsc = lv_display_get_driver_data(disp);
free(dsc->fb1);
lv_free(dsc);
}
#endif /*LV_USE_OPENGLES*/

View File

@@ -0,0 +1,66 @@
/**
* @file lv_opengles_texture.h
*
*/
#ifndef LV_OPENGLES_TEXTURE_H
#define LV_OPENGLES_TEXTURE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_OPENGLES
#include "../../display/lv_display.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a display that flushes to an OpenGL texture
* @param w width in pixels of the texture
* @param h height in pixels of the texture
* @return the new display
*/
lv_display_t * lv_opengles_texture_create(int32_t w, int32_t h);
/**
* Get the OpenGL texture ID of the display
* @param disp display
* @return texture ID
*/
unsigned int lv_opengles_texture_get_texture_id(lv_display_t * disp);
/**
* Get the display of an OpenGL texture if it is associated with one
* @param texture_id OpenGL texture ID
* @return display or `NULL` if there no display with that texture ID
*/
lv_display_t * lv_opengles_texture_get_from_texture_id(unsigned int texture_id);
/**********************
* MACROS
**********************/
#endif /* LV_USE_OPENGLES */
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_OPENGLES_TEXTURE_H*/

View File

@@ -38,7 +38,8 @@ extern "C" {
#include "windows/lv_windows_display.h"
#include "glfw/lv_glfw_window.h"
#include "glfw/lv_glfw_mouse.h"
#include "glfw/lv_opengles_texture.h"
#include "glfw/lv_opengles_driver.h"
#include "qnx/lv_qnx.h"

View File

@@ -321,6 +321,9 @@ typedef struct lv_rlottie_t lv_rlottie_t;
typedef struct lv_ffmpeg_player_t lv_ffmpeg_player_t;
typedef struct lv_glfw_window_t lv_glfw_window_t;
typedef struct lv_glfw_texture_t lv_glfw_texture_t;
typedef uint32_t lv_prop_id_t;
#if LV_USE_OBJ_PROPERTY