docs(disp): add rotation examples (#7314)
Co-authored-by: Neo Xu <neo.xu1990@gmail.com> Co-authored-by: Liam <30486941+liamHowatt@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
5272788bfb
commit
bee756ee0f
@@ -17,7 +17,7 @@ following for each display panel you want LVGL to use:
|
||||
- assign its :ref:`draw_buffers`.
|
||||
|
||||
|
||||
.. _multiple_dislays:
|
||||
.. _multiple_displays:
|
||||
|
||||
How Many Displays Can LVGL Use?
|
||||
*******************************
|
||||
@@ -56,7 +56,7 @@ it is representing, as well as other things relevant to its lifetime:
|
||||
modified with :cpp:expr:`lv_display_set_dpi(disp, new_dpi)`).
|
||||
- 4 :ref:`screen_layers` automatically created with each display
|
||||
- All :ref:`screens` created in association with this display (and not yet deleted---only
|
||||
one is dislayed at any given time)
|
||||
one is displayed at any given time)
|
||||
- The :ref:`draw_buffers` assigned to it
|
||||
- The :ref:`flush_callback` function that moves pixels from :ref:`draw_buffers` to Display hardware
|
||||
- What areas of the display have been updated (made "dirty") so rendering logic can
|
||||
@@ -157,9 +157,9 @@ If you added ``user_data`` to the Display, you can retrieve it in an event like
|
||||
|
||||
.. code-block:: c
|
||||
|
||||
lv_dislay_t *display1;
|
||||
lv_display_t *display1;
|
||||
my_type_t *my_user_data;
|
||||
display1 = (lv_dislay_t *)lv_event_get_current_target(e);
|
||||
display1 = (lv_display_t *)lv_event_get_current_target(e);
|
||||
my_user_data = lv_display_get_user_data(display1);
|
||||
|
||||
The following events are sent:
|
||||
@@ -199,7 +199,7 @@ To create a display for LVGL:
|
||||
|
||||
lv_display_t * display1 = lv_display_create(hor_res, ver_res)
|
||||
|
||||
You can create :ref:`multiple dislays <multiple_dislays>` with a different driver for
|
||||
You can create :ref:`multiple displays <multiple_displays>` with a different driver for
|
||||
each (see below).
|
||||
|
||||
When an ``lv_display_t`` object is created, with it are created 4 Screens set up
|
||||
@@ -217,7 +217,7 @@ Display remains the first one created.
|
||||
|
||||
To set another :ref:`display` as the Default Display, call :cpp:func:`lv_display_set_default`.
|
||||
|
||||
See :ref:`multiple_dislays` for more information about using multiple displays.
|
||||
See :ref:`multiple_displays` for more information about using multiple displays.
|
||||
|
||||
For many ``lv_display_...()`` functions, passing NULL for the ``disp`` argument will
|
||||
cause the function to target the Default Display. Check the API documentation for
|
||||
@@ -381,16 +381,17 @@ If a Flush-Wait Callback is not set, LVGL assumes that
|
||||
Rotation
|
||||
--------
|
||||
|
||||
LVGL supports rotation of the display in 90 degree increments. You can
|
||||
select whether you would like software rotation or hardware rotation.
|
||||
LVGL supports rotation of the display in 90 degree increments.
|
||||
|
||||
|
||||
The orientation of the display can be changed with
|
||||
``lv_display_set_rotation(disp, LV_DISPLAY_ROTATION_0/90/180/270)``.
|
||||
LVGL will swap the horizontal and vertical resolutions internally
|
||||
according to the set degree. When changing the rotation
|
||||
:cpp:enumerator:`LV_EVENT_SIZE_CHANGED` event is emitted (for any part of your system
|
||||
that has "subscribed" to this event) to allow reconfiguring of the hardware.
|
||||
In lack of hardware display rotation support
|
||||
according to the set degree, however will not perform the actual rotation.
|
||||
|
||||
When changing the rotation :cpp:enumerator:`LV_EVENT_SIZE_CHANGED` event is
|
||||
emitted (for any part of your system that has "subscribed" to this event) to
|
||||
allow reconfiguring of the hardware. In lack of hardware display rotation support
|
||||
:cpp:func:`lv_draw_sw_rotate` can be used to rotate the buffer in the
|
||||
:ref:`flush_callback`.
|
||||
|
||||
@@ -405,6 +406,72 @@ The same is true for :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_FULL`.
|
||||
In the case of :cpp:enumerator:`LV_DISPLAY_RENDER_MODE_PARTIAL` the small rendered areas
|
||||
can be rotated on their own before flushing to the frame buffer.
|
||||
|
||||
Below is an example for rotating when the rendering mode is
|
||||
:cpp:enumerator:`LV_DISPLAY_RENDER_MODE_PARTIAL` and the rotated image should be sent to a
|
||||
**display controller**.
|
||||
|
||||
.. code-block:: c
|
||||
/*Rotate a partially rendered area to another buffer and send it*/
|
||||
void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
|
||||
{
|
||||
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
|
||||
lv_area_t rotated_area;
|
||||
if(rotation != LV_DISPLAY_ROTATION_0) {
|
||||
lv_color_format_t cf = lv_display_get_color_format(disp);
|
||||
/*Calculate the position of the rotated area*/
|
||||
rotated_area = *area;
|
||||
lv_display_rotate_area(disp, &rotated_area);
|
||||
/*Calculate the source stride (bytes in a line) from the width of the area*/
|
||||
uint32_t src_stride = lv_draw_buf_width_to_stride(lv_area_get_width(area), cf);
|
||||
/*Calculate the stride of the destination (rotated) area too*/
|
||||
uint32_t dest_stride = lv_draw_buf_width_to_stride(lv_area_get_width(&rotated_area), cf);
|
||||
/*Have a buffer to store the rotated area and perform the rotation*/
|
||||
static uint8_t rotated_buf[500*1014];
|
||||
int32_t src_w = lv_area_get_width(area);
|
||||
int32_t src_h = lv_area_get_height(area);
|
||||
lv_draw_sw_rotate(px_map, rotated_buf, src_w, src_h, src_stride, dest_stride, rotation, cf);
|
||||
/*Use the rotated area and rotated buffer from now on*/
|
||||
area = &rotated_area;
|
||||
px_map = rotated_buf;
|
||||
}
|
||||
my_set_window(area->x1, area->y1, area->x2, area->y2);
|
||||
my_send_colors(px_map);
|
||||
}
|
||||
|
||||
Below is an example for rotating when the rendering mode is
|
||||
:cpp:enumerator:`LV_DISPLAY_RENDER_MODE_PARTIAL` and the image can be rotated directly
|
||||
into a **frame buffer of the LCD peripheral**.
|
||||
|
||||
.. code-block:: c
|
||||
/*Rotate a partially rendered area to the frame buffer*/
|
||||
void flush_cb(lv_display_t * disp, const lv_area_t * area, uint8_t * px_map)
|
||||
{
|
||||
lv_color_format_t cf = lv_display_get_color_format(disp);
|
||||
uint32_t px_size = lv_color_format_get_size(cf);
|
||||
/*Calculate the position of the rotated area*/
|
||||
lv_area_t rotated_area = *area;
|
||||
lv_display_rotate_area(disp, &rotated_area);
|
||||
/*Calculate the properties of the source buffer*/
|
||||
int32_t src_w = lv_area_get_width(area);
|
||||
int32_t src_h = lv_area_get_height(area);
|
||||
uint32_t src_stride = lv_draw_buf_width_to_stride(src_w, cf);
|
||||
/*Calculate the properties of the frame buffer*/
|
||||
int32_t fb_stride = lv_draw_buf_width_to_stride(disp->hor_res, cf);
|
||||
uint8_t * fb_start = my_fb_address;
|
||||
fb_start += rotated_area.y1 * fb_stride + rotated_area.x1 * px_size;
|
||||
lv_display_rotation_t rotation = lv_display_get_rotation(disp);
|
||||
if(rotation == LV_DISPLAY_ROTATION_0) {
|
||||
int32_t y;
|
||||
for(y = area->y1; y <= area->y2; y++) {
|
||||
lv_memcpy(fb_start, px_map, src_stride);
|
||||
px_map += src_stride;
|
||||
fb_start += fb_stride;
|
||||
}
|
||||
}
|
||||
else {
|
||||
lv_draw_sw_rotate(px_map, fb_start, src_w, src_h, src_stride, fb_stride, rotation, cf);
|
||||
}
|
||||
}
|
||||
|
||||
Color Format
|
||||
------------
|
||||
@@ -674,16 +741,11 @@ You can manually trigger an activity using
|
||||
:cpp:expr:`lv_display_trigger_activity(display1)`. If ``display1`` is ``NULL``, the
|
||||
:ref:`default_display` will be used (**not all displays**).
|
||||
|
||||
|
||||
|
||||
|
||||
.. admonition:: Further Reading
|
||||
|
||||
- `lv_port_disp_template.c <https://github.com/lvgl/lvgl/blob/master/examples/porting/lv_port_disp_template.c>`__
|
||||
for a template for your own driver.
|
||||
- :ref:`Drawing <draw>` to learn more about how rendering works in LVGL.
|
||||
|
||||
|
||||
|
||||
API
|
||||
***
|
||||
|
||||
Reference in New Issue
Block a user