feat(opengles): add basic driver for opengles (#6254)
Co-authored-by: Dany Liu <dany.yang.liu@email.com> Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
9
Kconfig
9
Kconfig
@@ -1646,6 +1646,15 @@ menu "LVGL configuration"
|
||||
config LV_USE_WINDOWS
|
||||
bool "Use LVGL Windows backend"
|
||||
default n
|
||||
|
||||
config LV_USE_OPENGLES
|
||||
bool "Use GLFW and OpenGL to open window on PC and handle mouse and keyboard"
|
||||
default n
|
||||
|
||||
config LV_USE_OPENGLES_DEBUG
|
||||
bool "Enable debug mode for OpenGL"
|
||||
depends on LV_USE_OPENGLES
|
||||
default n
|
||||
endmenu
|
||||
|
||||
menu "Examples"
|
||||
|
||||
@@ -10,3 +10,4 @@ Drivers
|
||||
libinput
|
||||
X11
|
||||
windows
|
||||
opengles
|
||||
|
||||
65
docs/integration/driver/opengles.rst
Normal file
65
docs/integration/driver/opengles.rst
Normal file
@@ -0,0 +1,65 @@
|
||||
===============================
|
||||
OpenGL ES Display/Inputs driver
|
||||
===============================
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
| The **OpenGL ES** display/input `driver <https://github.com/lvgl/lvgl/src/drivers/opengles>`__ offers support for simulating the LVGL display and keyboard/mouse inputs in an desktop window created via GLFW.
|
||||
| It is an alternative to **Wayland**, **XCB**, **SDL** or **Qt**.
|
||||
|
||||
The main purpose for this driver is for testing/debugging the LVGL application in an **OpenGL** simulation window.
|
||||
|
||||
Prerequisites
|
||||
-------------
|
||||
|
||||
The OpenGL driver uses GLEW GLFW to access the OpenGL window manager.
|
||||
|
||||
1. Install GLEW and GLFW: ``sudo apt-get install libglew-dev libglfw3-dev``
|
||||
|
||||
Configure OpenGL driver
|
||||
-----------------------
|
||||
|
||||
1. Required linked libraries: -lGL -lGLEW -lglfw
|
||||
2. Enable the OpenGL driver support in lv_conf.h, by cmake compiler define or by KConfig
|
||||
.. code:: c
|
||||
|
||||
#define LV_USE_OPENGLES 1
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
.. code:: c
|
||||
|
||||
#include "lvgl/lvgl.h"
|
||||
#include "lvgl/examples/lv_examples.h"
|
||||
#include "lvgl/demos/lv_demos.h"
|
||||
|
||||
int main()
|
||||
{
|
||||
lv_init();
|
||||
|
||||
lv_display_t * disp = lv_glfw_window_create(480, 272);
|
||||
|
||||
lv_indev_t * mouse = lv_glfw_mouse_create();
|
||||
lv_indev_set_group(mouse, lv_group_get_default());
|
||||
lv_indev_set_display(mouse, disp);
|
||||
|
||||
lv_display_set_default(disp);
|
||||
|
||||
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*/
|
||||
|
||||
lv_demo_widgets();
|
||||
|
||||
while (1)
|
||||
{
|
||||
uint32_t time_till_next = lv_timer_handler();
|
||||
lv_delay_ms(time_till_next);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -978,6 +978,12 @@
|
||||
/* LVGL Windows backend */
|
||||
#define LV_USE_WINDOWS 0
|
||||
|
||||
/* Use OpenGL to open window on PC and handle mouse and keyboard */
|
||||
#define LV_USE_OPENGLES 0
|
||||
#if LV_USE_OPENGLES
|
||||
#define LV_USE_OPENGLES_DEBUG 1 /* Enable or disable debug for opengles */
|
||||
#endif
|
||||
|
||||
/*==================
|
||||
* EXAMPLES
|
||||
*==================*/
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
vcpkg install vcpkg-tool-ninja libpng freetype
|
||||
vcpkg install vcpkg-tool-ninja libpng freetype opengl glfw3 glew
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
pip install pypng lz4
|
||||
if %errorlevel% neq 0 exit /b %errorlevel%
|
||||
|
||||
@@ -9,6 +9,7 @@ sudo dpkg --add-architecture i386
|
||||
sudo apt update
|
||||
sudo apt install gcc gcc-multilib g++-multilib ninja-build \
|
||||
libpng-dev libjpeg-turbo8-dev libfreetype6-dev \
|
||||
libglew-dev libglfw3-dev \
|
||||
libpng-dev:i386 libjpeg-dev:i386 libfreetype6-dev:i386 \
|
||||
ruby-full gcovr cmake python3 pngquant libinput-dev libxkbcommon-dev libdrm-dev pkg-config
|
||||
pip3 install pypng lz4
|
||||
|
||||
87
src/drivers/glfw/lv_glfw_mouse.c
Normal file
87
src/drivers/glfw/lv_glfw_mouse.c
Normal file
@@ -0,0 +1,87 @@
|
||||
/**
|
||||
* @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 */
|
||||
43
src/drivers/glfw/lv_glfw_mouse.h
Normal file
43
src/drivers/glfw/lv_glfw_mouse.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* @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 */
|
||||
89
src/drivers/glfw/lv_glfw_mouse_private.c
Normal file
89
src/drivers/glfw/lv_glfw_mouse_private.c
Normal file
@@ -0,0 +1,89 @@
|
||||
/**
|
||||
* @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 */
|
||||
52
src/drivers/glfw/lv_glfw_mouse_private.h
Normal file
52
src/drivers/glfw/lv_glfw_mouse_private.h
Normal file
@@ -0,0 +1,52 @@
|
||||
/**
|
||||
* @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 */
|
||||
379
src/drivers/glfw/lv_glfw_window.c
Normal file
379
src/drivers/glfw/lv_glfw_window.c
Normal file
@@ -0,0 +1,379 @@
|
||||
/**
|
||||
* @file lv_glfw_window.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "lv_glfw_window.h"
|
||||
#include "lv_glfw_mouse_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 "../../lv_init.h"
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "lv_opengles_driver.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* 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 VARIABLES
|
||||
**********************/
|
||||
static lv_timer_t * update_handler_timer;
|
||||
static lv_timer_t * event_handler_timer;
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
lv_display_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res)
|
||||
{
|
||||
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);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
lv_display_add_event_cb(disp, release_disp_cb, LV_EVENT_DELETE, disp);
|
||||
|
||||
lv_display_set_driver_data(disp, dsc);
|
||||
|
||||
int ret = window_create(disp);
|
||||
if(ret != 0) {
|
||||
lv_display_send_event(disp, LV_EVENT_DELETE, NULL);
|
||||
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);
|
||||
|
||||
lv_opengles_init(dsc->fb1, hor_res, ver_res);
|
||||
|
||||
return disp;
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void lv_glfw_window_quit(lv_display_t * disp)
|
||||
{
|
||||
lv_glfw_window_t * dsc = lv_display_get_driver_data(disp);
|
||||
if(inited) {
|
||||
lv_timer_delete(update_handler_timer);
|
||||
update_handler_timer = NULL;
|
||||
|
||||
glfwDestroyWindow(dsc->window);
|
||||
glfwTerminate();
|
||||
|
||||
inited = false;
|
||||
}
|
||||
}
|
||||
|
||||
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)) {
|
||||
window_update(disp);
|
||||
}
|
||||
|
||||
/*IMPORTANT! It must be called to tell the system the flush is ready*/
|
||||
lv_display_flush_ready(disp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handler for glfw events
|
||||
*/
|
||||
static void window_event_handler(lv_timer_t * t)
|
||||
{
|
||||
LV_UNUSED(t);
|
||||
if(deiniting == false) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
glfwSetWindowShouldClose(dsc->window, GLFW_TRUE);
|
||||
lv_display_send_event(disp, LV_EVENT_DELETE, NULL);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
if(!glfwWindowShouldClose(dsc->window)) {
|
||||
lv_opengles_update(dsc->fb1, disp->hor_res, disp->ver_res);
|
||||
|
||||
/* Swap front and back buffers */
|
||||
glfwSwapBuffers(dsc->window);
|
||||
|
||||
glfwPollEvents();
|
||||
}
|
||||
}
|
||||
|
||||
static void glfw_error_cb(int error, const char * description)
|
||||
{
|
||||
fprintf(stderr, "GLFW Error %d: %s\n", error, description);
|
||||
}
|
||||
|
||||
static void window_close_callback(GLFWwindow * window)
|
||||
{
|
||||
LV_UNUSED(window);
|
||||
deiniting = true;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void mouse_move_cllback(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);
|
||||
}
|
||||
|
||||
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_cllback);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static uint32_t lv_glfw_tick_count_callback(void)
|
||||
{
|
||||
int milliseconds = (int)(glfwGetTime() * 1000);
|
||||
return milliseconds;
|
||||
}
|
||||
|
||||
#endif /*LV_USE_OPENGLES*/
|
||||
46
src/drivers/glfw/lv_glfw_window.h
Normal file
46
src/drivers/glfw/lv_glfw_window.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/**
|
||||
* @file lv_glfw_window.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_GLFW_WINDOW_H
|
||||
#define LV_GLFW_WINDOW_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
|
||||
#include "../../display/lv_display.h"
|
||||
#include "../../indev/lv_indev.h"
|
||||
|
||||
#if LV_USE_OPENGLES
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL PROTOTYPES
|
||||
**********************/
|
||||
|
||||
lv_display_t * lv_glfw_window_create(int32_t hor_res, int32_t ver_res);
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
#endif /* LV_USE_OPENGLES */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV_GLFW_WINDOW_H */
|
||||
57
src/drivers/glfw/lv_opengles_debug.c
Normal file
57
src/drivers/glfw/lv_opengles_debug.c
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* @file lv_opengles_debug.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../display/lv_display.h"
|
||||
#include "lv_opengles_debug.h"
|
||||
|
||||
#if LV_USE_OPENGLES
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
|
||||
/***********************
|
||||
* GLOBAL PROTOTYPES
|
||||
***********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void GLClearError()
|
||||
{
|
||||
while(glGetError() != GL_NO_ERROR);
|
||||
}
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif /* LV_USE_OPENGLES */
|
||||
38
src/drivers/glfw/lv_opengles_debug.h
Normal file
38
src/drivers/glfw/lv_opengles_debug.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* @file lv_opengles_debug.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OPENGLES_DEBUG_H
|
||||
#define LV_OPENGLES_DEBUG_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#if LV_USE_OPENGLES
|
||||
|
||||
#include <GL/glew.h>
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
void GLClearError(void);
|
||||
|
||||
bool GLLogCall(const char * function, const char * file, int line);
|
||||
|
||||
#if LV_USE_OPENGLES_DEBUG
|
||||
#define GL_CALL(x) GLClearError();\
|
||||
x;\
|
||||
GLLogCall(#x, __FILE__, __LINE__)
|
||||
#else
|
||||
#define GL_CALL(x) x
|
||||
#endif
|
||||
|
||||
#endif /* LV_USE_OPENGLES */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV_OPENGLES_DEBUG_H */
|
||||
447
src/drivers/glfw/lv_opengles_driver.c
Normal file
447
src/drivers/glfw/lv_opengles_driver.c
Normal file
@@ -0,0 +1,447 @@
|
||||
/**
|
||||
* @file lv_opengles_driver.c
|
||||
*
|
||||
*/
|
||||
|
||||
/*********************
|
||||
* INCLUDES
|
||||
*********************/
|
||||
#include "../../display/lv_display.h"
|
||||
|
||||
#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"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
/**********************
|
||||
* TYPEDEFS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* STATIC PROTOTYPES
|
||||
**********************/
|
||||
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);
|
||||
static void lv_opengles_vertex_buffer_unbind(void);
|
||||
static void lv_opengles_vertex_array_init(void);
|
||||
static void lv_opengles_vertex_array_deinit(void);
|
||||
static void lv_opengles_vertex_array_bind(void);
|
||||
static void lv_opengles_vertex_array_unbind(void);
|
||||
static void lv_opengles_vertex_array_add_buffer(void);
|
||||
static void lv_opengles_index_buffer_init(const unsigned int * data, unsigned int count);
|
||||
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);
|
||||
static void lv_opengles_shader_deinit(void);
|
||||
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_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
|
||||
***********************/
|
||||
|
||||
/**********************
|
||||
* STATIC VARIABLES
|
||||
**********************/
|
||||
static unsigned int vertex_buffer_id = 0;
|
||||
|
||||
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 * vertex_shader =
|
||||
"#version 300 es\n"
|
||||
"\n"
|
||||
"in vec4 position;\n"
|
||||
"in vec2 texCoord;\n"
|
||||
"\n"
|
||||
"out vec2 v_TexCoord;\n"
|
||||
"\n"
|
||||
"void main()\n"
|
||||
"{\n"
|
||||
" gl_Position = position;\n"
|
||||
" v_TexCoord = texCoord;\n"
|
||||
"};\n";
|
||||
|
||||
static const char * fragment_shader =
|
||||
"#version 300 es\n"
|
||||
"\n"
|
||||
"precision mediump float;\n"
|
||||
"\n"
|
||||
"layout(location = 0) out vec4 color;\n"
|
||||
"\n"
|
||||
"in vec2 v_TexCoord;\n"
|
||||
"\n"
|
||||
"uniform vec4 u_Color;\n"
|
||||
"uniform sampler2D u_Texture;\n"
|
||||
"uniform int u_ColorDepth;\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"
|
||||
" } else {\n"
|
||||
" color = texColor;\n"
|
||||
" }\n"
|
||||
"};\n";
|
||||
|
||||
/**********************
|
||||
* MACROS
|
||||
**********************/
|
||||
|
||||
/**********************
|
||||
* GLOBAL FUNCTIONS
|
||||
**********************/
|
||||
|
||||
void lv_opengles_init(uint8_t * frame_buffer, int32_t hor, int32_t ver)
|
||||
{
|
||||
float positions[] = {
|
||||
-1.0f, 1.0f, 0.0f, 0.0f,
|
||||
1.0f, 1.0f, 1.0f, 0.0f,
|
||||
1.0f, -1.0f, 1.0f, 1.0f,
|
||||
-1.0f, -1.0f, 0.0f, 1.0f
|
||||
};
|
||||
|
||||
unsigned int indices[] = {
|
||||
0, 1, 2,
|
||||
2, 3, 0
|
||||
};
|
||||
|
||||
lv_opengles_vertex_buffer_init(positions, 4 * 4 * sizeof(float));
|
||||
|
||||
lv_opengles_vertex_array_init();
|
||||
lv_opengles_vertex_array_add_buffer();
|
||||
|
||||
lv_opengles_index_buffer_init(indices, 6);
|
||||
|
||||
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 */
|
||||
lv_opengles_vertex_array_unbind();
|
||||
lv_opengles_vertex_buffer_unbind();
|
||||
lv_opengles_index_buffer_unbind();
|
||||
lv_opengles_shader_unbind();
|
||||
}
|
||||
|
||||
void lv_opengles_deinit(void)
|
||||
{
|
||||
lv_opengles_texture_deinit();
|
||||
lv_opengles_shader_deinit();
|
||||
lv_opengles_index_buffer_deinit();
|
||||
lv_opengles_vertex_buffer_deinit();
|
||||
lv_opengles_vertex_array_deinit();
|
||||
}
|
||||
|
||||
void lv_opengles_update(uint8_t * frame_buffer, int32_t hor, int32_t ver)
|
||||
{
|
||||
lv_opengles_render_clear();
|
||||
lv_opengles_texture_update(frame_buffer, hor, ver);
|
||||
|
||||
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_render_draw();
|
||||
}
|
||||
|
||||
/**********************
|
||||
* STATIC FUNCTIONS
|
||||
**********************/
|
||||
|
||||
static void lv_opengles_vertex_buffer_init(const void * data, unsigned int size)
|
||||
{
|
||||
GL_CALL(glGenBuffers(1, &vertex_buffer_id));
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id));
|
||||
GL_CALL(glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
static void lv_opengles_vertex_buffer_deinit()
|
||||
{
|
||||
GL_CALL(glDeleteBuffers(1, &vertex_buffer_id));
|
||||
}
|
||||
|
||||
static void lv_opengles_vertex_buffer_bind()
|
||||
{
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, vertex_buffer_id));
|
||||
}
|
||||
|
||||
static void lv_opengles_vertex_buffer_unbind()
|
||||
{
|
||||
GL_CALL(glBindBuffer(GL_ARRAY_BUFFER, 0));
|
||||
}
|
||||
|
||||
static void lv_opengles_vertex_array_init()
|
||||
{
|
||||
GL_CALL(glGenVertexArrays(1, &vertex_array_id));
|
||||
}
|
||||
|
||||
static void lv_opengles_vertex_array_deinit()
|
||||
{
|
||||
GL_CALL(glDeleteVertexArrays(1, &vertex_array_id));
|
||||
}
|
||||
|
||||
static void lv_opengles_vertex_array_bind()
|
||||
{
|
||||
GL_CALL(glBindVertexArray(vertex_array_id));
|
||||
}
|
||||
|
||||
static void lv_opengles_vertex_array_unbind()
|
||||
{
|
||||
GL_CALL(glBindVertexArray(0));
|
||||
}
|
||||
|
||||
static void lv_opengles_vertex_array_add_buffer()
|
||||
{
|
||||
lv_opengles_vertex_buffer_bind();
|
||||
intptr_t offset = 0;
|
||||
|
||||
for(unsigned int i = 0; i < 2; i++) {
|
||||
lv_opengles_vertex_array_bind();
|
||||
GL_CALL(glEnableVertexAttribArray(i));
|
||||
GL_CALL(glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, 16, (const void *)offset));
|
||||
offset += 2 * 4;
|
||||
}
|
||||
}
|
||||
|
||||
static void lv_opengles_index_buffer_init(const unsigned int * data, unsigned int count)
|
||||
{
|
||||
index_buffer_count = count;
|
||||
GL_CALL(glGenBuffers(1, &index_buffer_id));
|
||||
|
||||
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_id));
|
||||
|
||||
GL_CALL(glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(GLuint), data, GL_STATIC_DRAW));
|
||||
}
|
||||
|
||||
static void lv_opengles_index_buffer_deinit()
|
||||
{
|
||||
GL_CALL(glDeleteBuffers(1, &index_buffer_id));
|
||||
}
|
||||
|
||||
static unsigned int lv_opengles_index_buffer_get_count()
|
||||
{
|
||||
return index_buffer_count;
|
||||
}
|
||||
|
||||
static void lv_opengles_index_buffer_bind()
|
||||
{
|
||||
GL_CALL(glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, index_buffer_id));
|
||||
}
|
||||
|
||||
static void lv_opengles_index_buffer_unbind()
|
||||
{
|
||||
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));
|
||||
const char * src = source;
|
||||
GL_CALL(glShaderSource(id, 1, &src, NULL));
|
||||
GL_CALL(glCompileShader(id));
|
||||
|
||||
int result;
|
||||
GL_CALL(glGetShaderiv(id, GL_COMPILE_STATUS, &result));
|
||||
if(result == GL_FALSE) {
|
||||
int length;
|
||||
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);
|
||||
GL_CALL(glDeleteShader(id));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
static unsigned int lv_opengles_shader_create(const char * vertexShader, const char * fragmentShader)
|
||||
{
|
||||
GL_CALL(unsigned int program = glCreateProgram());
|
||||
unsigned int vs = lv_opengles_shader_compile(GL_VERTEX_SHADER, vertexShader);
|
||||
unsigned int fs = lv_opengles_shader_compile(GL_FRAGMENT_SHADER, fragmentShader);
|
||||
|
||||
GL_CALL(glAttachShader(program, vs));
|
||||
GL_CALL(glAttachShader(program, fs));
|
||||
GL_CALL(glLinkProgram(program));
|
||||
GL_CALL(glValidateProgram(program));
|
||||
|
||||
GL_CALL(glDeleteShader(vs));
|
||||
GL_CALL(glDeleteShader(fs));
|
||||
|
||||
return program;
|
||||
}
|
||||
|
||||
static void lv_opengles_shader_init()
|
||||
{
|
||||
shader_id = lv_opengles_shader_create(vertex_shader, fragment_shader);
|
||||
}
|
||||
|
||||
static void lv_opengles_shader_deinit()
|
||||
{
|
||||
GL_CALL(glDeleteProgram(shader_id));
|
||||
}
|
||||
|
||||
static void lv_opengles_shader_bind()
|
||||
{
|
||||
GL_CALL(glUseProgram(shader_id));
|
||||
}
|
||||
|
||||
static void lv_opengles_shader_unbind()
|
||||
{
|
||||
GL_CALL(glUseProgram(0));
|
||||
}
|
||||
|
||||
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) {
|
||||
id = i;
|
||||
}
|
||||
}
|
||||
if(id == -1) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(shader_location[id] != 0) {
|
||||
return shader_location[id];
|
||||
}
|
||||
|
||||
GL_CALL(int location = glGetUniformLocation(shader_id, name));
|
||||
if(location == -1)
|
||||
LV_LOG_WARN("Warning: uniform '%s' doesn't exist!\n", name);
|
||||
|
||||
shader_location[id] = location;
|
||||
return location;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
GL_CALL(glUniform4f(lv_opengles_shader_get_uniform_location(name), v0, v1, v2, v3));
|
||||
}
|
||||
|
||||
static void lv_opengles_render_draw()
|
||||
{
|
||||
lv_opengles_shader_bind();
|
||||
lv_opengles_vertex_array_bind();
|
||||
lv_opengles_index_buffer_bind();
|
||||
unsigned int count = lv_opengles_index_buffer_get_count();
|
||||
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 */
|
||||
27
src/drivers/glfw/lv_opengles_driver.h
Normal file
27
src/drivers/glfw/lv_opengles_driver.h
Normal file
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @file lv_opengles_driver.h
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef LV_OPENGLES_DRIVER_H
|
||||
#define LV_OPENGLES_DRIVER_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#if LV_USE_OPENGLES
|
||||
|
||||
void lv_opengles_init(uint8_t * frame_buffer, int32_t hor, int32_t ver);
|
||||
|
||||
void lv_opengles_update(uint8_t * frame_buffer, int32_t hor, int32_t ver);
|
||||
|
||||
void lv_opengles_deinit(void);
|
||||
|
||||
#endif /* LV_USE_OPENGLES */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* LV_OPENGLES_DRIVER_H */
|
||||
@@ -37,6 +37,9 @@ extern "C" {
|
||||
#include "windows/lv_windows_input.h"
|
||||
#include "windows/lv_windows_display.h"
|
||||
|
||||
#include "glfw/lv_glfw_window.h"
|
||||
#include "glfw/lv_glfw_mouse.h"
|
||||
|
||||
/*********************
|
||||
* DEFINES
|
||||
*********************/
|
||||
|
||||
@@ -3191,6 +3191,28 @@
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Use OpenGL to open window on PC and handle mouse and keyboard */
|
||||
#ifndef LV_USE_OPENGLES
|
||||
#ifdef CONFIG_LV_USE_OPENGLES
|
||||
#define LV_USE_OPENGLES CONFIG_LV_USE_OPENGLES
|
||||
#else
|
||||
#define LV_USE_OPENGLES 0
|
||||
#endif
|
||||
#endif
|
||||
#if LV_USE_OPENGLES
|
||||
#ifndef LV_USE_OPENGLES_DEBUG
|
||||
#ifdef _LV_KCONFIG_PRESENT
|
||||
#ifdef CONFIG_LV_USE_OPENGLES_DEBUG
|
||||
#define LV_USE_OPENGLES_DEBUG CONFIG_LV_USE_OPENGLES_DEBUG
|
||||
#else
|
||||
#define LV_USE_OPENGLES_DEBUG 0
|
||||
#endif
|
||||
#else
|
||||
#define LV_USE_OPENGLES_DEBUG 1 /* Enable or disable debug for opengles */
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/*==================
|
||||
* EXAMPLES
|
||||
*==================*/
|
||||
|
||||
@@ -336,6 +336,18 @@ if ($ENV{NON_AMD64_BUILD})
|
||||
include_directories(${LIBINPUT_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
# OpenGL ES is required for its driver
|
||||
if (NOT $ENV{NON_AMD64_BUILD})
|
||||
find_package(OpenGL REQUIRED)
|
||||
find_package(GLEW REQUIRED)
|
||||
find_package(glfw3 REQUIRED)
|
||||
|
||||
# Include directories
|
||||
include_directories(${OPENGL_INCLUDE_DIR})
|
||||
include_directories(${GLEW_INCLUDE_DIRS})
|
||||
include_directories(${GLFW_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
if (NOT LIBINPUT_FOUND)
|
||||
message("libinput not found, defaulting to 0")
|
||||
add_definitions(-DLV_USE_LIBINPUT=0)
|
||||
@@ -423,6 +435,13 @@ foreach( test_case_fname ${TEST_CASE_FILES} )
|
||||
m
|
||||
pthread
|
||||
${TEST_LIBS})
|
||||
|
||||
if (NOT $ENV{NON_AMD64_BUILD})
|
||||
target_link_libraries(${test_name} PRIVATE
|
||||
${OPENGL_LIBRARIES} ${GLEW_LIBRARIES} glfw)
|
||||
endif()
|
||||
|
||||
|
||||
target_include_directories(${test_name} PUBLIC ${TEST_INCLUDE_DIRS})
|
||||
target_compile_options(${test_name} PUBLIC ${LVGL_TESTFILE_COMPILE_OPTIONS})
|
||||
|
||||
|
||||
@@ -134,6 +134,10 @@
|
||||
#define LV_LIBINPUT_XKB 1
|
||||
#endif
|
||||
|
||||
#if !defined(NON_AMD64_BUILD) && !defined(_MSC_VER) && !defined(_WIN32)
|
||||
#define LV_USE_OPENGLES 1
|
||||
#endif
|
||||
|
||||
#define LV_USE_FREETYPE 1
|
||||
#define LV_FREETYPE_USE_LVGL_PORT 0
|
||||
#define LV_FREETYPE_CACHE_FT_GLYPH_CNT 10
|
||||
|
||||
Reference in New Issue
Block a user