feat(widget): Add lv_3dtexture widget and 3D draw task type (#8033)

Co-authored-by: Gabor Kiss-Vamosi <kisvegabor@gmail.com>
This commit is contained in:
Liam Howatt
2025-04-16 19:44:40 +02:00
committed by GitHub
parent bb681971b3
commit c29b220309
15 changed files with 570 additions and 1 deletions
+76
View File
@@ -0,0 +1,76 @@
.. _lv_3dtexture:
=========================
3D Texture (lv_3dtexture)
=========================
Overview
********
3D texture widgets are used to embed an external 3D graphics library's "texutre" primitive
into an LVGL UI.
.. _lv_3dtexture_parts_and_styles:
Parts and Styles
****************
The size should be set to the actual size of the texture primitive.
The opacity may also be changed.
.. _lv_3dtexture_usage:
Usage
*****
Requires a draw unit to be enabled which can draw the
:cpp:enumerator:`LV_DRAW_TASK_TYPE_3D` draw task type.
OpenGL is the first supported 3D graphics backend. The following must be enabled.
- :c:macro:`LV_USE_3DTEXTURE`
- :c:macro:`LV_USE_OPENGLES`
- :c:macro:`LV_USE_DRAW_OPENGLES`
See :ref:`LVGL's OpenGLES driver docs <opengl_es_driver>` to create a window and a
display texture.
The `lv_example_3dtexture <https://github.com/lvgl/lv_example_3dtexture>` repo is a
demonstration of how to use the ``3dtexture`` widget to load glTF models with OpenGL
and display them in LVGL.
.. code-block:: c
lv_obj_t * tex = lv_3dtexture_create(parent);
/*Render something to the texture. You can replace it with your code.*/
lv_3dtexture_id_t gltf_texture = render_gltf_model_to_opengl_texture(path, w, h, color);
lv_3dtexture_set_src(tex, gltf_texture);
lv_obj_set_size(tex, w, h);
lv_obj_set_style_opa(tex, opa, 0);
The real type of :cpp:type:`lv_3dtexture_id_t` depends on the active 3D graphics backend.
With OpenGL, the type is ``unsigned int``.
.. _lv_3dtexture_events:
Events
******
3D Texture has no special event handling.
.. _lv_3dtexture_example:
Example
*******
See the `lv_example_3dtexture <https://github.com/lvgl/lv_example_3dtexture>` repo.
.. _lv_3dtexture_api:
API
***
+2
View File
@@ -776,6 +776,8 @@
#define LV_USE_WIN 1 #define LV_USE_WIN 1
#define LV_USE_3DTEXTURE 0
/*================== /*==================
* THEMES * THEMES
*==================*/ *==================*/
+1
View File
@@ -83,6 +83,7 @@ extern "C" {
#include "src/widgets/textarea/lv_textarea.h" #include "src/widgets/textarea/lv_textarea.h"
#include "src/widgets/tileview/lv_tileview.h" #include "src/widgets/tileview/lv_tileview.h"
#include "src/widgets/win/lv_win.h" #include "src/widgets/win/lv_win.h"
#include "src/widgets/3dtexture/lv_3dtexture.h"
#include "src/others/snapshot/lv_snapshot.h" #include "src/others/snapshot/lv_snapshot.h"
#include "src/others/sysmon/lv_sysmon.h" #include "src/others/sysmon/lv_sysmon.h"
+1
View File
@@ -96,6 +96,7 @@ extern "C" {
#include "src/widgets/label/lv_label_private.h" #include "src/widgets/label/lv_label_private.h"
#include "src/widgets/canvas/lv_canvas_private.h" #include "src/widgets/canvas/lv_canvas_private.h"
#include "src/widgets/tabview/lv_tabview_private.h" #include "src/widgets/tabview/lv_tabview_private.h"
#include "src/widgets/3dtexture/lv_3dtexture_private.h"
#include "src/tick/lv_tick_private.h" #include "src/tick/lv_tick_private.h"
#include "src/stdlib/builtin/lv_tlsf_private.h" #include "src/stdlib/builtin/lv_tlsf_private.h"
#include "src/libs/rlottie/lv_rlottie_private.h" #include "src/libs/rlottie/lv_rlottie_private.h"
+5
View File
@@ -15,6 +15,7 @@
#include "lv_draw_private.h" #include "lv_draw_private.h"
#include "lv_draw_mask_private.h" #include "lv_draw_mask_private.h"
#include "lv_draw_vector_private.h" #include "lv_draw_vector_private.h"
#include "lv_draw_3d.h"
#include "sw/lv_draw_sw.h" #include "sw/lv_draw_sw.h"
#include "../display/lv_display_private.h" #include "../display/lv_display_private.h"
#include "../core/lv_global.h" #include "../core/lv_global.h"
@@ -581,6 +582,10 @@ static inline size_t get_draw_dsc_size(lv_draw_task_type_t type)
#if LV_USE_VECTOR_GRAPHIC #if LV_USE_VECTOR_GRAPHIC
case LV_DRAW_TASK_TYPE_VECTOR: case LV_DRAW_TASK_TYPE_VECTOR:
return sizeof(lv_draw_vector_task_dsc_t); return sizeof(lv_draw_vector_task_dsc_t);
#endif
#if LV_USE_3DTEXTURE
case LV_DRAW_TASK_TYPE_3D:
return sizeof(lv_draw_3d_dsc_t);
#endif #endif
/* Note that default is not added here because when adding new draw task type, /* Note that default is not added here because when adding new draw task type,
* if forget to add case, the compiler will automatically report a warning. * if forget to add case, the compiler will automatically report a warning.
+3
View File
@@ -60,6 +60,9 @@ typedef enum {
#if LV_USE_VECTOR_GRAPHIC #if LV_USE_VECTOR_GRAPHIC
LV_DRAW_TASK_TYPE_VECTOR, LV_DRAW_TASK_TYPE_VECTOR,
#endif #endif
#if LV_USE_3DTEXTURE
LV_DRAW_TASK_TYPE_3D,
#endif
} lv_draw_task_type_t; } lv_draw_task_type_t;
typedef enum { typedef enum {
+69
View File
@@ -0,0 +1,69 @@
/**
* @file lv_draw_3d.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_draw_3d.h"
#if LV_USE_3DTEXTURE
#include "lv_draw_private.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
/**********************
* STATIC VARIABLES
**********************/
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
void lv_draw_3d_dsc_init(lv_draw_3d_dsc_t * dsc)
{
lv_memzero(dsc, sizeof(lv_draw_3d_dsc_t));
dsc->base.dsc_size = sizeof(lv_draw_3d_dsc_t);
dsc->tex_id = LV_3DTEXTURE_ID_NULL;
dsc->opa = LV_OPA_COVER;
}
lv_draw_3d_dsc_t * lv_draw_task_get_3d_dsc(lv_draw_task_t * task)
{
return task->type == LV_DRAW_TASK_TYPE_3D ? (lv_draw_3d_dsc_t *)task->draw_dsc : NULL;
}
void lv_draw_3d(lv_layer_t * layer, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords)
{
LV_PROFILER_DRAW_BEGIN;
lv_draw_task_t * t = lv_draw_add_task(layer, coords, LV_DRAW_TASK_TYPE_3D);
lv_memcpy(t->draw_dsc, dsc, sizeof(*dsc));
lv_draw_finalize_task_creation(layer, t);
LV_PROFILER_DRAW_END;
}
/**********************
* STATIC FUNCTIONS
**********************/
#endif /*LV_USE_3DTEXTURE*/
+70
View File
@@ -0,0 +1,70 @@
/**
* @file lv_draw_3d.h
*
*/
#ifndef LV_DRAW_3D_H
#define LV_DRAW_3D_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../lv_conf_internal.h"
#if LV_USE_3DTEXTURE
#include "lv_draw.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
typedef struct {
lv_draw_dsc_base_t base;
lv_3dtexture_id_t tex_id;
lv_opa_t opa;
} lv_draw_3d_dsc_t;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Initialize a 3D draw descriptor
* @param dsc pointer to a draw descriptor
*/
void lv_draw_3d_dsc_init(lv_draw_3d_dsc_t * dsc);
/**
* Try to get a 3D draw descriptor from a draw task.
* @param task draw task
* @return the task's draw descriptor or NULL if the task is not of type LV_DRAW_TASK_TYPE_3D
*/
lv_draw_3d_dsc_t * lv_draw_task_get_3d_dsc(lv_draw_task_t * task);
/**
* Create a 3D draw task
* @param layer pointer to a layer
* @param dsc pointer to an initialized `lv_draw_3d_dsc_t` variable
*/
void lv_draw_3d(lv_layer_t * layer, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords);
/**********************
* MACROS
**********************/
#endif /*LV_USE_3DTEXTURE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_DRAW_3D_H*/
+41 -1
View File
@@ -22,6 +22,7 @@
#include "../../draw/lv_draw_image.h" #include "../../draw/lv_draw_image.h"
#include "../../draw/lv_draw_triangle.h" #include "../../draw/lv_draw_triangle.h"
#include "../../draw/lv_draw_line.h" #include "../../draw/lv_draw_line.h"
#include "../../draw/lv_draw_3d.h"
#include "../../core/lv_obj.h" #include "../../core/lv_obj.h"
#include "../../core/lv_refr_private.h" #include "../../core/lv_refr_private.h"
#include "../../display/lv_display_private.h" #include "../../display/lv_display_private.h"
@@ -75,6 +76,10 @@ static unsigned int layer_get_texture(lv_layer_t * layer);
static unsigned int get_framebuffer(lv_draw_opengles_unit_t * u); static unsigned int get_framebuffer(lv_draw_opengles_unit_t * u);
static unsigned int create_texture(int32_t w, int32_t h, const void * data); static unsigned int create_texture(int32_t w, int32_t h, const void * data);
#if LV_USE_3DTEXTURE
static void lv_draw_opengles_3d(lv_draw_task_t * t, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords);
#endif
/********************** /**********************
* STATIC VARIABLES * STATIC VARIABLES
**********************/ **********************/
@@ -223,7 +228,7 @@ static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
} }
/*If not refreshing the display probably it's a canvas rendering /*If not refreshing the display probably it's a canvas rendering
*which his not support in SDL as it's not a texture.*/ *which his not supported in OpenGL as it's not a texture.*/
if(lv_refr_get_disp_refreshing() == NULL) return 0; if(lv_refr_get_disp_refreshing() == NULL) return 0;
if(((lv_draw_dsc_base_t *)task->draw_dsc)->user_data == NULL) { if(((lv_draw_dsc_base_t *)task->draw_dsc)->user_data == NULL) {
@@ -548,6 +553,13 @@ static void execute_drawing(lv_draw_opengles_unit_t * u)
return; return;
} }
#if LV_USE_3DTEXTURE
if(t->type == LV_DRAW_TASK_TYPE_3D) {
lv_draw_opengles_3d(t, t->draw_dsc, &t->area);
return;
}
#endif
draw_from_cached_texture(t); draw_from_cached_texture(t);
} }
@@ -589,4 +601,32 @@ static unsigned int create_texture(int32_t w, int32_t h, const void * data)
return texture; return texture;
} }
#if LV_USE_3DTEXTURE
static void lv_draw_opengles_3d(lv_draw_task_t * t, const lv_draw_3d_dsc_t * dsc, const lv_area_t * coords)
{
lv_draw_opengles_unit_t * u = (lv_draw_opengles_unit_t *) t->draw_unit;
lv_layer_t * dest_layer = t->target_layer;
unsigned int target_texture = layer_get_texture(dest_layer);
LV_ASSERT(target_texture != 0);
int32_t targ_tex_w = lv_area_get_width(&dest_layer->buf_area);
int32_t targ_tex_h = lv_area_get_height(&dest_layer->buf_area);
GL_CALL(glBindTexture(GL_TEXTURE_2D, target_texture));
unsigned int framebuffer = get_framebuffer(u);
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, framebuffer));
GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, target_texture, 0));
lv_opengles_viewport(0, 0, targ_tex_w, targ_tex_h);
lv_area_t clip_area = t->clip_area;
lv_area_move(&clip_area, -dest_layer->buf_area.x1, -dest_layer->buf_area.y1);
lv_opengles_render_texture(dsc->tex_id, coords, dsc->opa, targ_tex_w, targ_tex_h, &clip_area, true);
GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
}
#endif /*LV_USE_3DTEXTURE*/
#endif /*LV_USE_DRAW_OPENGLES*/ #endif /*LV_USE_DRAW_OPENGLES*/
+4
View File
@@ -227,6 +227,10 @@ static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task)
} }
} }
break; break;
#if LV_USE_3DTEXTURE
case LV_DRAW_TASK_TYPE_3D:
return 0;
#endif
default: default:
break; break;
} }
+8
View File
@@ -2483,6 +2483,14 @@
#endif #endif
#endif #endif
#ifndef LV_USE_3DTEXTURE
#ifdef CONFIG_LV_USE_3DTEXTURE
#define LV_USE_3DTEXTURE CONFIG_LV_USE_3DTEXTURE
#else
#define LV_USE_3DTEXTURE 0
#endif
#endif
/*================== /*==================
* THEMES * THEMES
*==================*/ *==================*/
+18
View File
@@ -41,6 +41,16 @@ extern "C" {
#endif #endif
#if LV_USE_3DTEXTURE
#if LV_USE_OPENGLES
#define LV_3DTEXTURE_ID_NULL 0u
#endif
#ifndef LV_3DTEXTURE_ID_NULL
#error enable LV_USE_OPENGLES to use LV_USE_3DTEXTURE
#endif
#endif /*LV_USE_3DTEXTURE*/
/********************** /**********************
* TYPEDEFS * TYPEDEFS
**********************/ **********************/
@@ -81,6 +91,12 @@ typedef float lv_value_precise_t;
typedef int32_t lv_value_precise_t; typedef int32_t lv_value_precise_t;
#endif #endif
#if LV_USE_3DTEXTURE
#if LV_USE_OPENGLES
typedef unsigned int lv_3dtexture_id_t;
#endif
#endif
/** /**
* Typedefs from various lvgl modules. * Typedefs from various lvgl modules.
* They are defined here to avoid circular dependencies. * They are defined here to avoid circular dependencies.
@@ -257,6 +273,8 @@ typedef struct _lv_tileview_tile_t lv_tileview_tile_t;
typedef struct _lv_win_t lv_win_t; typedef struct _lv_win_t lv_win_t;
typedef struct _lv_3dtexture_t lv_3dtexture_t;
typedef struct _lv_observer_t lv_observer_t; typedef struct _lv_observer_t lv_observer_t;
typedef struct _lv_monkey_config_t lv_monkey_config_t; typedef struct _lv_monkey_config_t lv_monkey_config_t;
+144
View File
@@ -0,0 +1,144 @@
/**
* @file lv_3dtexture.c
*
*/
/*********************
* INCLUDES
*********************/
#include "lv_3dtexture_private.h"
#if LV_USE_3DTEXTURE
#include "../../core/lv_obj_class_private.h"
#include "../../draw/lv_draw_3d.h"
/*********************
* DEFINES
*********************/
#define MY_CLASS (&lv_3dtexture_class)
/**********************
* TYPEDEFS
**********************/
/**********************
* STATIC PROTOTYPES
**********************/
static void lv_3dtexture_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_3dtexture_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj);
static void lv_3dtexture_event(const lv_obj_class_t * class_p, lv_event_t * e);
static void draw_3dtexture(lv_event_t * e);
/**********************
* STATIC VARIABLES
**********************/
const lv_obj_class_t lv_3dtexture_class = {
.constructor_cb = lv_3dtexture_constructor,
.destructor_cb = lv_3dtexture_destructor,
.event_cb = lv_3dtexture_event,
.width_def = LV_DPI_DEF,
.height_def = LV_DPI_DEF,
.instance_size = sizeof(lv_3dtexture_t),
.base_class = &lv_obj_class,
.name = "3dtexture",
};
/**********************
* MACROS
**********************/
/**********************
* GLOBAL FUNCTIONS
**********************/
lv_obj_t * lv_3dtexture_create(lv_obj_t * parent)
{
LV_LOG_INFO("begin");
lv_obj_t * obj = lv_obj_class_create_obj(MY_CLASS, parent);
lv_obj_class_init_obj(obj);
return obj;
}
void lv_3dtexture_set_src(lv_obj_t * obj, lv_3dtexture_id_t id)
{
LV_ASSERT_OBJ(obj, MY_CLASS);
lv_3dtexture_t * tex = (lv_3dtexture_t *)obj;
tex->id = id;
}
/*======================
* Add/remove functions
*=====================*/
/*=====================
* Setter functions
*====================*/
/*=====================
* Getter functions
*====================*/
/*=====================
* Other functions
*====================*/
/**********************
* STATIC FUNCTIONS
**********************/
static void lv_3dtexture_constructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
LV_TRACE_OBJ_CREATE("begin");
lv_3dtexture_t * tex = (lv_3dtexture_t *)obj;
tex->id = LV_3DTEXTURE_ID_NULL;
LV_TRACE_OBJ_CREATE("finished");
}
static void lv_3dtexture_destructor(const lv_obj_class_t * class_p, lv_obj_t * obj)
{
LV_UNUSED(class_p);
lv_3dtexture_t * tex = (lv_3dtexture_t *)obj;
LV_UNUSED(tex);
}
static void lv_3dtexture_event(const lv_obj_class_t * class_p, lv_event_t * e)
{
LV_UNUSED(class_p);
lv_result_t res;
/*Call the ancestor's event handler*/
res = lv_obj_event_base(MY_CLASS, e);
if(res != LV_RESULT_OK) return;
lv_event_code_t code = lv_event_get_code(e);
if(code == LV_EVENT_DRAW_MAIN) {
draw_3dtexture(e);
}
}
static void draw_3dtexture(lv_event_t * e)
{
lv_obj_t * obj = lv_event_get_current_target(e);
lv_3dtexture_t * tex = (lv_3dtexture_t *)obj;
lv_layer_t * layer = lv_event_get_layer(e);
lv_draw_3d_dsc_t dsc;
lv_draw_3d_dsc_init(&dsc);
dsc.tex_id = tex->id;
dsc.opa = lv_obj_get_style_opa(obj, 0);
lv_area_t coords;
lv_obj_get_coords(obj, &coords);
lv_draw_3d(layer, &dsc, &coords);
}
#endif /*LV_USE_3DTEXTURE*/
+78
View File
@@ -0,0 +1,78 @@
/**
* @file lv_3dtexture.h
*
*/
#ifndef LV_3DTEXTURE_H
#define LV_3DTEXTURE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "../../lv_conf_internal.h"
#if LV_USE_3DTEXTURE
#include "../../core/lv_obj.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
LV_ATTRIBUTE_EXTERN_DATA extern const lv_obj_class_t lv_3dtexture_class;
/**********************
* GLOBAL PROTOTYPES
**********************/
/**
* Create a 3dtexture object
* @param parent pointer to an object, it will be the parent of the new 3dtexture
* @return pointer to the created 3dtexture
*/
lv_obj_t * lv_3dtexture_create(lv_obj_t * parent);
/**
* Set the source texture of the widget.
* The object size should be manually set to match.
* @param obj the 3dtexture widget
* @param id the texture handle from the 3D graphics backend.
* I.e., an `unsigned int` texture for OpenGL.
*/
void lv_3dtexture_set_src(lv_obj_t * obj, lv_3dtexture_id_t id);
/*======================
* Add/remove functions
*=====================*/
/*=====================
* Setter functions
*====================*/
/*=====================
* Getter functions
*====================*/
/*=====================
* Other functions
*====================*/
/**********************
* MACROS
**********************/
#endif /*LV_USE_3DTEXTURE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_3DTEXTURE_H*/
@@ -0,0 +1,50 @@
/**
* @file lv_3dtexture_private.h
*
*/
#ifndef LV_3DTEXTURE_PRIVATE_H
#define LV_3DTEXTURE_PRIVATE_H
#ifdef __cplusplus
extern "C" {
#endif
/*********************
* INCLUDES
*********************/
#include "lv_3dtexture.h"
#if LV_USE_3DTEXTURE
#include "../../core/lv_obj_private.h"
/*********************
* DEFINES
*********************/
/**********************
* TYPEDEFS
**********************/
/*Data of 3dtexture*/
struct _lv_3dtexture_t {
lv_obj_t obj;
lv_3dtexture_id_t id;
};
/**********************
* GLOBAL PROTOTYPES
**********************/
/**********************
* MACROS
**********************/
#endif /*LV_USE_3DTEXTURE*/
#ifdef __cplusplus
} /*extern "C"*/
#endif
#endif /*LV_3DTEXTURE_PRIVATE_H*/