diff --git a/docs/src/details/widgets/3dtexture.rst b/docs/src/details/widgets/3dtexture.rst new file mode 100644 index 0000000000..eb26749ab7 --- /dev/null +++ b/docs/src/details/widgets/3dtexture.rst @@ -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 ` to create a window and a +display texture. + +The `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 ` repo. + + +.. _lv_3dtexture_api: + +API +*** diff --git a/lv_conf_template.h b/lv_conf_template.h index b2742d1154..dd03e8bb0e 100644 --- a/lv_conf_template.h +++ b/lv_conf_template.h @@ -776,6 +776,8 @@ #define LV_USE_WIN 1 +#define LV_USE_3DTEXTURE 0 + /*================== * THEMES *==================*/ diff --git a/lvgl.h b/lvgl.h index 6ee7e7379f..8cb6751e6a 100644 --- a/lvgl.h +++ b/lvgl.h @@ -83,6 +83,7 @@ extern "C" { #include "src/widgets/textarea/lv_textarea.h" #include "src/widgets/tileview/lv_tileview.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/sysmon/lv_sysmon.h" diff --git a/lvgl_private.h b/lvgl_private.h index cb8f9ba223..426a4ca418 100644 --- a/lvgl_private.h +++ b/lvgl_private.h @@ -96,6 +96,7 @@ extern "C" { #include "src/widgets/label/lv_label_private.h" #include "src/widgets/canvas/lv_canvas_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/stdlib/builtin/lv_tlsf_private.h" #include "src/libs/rlottie/lv_rlottie_private.h" diff --git a/src/draw/lv_draw.c b/src/draw/lv_draw.c index b24dda671b..a80ae196fc 100644 --- a/src/draw/lv_draw.c +++ b/src/draw/lv_draw.c @@ -15,6 +15,7 @@ #include "lv_draw_private.h" #include "lv_draw_mask_private.h" #include "lv_draw_vector_private.h" +#include "lv_draw_3d.h" #include "sw/lv_draw_sw.h" #include "../display/lv_display_private.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 case LV_DRAW_TASK_TYPE_VECTOR: 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 /* 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. diff --git a/src/draw/lv_draw.h b/src/draw/lv_draw.h index b35cb52f82..d394de87c8 100644 --- a/src/draw/lv_draw.h +++ b/src/draw/lv_draw.h @@ -60,6 +60,9 @@ typedef enum { #if LV_USE_VECTOR_GRAPHIC LV_DRAW_TASK_TYPE_VECTOR, #endif +#if LV_USE_3DTEXTURE + LV_DRAW_TASK_TYPE_3D, +#endif } lv_draw_task_type_t; typedef enum { diff --git a/src/draw/lv_draw_3d.c b/src/draw/lv_draw_3d.c new file mode 100644 index 0000000000..0ea6cbc759 --- /dev/null +++ b/src/draw/lv_draw_3d.c @@ -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*/ diff --git a/src/draw/lv_draw_3d.h b/src/draw/lv_draw_3d.h new file mode 100644 index 0000000000..436be9a8f5 --- /dev/null +++ b/src/draw/lv_draw_3d.h @@ -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*/ diff --git a/src/draw/opengles/lv_draw_opengles.c b/src/draw/opengles/lv_draw_opengles.c index 03a251c3e0..b3f2122a7c 100644 --- a/src/draw/opengles/lv_draw_opengles.c +++ b/src/draw/opengles/lv_draw_opengles.c @@ -22,6 +22,7 @@ #include "../../draw/lv_draw_image.h" #include "../../draw/lv_draw_triangle.h" #include "../../draw/lv_draw_line.h" +#include "../../draw/lv_draw_3d.h" #include "../../core/lv_obj.h" #include "../../core/lv_refr_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 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 **********************/ @@ -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 - *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_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; } +#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); } @@ -589,4 +601,32 @@ static unsigned int create_texture(int32_t w, int32_t h, const void * data) 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*/ diff --git a/src/draw/sw/lv_draw_sw.c b/src/draw/sw/lv_draw_sw.c index 7664849ae7..b1a8dc2b0c 100644 --- a/src/draw/sw/lv_draw_sw.c +++ b/src/draw/sw/lv_draw_sw.c @@ -227,6 +227,10 @@ static int32_t evaluate(lv_draw_unit_t * draw_unit, lv_draw_task_t * task) } } break; +#if LV_USE_3DTEXTURE + case LV_DRAW_TASK_TYPE_3D: + return 0; +#endif default: break; } diff --git a/src/lv_conf_internal.h b/src/lv_conf_internal.h index 671f17b551..d03bc2de52 100644 --- a/src/lv_conf_internal.h +++ b/src/lv_conf_internal.h @@ -2483,6 +2483,14 @@ #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 *==================*/ diff --git a/src/misc/lv_types.h b/src/misc/lv_types.h index 88656c73b6..3ed62534b1 100644 --- a/src/misc/lv_types.h +++ b/src/misc/lv_types.h @@ -41,6 +41,16 @@ extern "C" { #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 **********************/ @@ -81,6 +91,12 @@ typedef float lv_value_precise_t; typedef int32_t lv_value_precise_t; #endif +#if LV_USE_3DTEXTURE +#if LV_USE_OPENGLES +typedef unsigned int lv_3dtexture_id_t; +#endif +#endif + /** * Typedefs from various lvgl modules. * 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_3dtexture_t lv_3dtexture_t; + typedef struct _lv_observer_t lv_observer_t; typedef struct _lv_monkey_config_t lv_monkey_config_t; diff --git a/src/widgets/3dtexture/lv_3dtexture.c b/src/widgets/3dtexture/lv_3dtexture.c new file mode 100644 index 0000000000..8db3f4e4da --- /dev/null +++ b/src/widgets/3dtexture/lv_3dtexture.c @@ -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*/ diff --git a/src/widgets/3dtexture/lv_3dtexture.h b/src/widgets/3dtexture/lv_3dtexture.h new file mode 100644 index 0000000000..87f1588874 --- /dev/null +++ b/src/widgets/3dtexture/lv_3dtexture.h @@ -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*/ diff --git a/src/widgets/3dtexture/lv_3dtexture_private.h b/src/widgets/3dtexture/lv_3dtexture_private.h new file mode 100644 index 0000000000..0a7b770f58 --- /dev/null +++ b/src/widgets/3dtexture/lv_3dtexture_private.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*/