Skip to content
GitLab
Menu
Projects
Groups
Snippets
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
card10
firmware
Commits
17f6478a
Commit
17f6478a
authored
Feb 14, 2021
by
schneider
Browse files
change(blit): Allow to blit images with alpha channel
parent
2acbd18c
Pipeline
#5154
passed with stages
in 57 seconds
Changes
14
Pipelines
1
Hide whitespace changes
Inline
Side-by-side
bootloader/bootloader-display.c
View file @
17f6478a
...
...
@@ -8,13 +8,12 @@
static
void
bootloader_display_splash
(
void
)
{
gfx_copy_region
(
gfx_copy_region
_rle_mono
(
&
display_screen
,
0
,
0
,
160
,
80
,
GFX_RLE_MONO
,
sizeof
(
splash
),
(
const
void
*
)(
splash
)
);
...
...
epicardium/epicardium.h
View file @
17f6478a
...
...
@@ -1652,6 +1652,16 @@ enum disp_font_name {
DISP_FONT24
=
4
,
};
/*
* Image data type
*/
enum
epic_rgb_format
{
EPIC_RGB8
=
0
,
EPIC_RGBA8
=
1
,
EPIC_RGB565
=
2
,
EPIC_RGBA5551
=
3
,
};
/**
* Prints a string into the display framebuffer with font type selectable
*
...
...
@@ -1699,22 +1709,22 @@ API(API_DISP_PIXEL, int epic_disp_pixel(
));
/**
* Blit an image buffer to display
* Blit
s
an image buffer to
the
display
*
* :param x: x position
* :param y: y position
* :param w:
i
mage width
* :param h:
i
mage height
* :param img:
i
mage data
(rgb565)
* :param
alpha: 8 bit alpha channel. Currently unused
.
* :param w:
I
mage width
* :param h:
I
mage height
* :param img:
I
mage data
* :param
format: Format of the image data. One of :c:type:`epic_rgb_format`
.
*/
API
(
API_DISP_BLIT
,
int
epic_disp_blit
(
int16_t
x
,
int16_t
y
,
int16_t
w
,
int16_t
h
,
uint16_t
*
img
,
uint8_t
*
alpha
void
*
img
,
enum
epic_rgb_format
format
));
/**
...
...
epicardium/main.c
View file @
17f6478a
...
...
@@ -48,14 +48,7 @@ int main(void)
epic_disp_clear
(
0x0000
);
gfx_copy_region
(
&
display_screen
,
0
,
0
,
160
,
80
,
GFX_RAW
,
sizeof
(
version_splash
),
version_splash
&
display_screen
,
0
,
0
,
160
,
80
,
GFX_RGB565
,
version_splash
);
if
(
strcmp
(
CARD10_VERSION
,
"v1.16"
)
!=
0
)
{
...
...
epicardium/modules/display.c
View file @
17f6478a
...
...
@@ -92,61 +92,81 @@ int epic_disp_blit(
int16_t
pos_y
,
int16_t
width
,
int16_t
height
,
uint16_t
*
img
,
uint8_t
*
alpha
void
*
img
,
enum
epic_rgb_format
format
)
{
/* TODO: alpha is not supported yet */
int
cl
=
check_lock
();
if
(
cl
<
0
)
{
return
cl
;
}
else
{
int16_t
offset_x
=
(
pos_x
<
0
)
?
-
pos_x
:
0
;
int16_t
count_x
=
width
-
offset_x
;
int16_t
offset_y
=
(
pos_y
<
0
)
?
-
pos_y
:
0
;
int16_t
count_y
=
height
-
offset_y
;
}
if
(
pos_x
+
width
>=
160
)
{
count_x
-=
(
pos_x
+
width
)
%
160
;
}
if
(
pos_y
+
height
>=
80
)
{
count_y
-=
(
pos_y
+
height
)
%
80
;
}
int16_t
offset_x
=
(
pos_x
<
0
)
?
-
pos_x
:
0
;
int16_t
count_x
=
width
-
offset_x
;
int16_t
offset_y
=
(
pos_y
<
0
)
?
-
pos_y
:
0
;
int16_t
count_y
=
height
-
offset_y
;
if
(
pos_x
+
width
>=
160
)
{
count_x
-=
(
pos_x
+
width
)
%
160
;
}
if
(
pos_y
+
height
>=
80
)
{
count_y
-=
(
pos_y
+
height
)
%
80
;
}
size_t
bpp
;
enum
gfx_encoding
encoding
;
switch
(
format
)
{
case
EPIC_RGB565
:
bpp
=
2
;
encoding
=
GFX_RGB565
;
break
;
case
EPIC_RGBA5551
:
bpp
=
2
;
encoding
=
GFX_RGBA5551
;
break
;
case
EPIC_RGB8
:
bpp
=
3
;
encoding
=
GFX_RGB8
;
break
;
case
EPIC_RGBA8
:
bpp
=
4
;
encoding
=
GFX_RGBA8
;
break
;
default:
return
-
1
;
break
;
}
if
(
offset_x
==
0
&&
offset_y
==
0
&&
count_x
==
width
&&
count_y
==
height
)
{
/* Simply copy full image, no cropping or alpha blending */
if
(
offset_x
==
0
&&
offset_y
==
0
&&
count_x
==
width
&&
count_y
==
height
)
{
/* Copy full image. No cropping.*/
gfx_copy_region
(
&
display_screen
,
pos_x
,
pos_y
,
width
,
height
,
encoding
,
img
);
}
else
{
/* Copy cropped image line by line. */
int16_t
curr_y
;
for
(
curr_y
=
offset_y
;
curr_y
<
offset_y
+
count_y
;
curr_y
++
)
{
uint8_t
*
line
=
img
+
(
curr_y
*
width
+
offset_x
)
*
bpp
;
gfx_copy_region
(
&
display_screen
,
pos_x
,
pos_y
,
width
,
height
,
GFX_RAW
,
width
*
height
*
2
,
img
pos_x
+
offset_x
,
pos_y
+
curr_y
,
count_x
,
1
,
encoding
,
line
);
}
else
{
/* Copy cropped image line by line */
for
(
int16_t
curr_y
=
offset_y
;
curr_y
<
offset_y
+
count_y
;
curr_y
++
)
{
uint16_t
*
curr_img
=
img
+
(
curr_y
*
width
+
offset_x
);
gfx_copy_region
(
&
display_screen
,
pos_x
+
offset_x
,
pos_y
+
curr_y
,
count_x
,
1
,
GFX_RAW
,
count_x
*
2
,
curr_img
);
}
}
return
0
;
}
return
0
;
}
int
epic_disp_line
(
...
...
epicardium/modules/panic.c
View file @
17f6478a
...
...
@@ -120,13 +120,12 @@ static void faultsplash(const char *msg)
{
LCD_SetBacklight
(
100
);
gfx_copy_region
(
gfx_copy_region
_rle_mono
(
&
display_screen
,
0
,
0
,
160
,
80
,
GFX_RLE_MONO
,
sizeof
(
faultsplash_rle
),
faultsplash_rle
);
...
...
hw-tests/dual-core/main.c
View file @
17f6478a
...
...
@@ -28,8 +28,7 @@ int main(void)
0
,
160
,
80
,
GFX_RAW
,
sizeof
(
Heart
),
GFX_RGB565
,
(
const
void
*
)(
Heart
)
);
gfx_update
(
&
display_screen
);
...
...
hw-tests/hello-world/main.c
View file @
17f6478a
...
...
@@ -36,8 +36,7 @@ int main(void)
0
,
160
,
80
,
GFX_RAW
,
sizeof
(
Heart
),
GFX_RGB565
,
(
const
void
*
)(
Heart
)
);
gfx_update
(
&
display_screen
);
...
...
hw-tests/ips/main.c
View file @
17f6478a
...
...
@@ -43,8 +43,7 @@ int main(void)
0
,
40
,
40
,
GFX_RAW
,
40
*
40
*
2
,
GFX_RGB565
,
(
const
void
*
)(
gImage_40X40
)
);
gfx_copy_region
(
...
...
@@ -53,8 +52,7 @@ int main(void)
0
,
160
,
80
,
GFX_RAW
,
160
*
80
*
2
,
GFX_RGB565
,
(
const
void
*
)(
gImage_160X80
)
);
gfx_update
(
&
display_screen
);
...
...
lib/gfx/framebuffer.c
View file @
17f6478a
...
...
@@ -99,3 +99,21 @@ void fb_setpixel(struct framebuffer *fb, int x, int y, Color c)
pixel
[
0
]
=
color
[
1
];
}
}
Color
fb_getpixel
(
struct
framebuffer
*
fb
,
int
x
,
int
y
)
{
uint8_t
*
pixel
=
fb_pixel
(
fb
,
x
,
y
);
if
(
pixel
==
NULL
)
return
0
;
Color
c
;
uint8_t
*
color
=
(
uint8_t
*
)(
&
c
);
const
size_t
bpp
=
fb_bytes_per_pixel
(
fb
);
switch
(
bpp
)
{
default:
case
2
:
color
[
0
]
=
pixel
[
1
];
color
[
1
]
=
pixel
[
0
];
}
return
c
;
}
lib/gfx/framebuffer.h
View file @
17f6478a
...
...
@@ -27,6 +27,7 @@ struct framebuffer {
size_t
fb_bytes_per_pixel
(
const
struct
framebuffer
*
fb
);
void
*
fb_pixel
(
struct
framebuffer
*
fb
,
int
x
,
int
y
);
void
fb_setpixel
(
struct
framebuffer
*
fb
,
int
x
,
int
y
,
Color
c
);
Color
fb_getpixel
(
struct
framebuffer
*
fb
,
int
x
,
int
y
);
void
fb_clear_to_color
(
struct
framebuffer
*
fb
,
Color
c
);
void
fb_clear
(
struct
framebuffer
*
fb
);
Color
fb_encode_color_rgb
(
struct
framebuffer
*
fb
,
int
r
,
int
g
,
int
b
);
...
...
lib/gfx/gfx.c
View file @
17f6478a
...
...
@@ -13,6 +13,42 @@ const struct gfx_color_rgb gfx_colors_rgb[COLORS] = {
{
255
,
255
,
0
}
/* YELLOW */
};
static
inline
uint16_t
rgb8_to_rgb565
(
const
uint8_t
*
bytes
)
{
return
((
bytes
[
0
]
&
0
b11111000
)
<<
8
)
|
((
bytes
[
1
]
&
0
b11111100
)
<<
3
)
|
(
bytes
[
2
]
>>
3
);
}
static
inline
void
rgb565_to_rgb8
(
uint16_t
c
,
uint8_t
*
bytes
)
{
bytes
[
0
]
=
(
c
&
0
b1111100000000000
)
>>
8
;
bytes
[
1
]
=
(
c
&
0
b0000011111100000
)
>>
3
;
bytes
[
2
]
=
(
c
&
0
b0000000000011111
)
<<
3
;
}
static
inline
uint16_t
rgba5551_to_rgb565
(
const
uint8_t
*
bytes
)
{
return
(
bytes
[
1
]
<<
8
)
|
(
bytes
[
0
]
&
0
b11000000
)
|
((
bytes
[
0
]
&
0
b00111110
)
>>
1
);
}
static
inline
uint8_t
apply_alpha
(
uint8_t
in
,
uint8_t
bg
,
uint8_t
alpha
)
{
/* Not sure if it is worth (or even a good idea) to have
* the special cases here. */
if
(
bg
==
0
)
{
return
(
in
*
alpha
)
/
255
;
}
uint8_t
beta
=
255
-
alpha
;
if
(
bg
==
255
)
{
return
((
in
*
alpha
)
/
255
)
+
beta
;
}
return
(
in
*
alpha
+
bg
*
beta
)
/
255
;
}
void
gfx_setpixel
(
struct
gfx_region
*
r
,
int
x
,
int
y
,
Color
c
)
{
if
(
x
<
0
||
y
<
0
)
...
...
@@ -23,6 +59,25 @@ void gfx_setpixel(struct gfx_region *r, int x, int y, Color c)
fb_setpixel
(
r
->
fb
,
r
->
x
+
x
,
r
->
y
+
y
,
c
);
}
void
gfx_setpixel_rgba
(
struct
gfx_region
*
r
,
int
x
,
int
y
,
const
uint8_t
*
c
)
{
if
(
x
<
0
||
y
<
0
)
return
;
if
((
size_t
)
x
>=
r
->
width
||
(
size_t
)
y
>=
r
->
height
)
return
;
uint8_t
pixel
[
3
];
Color
p
=
fb_getpixel
(
r
->
fb
,
r
->
x
+
x
,
r
->
y
+
y
);
rgb565_to_rgb8
(
p
,
pixel
);
uint8_t
alpha
=
c
[
3
];
pixel
[
0
]
=
apply_alpha
(
c
[
0
],
pixel
[
0
],
alpha
);
pixel
[
1
]
=
apply_alpha
(
c
[
1
],
pixel
[
1
],
alpha
);
pixel
[
2
]
=
apply_alpha
(
c
[
2
],
pixel
[
2
],
alpha
);
fb_setpixel
(
r
->
fb
,
r
->
x
+
x
,
r
->
y
+
y
,
rgb8_to_rgb565
(
pixel
));
}
struct
gfx_region
gfx_screen
(
struct
framebuffer
*
fb
)
{
struct
gfx_region
r
=
{
.
fb
=
fb
,
...
...
@@ -270,61 +325,48 @@ Color gfx_color(struct gfx_region *reg, enum gfx_color color)
return
gfx_color_rgb
(
reg
,
c
->
r
,
c
->
g
,
c
->
b
);
}
static
void
gfx_copy_region
_raw
(
void
gfx_copy_region
(
struct
gfx_region
*
reg
,
int
x
,
int
y
,
int
w
,
int
h
,
size_t
size
,
const
void
*
p
enum
gfx_encoding
encoding
,
const
uint8_t
*
p
)
{
size_t
bpp
=
size
/
(
w
*
h
);
for
(
int
y_
=
0
;
y_
<
h
;
y_
++
)
{
for
(
int
x_
=
0
;
x_
<
w
;
x_
++
)
{
Color
c
;
uint8_t
alpha
;
switch
(
bpp
)
{
default
:
case
2
:
switch
(
encoding
)
{
case
GFX_RGB565
:
/* Assuming alignment here */
c
=
*
(
const
uint16_t
*
)(
p
);
gfx_setpixel
(
reg
,
x
+
x_
,
y
+
y_
,
c
);
p
+=
2
;
break
;
case
GFX_RGB8
:
c
=
rgb8_to_rgb565
(
p
);
gfx_setpixel
(
reg
,
x
+
x_
,
y
+
y_
,
c
);
p
+=
3
;
break
;
case
GFX_RGBA5551
:
c
=
rgba5551_to_rgb565
(
p
);
alpha
=
(
*
p
)
&
1
;
if
(
alpha
)
{
gfx_setpixel
(
reg
,
x
+
x_
,
y
+
y_
,
c
);
}
p
+=
2
;
break
;
case
GFX_RGBA8
:
gfx_setpixel_rgba
(
reg
,
x
+
x_
,
y
+
y_
,
p
);
p
+=
4
;
break
;
default:
return
;
break
;
}
gfx_setpixel
(
reg
,
x
+
x_
,
y
+
y_
,
c
);
p
+=
bpp
;
}
}
}
static
void
gfx_copy_region_mono
(
struct
gfx_region
*
reg
,
int
x
,
int
y
,
int
w
,
int
h
,
size_t
size
,
const
void
*
p
)
{
const
char
*
bp
=
p
;
int
bit
=
0
;
Color
white
=
gfx_color
(
reg
,
WHITE
);
Color
black
=
gfx_color
(
reg
,
BLACK
);
for
(
int
y_
=
0
;
y_
<
h
;
y_
++
)
{
for
(
int
x_
=
0
;
x_
<
w
;
x_
++
)
{
int
value
=
*
bp
&
(
1
<<
bit
);
if
(
++
bit
>=
8
)
{
bp
++
;
bit
%=
8
;
if
((
const
void
*
)(
bp
)
>=
(
p
+
size
))
return
;
}
Color
c
=
value
?
white
:
black
;
gfx_setpixel
(
reg
,
x
+
x_
,
y
+
y_
,
c
);
}
}
}
...
...
@@ -336,7 +378,7 @@ static void gfx_copy_region_mono(
* significant bit determines the color, the remaining 7 bits determine the
* amount.
*/
static
void
gfx_copy_region_rle_mono
(
void
gfx_copy_region_rle_mono
(
struct
gfx_region
*
reg
,
int
x
,
int
y
,
...
...
@@ -363,31 +405,6 @@ static void gfx_copy_region_rle_mono(
}
}
void
gfx_copy_region
(
struct
gfx_region
*
reg
,
int
x
,
int
y
,
int
w
,
int
h
,
enum
gfx_encoding
encoding
,
size_t
size
,
const
void
*
p
)
{
switch
(
encoding
)
{
case
GFX_RAW
:
gfx_copy_region_raw
(
reg
,
x
,
y
,
w
,
h
,
size
,
p
);
break
;
case
GFX_MONO
:
gfx_copy_region_mono
(
reg
,
x
,
y
,
w
,
h
,
size
,
p
);
break
;
case
GFX_RLE_MONO
:
gfx_copy_region_rle_mono
(
reg
,
x
,
y
,
w
,
h
,
size
,
p
);
break
;
default:
break
;
}
}
void
gfx_copy_raw
(
struct
gfx_region
*
reg
,
const
void
*
p
,
size_t
size
)
{
fb_copy_raw
(
reg
->
fb
,
p
,
size
);
...
...
lib/gfx/gfx.h
View file @
17f6478a
...
...
@@ -44,9 +44,12 @@ enum gfx_color {
};
enum
gfx_encoding
{
GFX_R
AW
,
GFX_R
GB565
,
GFX_MONO
,
GFX_RLE_MONO
GFX_RLE_MONO
,
GFX_RGB8
,
GFX_RGBA8
,
GFX_RGBA5551
};
struct
gfx_color_rgb
{
...
...
@@ -57,9 +60,10 @@ struct gfx_color_rgb {
Color
gfx_color
(
struct
gfx_region
*
reg
,
enum
gfx_color
color
);
void
gfx_copy_region
(
struct
gfx_region
*
reg
,
int
x
,
int
y
,
int
w
,
int
h
,
enum
gfx_encoding
encoding
,
size_t
size
,
const
void
*
p
);
void
gfx_copy_region_rle_mono
(
struct
gfx_region
*
reg
,
int
x
,
int
y
,
int
w
,
int
h
,
size_t
size
,
const
void
*
p
);
void
gfx_copy_region
(
struct
gfx_region
*
reg
,
int
x
,
int
y
,
int
w
,
int
h
,
enum
gfx_encoding
encoding
,
const
uint8_t
*
p
);
void
gfx_copy_raw
(
struct
gfx_region
*
reg
,
const
void
*
p
,
size_t
size
);
#endif
pycardium/modules/py/display.py
View file @
17f6478a
...
...
@@ -8,6 +8,11 @@ FONT16 = 2
FONT20
=
3
FONT24
=
4
RGB8
=
0
RGBA8
=
1
RGB565
=
2
RGBA5551
=
3
class
Display
:
"""
...
...
@@ -120,7 +125,7 @@ class Display:
sys_display
.
pixel
(
x
,
y
,
col
)
return
self
def
blit
(
self
,
x
,
y
,
w
,
h
,
img
,
rgb565
=
False
,
alpha
=
None
):
def
blit
(
self
,
x
,
y
,
w
,
h
,
img
,
format
=
RGB8
):
"""
Draws an image on the display.
...
...
@@ -128,16 +133,20 @@ class Display:
:param y: Y coordinate
:param w: Image width
:param h: Image height
:param img: Buffer with pixel data. Default format is RGB with 8 bits per channel.
:param alpha: Alpha mask for `img`
:param rgb565: Set to `True` if the data supplied is in rgb565 format instead of 8 bit RGB.
:param img: Buffer with pixel data
:param format: Format of the RGB data. One of ``display.RGB8``, ``
- ``display.RGB8``: 24 bit RGB.
- ``display.RGBA8``: 24 bit RGB + 8 bit alpha.
- ``display.RGB565``: 16 bit RGB. This consumes 1 byte less RAM per pixel than ``display.RGB8``.
- ``display.RGBA5551``: 15 bit RGB + 1 bit alpha.
Default is ``display.RGB8``.
.. note::
Alpha mask support is not yet implemented.
.. versionadded:: 1.17
**Example with RGB data:**
**Example with RGB
8
data:**
.. code-block:: python
...
...
@@ -153,7 +162,7 @@ class Display:
d.update()
**Example with
rgb
565 data:**
**Example with
RGB
565 data:**
.. code-block:: python
...
...
@@ -165,7 +174,7 @@ class Display:
img = array.array('H', [0x07E0 for x in range(32 * 20)])
with display.open() as d:
d.clear()
d.blit(10, 10, 32, 20, img,
rgb565=True
)
d.blit(10, 10, 32, 20, img,
format=display.RGB565
)
d.update()
...
...
@@ -180,20 +189,13 @@ class Display:
f = framebuf.FrameBuffer(bytearray(160 * 80 * 2), 160, 80, framebuf.RGB565)
with display.open() as d:
f.text("Hello World", 0, 0, 0xF800) # red
d.blit(0, 0, 160, 80, f,
rgb565=True
)
d.blit(0, 0, 160, 80, f,
format=display.RGB565
)
d.update()
"""
# TODO: alpha is not yet supported by epicardium
if
alpha
is
not
None
:
raise
ValueError
(
"alpha not yet supported"
)
if
alpha
is
None
:
sys_display
.
blit
(
x
,
y
,
w
,
h
,
img
,
rgb565
)
else
:
sys_display
.
blit
(
x
,
y
,
w
,
h
,
img
,
rgb565
,
alpha
)
sys_display
.
blit
(
x
,
y
,
w
,
h
,
img
,
format
)
return
self
...
...
pycardium/modules/sys_display.c
View file @
17f6478a
...
...
@@ -97,14 +97,11 @@ static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(
/* blit image to display */
static
mp_obj_t
mp_display_blit
(
size_t
n_args
,
const
mp_obj_t
*
args
)
{
/* Required arguments: posx, posy (on display),
width, height (of image),
buffer (rgb data of image) */
int
pos_x
=
mp_obj_get_int
(
args
[
0
]);
int
pos_y
=
mp_obj_get_int
(
args
[
1
]);
int
width