Merge a4fd40fb1d
into c635b945e1
commit
c1c05af1f9
@ -0,0 +1,120 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GL_BITBLT_H
|
||||
#define GL_BITBLT_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "gl_color.h"
|
||||
|
||||
// These module provides low-level bit block transfer (bitblt)
|
||||
// operations on different bitmap/framebuffer types.
|
||||
//
|
||||
// `fill` - fills a rectangle with a solid color (with an optional
|
||||
// alpha, allowing color blending).
|
||||
//
|
||||
// `copy` - copies a bitmap or part of it to the destination bitmap.
|
||||
//
|
||||
// `blend` - blends a bitmap with a 1- or 4-bit alpha channel to the
|
||||
// destination using background and foreground colors.
|
||||
//
|
||||
// These operations might be accelerated using DMA2D (ChromART accelerator)
|
||||
// on the STM32 platform.
|
||||
|
||||
// Represents a set of parameters for a bit block transfer operation.
|
||||
typedef struct {
|
||||
// Pointer to the destination bitmap's first row
|
||||
void* dst_row;
|
||||
// Number of bytes per line in the destination bitmap
|
||||
uint16_t dst_stride;
|
||||
// X-coordinate of the top-left corner inside the destination
|
||||
uint16_t dst_x;
|
||||
// Y-coordinate of the top-left corner inside the destination
|
||||
uint16_t dst_y;
|
||||
// Height of the filled/copied/blended area
|
||||
uint16_t height;
|
||||
// Width of the filled/copied/blended area
|
||||
uint16_t width;
|
||||
|
||||
// Pointer to the source bitmap's first row
|
||||
// (unused for fill operations)
|
||||
void* src_row;
|
||||
// Number of bytes per line in the source bitmap
|
||||
// (unused for fill operations)
|
||||
uint16_t src_stride;
|
||||
// X-coordinate of the origin in the source bitmap
|
||||
// (unused for fill operations)
|
||||
uint16_t src_x;
|
||||
// Y-coordinate of the origin in the source bitmap
|
||||
// (unused for fill operations)
|
||||
uint16_t src_y;
|
||||
|
||||
// Foreground color used when copying/blending/filling
|
||||
gl_color_t src_fg;
|
||||
// Background color used when copying mono bitmaps
|
||||
gl_color_t src_bg;
|
||||
// Alpha value for fill operation (255 => normal fill, 0 => noop)
|
||||
uint8_t src_alpha;
|
||||
|
||||
} gl_bitblt_t;
|
||||
|
||||
// Functions for RGB565 bitmap/framebuffer
|
||||
|
||||
// Fills a rectangle with a solid color
|
||||
void gl_rgb565_fill(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 1-bit alpha channel)
|
||||
void gl_rgb565_copy_mono1p(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 4-bit alpha channel)
|
||||
void gl_rgb565_copy_mono4(const gl_bitblt_t* bb);
|
||||
// Copies an RGB565 bitmap
|
||||
void gl_rgb565_copy_rgb565(const gl_bitblt_t* bb);
|
||||
// Blends a mono bitmap (with 4-bit alpha channel)
|
||||
// with the destination bitmap
|
||||
void gl_rgb565_blend_mono4(const gl_bitblt_t* bb);
|
||||
|
||||
// Functions for RGBA8888 bitmap/framebuffer
|
||||
void gl_rgba8888_fill(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 1-bit alpha channel)
|
||||
void gl_rgba8888_copy_mono1p(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 4-bit alpha channel)
|
||||
void gl_rgba8888_copy_mono4(const gl_bitblt_t* bb);
|
||||
// Copies an RGB565 bitmap
|
||||
void gl_rgba8888_copy_rgb565(const gl_bitblt_t* bb);
|
||||
// Copies an RGBA8888 bitmap
|
||||
void gl_rgba8888_copy_rgba8888(const gl_bitblt_t* bb);
|
||||
// Blends a mono bitmap (with 4-bit alpha channel)
|
||||
// with the destination bitmap
|
||||
void gl_rgba8888_blend_mono4(const gl_bitblt_t* bb);
|
||||
|
||||
// Functions for Mono8 bitmap/framebuffer
|
||||
void gl_mono8_fill(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 1-bit alpha channel)
|
||||
void gl_mono8_copy_mono1p(const gl_bitblt_t* bb);
|
||||
// Copies a mono bitmap (with 4-bit alpha channel)
|
||||
void gl_mono8_copy_mono4(const gl_bitblt_t* bb);
|
||||
// Blends a mono bitmap (with 1-bit alpha channel)
|
||||
// with the destination bitmap
|
||||
void gl_mono8_blend_mono1p(const gl_bitblt_t* bb);
|
||||
// Blends a mono bitmap (with 4-bit alpha channel)
|
||||
// with the destination bitmap
|
||||
void gl_mono8_blend_mono4(const gl_bitblt_t* bb);
|
||||
|
||||
#endif // GL_BITBLT_H
|
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gl_bitblt.h"
|
||||
|
||||
void gl_mono8_fill(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = fg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void gl_mono8_copy_mono1p(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src = (uint8_t*)bb->src_row;
|
||||
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
uint8_t bg = gl_color_lum(bb->src_bg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
|
||||
uint8_t data = src[(src_ofs + x) / 8];
|
||||
dst_ptr[x] = (data & mask) ? fg : bg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ofs += bb->src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void gl_mono8_copy_mono4(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
uint8_t bg = gl_color_lum(bb->src_bg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t src_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t src_lum = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0xF;
|
||||
dst_ptr[x] = (fg * src_lum + bg * (15 - src_lum)) / 15;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
|
||||
void gl_mono8_blend_mono1p(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src = (uint8_t*)bb->src_row;
|
||||
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
|
||||
uint8_t data = src[(src_ofs + x) / 8];
|
||||
dst_ptr[x] = (data & mask) ? fg : dst_ptr[x];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ofs += bb->src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void gl_mono8_blend_mono4(const gl_bitblt_t* bb) {
|
||||
uint8_t* dst_ptr = (uint8_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint8_t fg = gl_color_lum(bb->src_fg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t src_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t src_alpha = (x + bb->src_x) & 1 ? src_data >> 4 : src_data & 0x0F;
|
||||
dst_ptr[x] = (fg * src_alpha + dst_ptr[x] * (15 - src_alpha)) / 15;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
@ -0,0 +1,136 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gl_bitblt.h"
|
||||
|
||||
#if USE_DMA2D
|
||||
#include "dma2d_bitblt.h"
|
||||
#endif
|
||||
|
||||
void gl_rgb565_fill(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (!dma2d_rgb565_fill(bb))
|
||||
#endif
|
||||
{
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
if (bb->src_alpha == 255) {
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = bb->src_fg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
} else {
|
||||
uint8_t alpha = bb->src_alpha;
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color16_blend_a8(bb->src_fg, dst_ptr[x], alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgb565_copy_mono1p(const gl_bitblt_t* bb) {
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src = (uint8_t*)bb->src_row;
|
||||
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint16_t fg = gl_color_to_color16(bb->src_fg);
|
||||
uint16_t bg = gl_color_to_color16(bb->src_bg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
|
||||
uint8_t data = src[(src_ofs + x) / 8];
|
||||
dst_ptr[x] = (data & mask) ? fg : bg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ofs += bb->src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgb565_copy_mono4(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (!dma2d_rgb565_copy_mono4(bb))
|
||||
#endif
|
||||
{
|
||||
const gl_color16_t* gradient =
|
||||
gl_color16_gradient_a4(bb->src_fg, bb->src_bg);
|
||||
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF;
|
||||
dst_ptr[x] = gradient[fg_lum];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgb565_copy_rgb565(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (!dma2d_rgb565_copy_rgb565(bb))
|
||||
#endif
|
||||
{
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = src_ptr[x];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgb565_blend_mono4(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (!dma2d_rgb565_blend_mono4(bb))
|
||||
#endif
|
||||
{
|
||||
uint16_t* dst_ptr = (uint16_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
|
||||
dst_ptr[x] = gl_color16_blend_a4(
|
||||
bb->src_fg, gl_color16_to_color(dst_ptr[x]), fg_alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gl_bitblt.h"
|
||||
|
||||
#if USE_DMA2D
|
||||
#include "dma2d_bitblt.h"
|
||||
#endif
|
||||
|
||||
void gl_rgba8888_fill(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (!dma2d_rgba8888_fill(bb))
|
||||
#endif
|
||||
{
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
if (bb->src_alpha == 255) {
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color_to_color32(bb->src_fg);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
} else {
|
||||
uint8_t alpha = bb->src_alpha;
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color32_blend_a8(
|
||||
bb->src_fg, gl_color32_to_color(dst_ptr[x]), alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_copy_mono1p(const gl_bitblt_t* bb) {
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src = (uint8_t*)bb->src_row;
|
||||
uint16_t src_ofs = bb->src_stride * bb->src_y + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
uint32_t fg = gl_color_to_color32(bb->src_fg);
|
||||
uint32_t bg = gl_color_to_color32(bb->src_bg);
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t mask = 1 << (7 - ((src_ofs + x) & 7));
|
||||
uint8_t data = src[(src_ofs + x) / 8];
|
||||
dst_ptr[x] = (data & mask) ? fg : bg;
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ofs += bb->src_stride;
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_copy_mono4(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (!dma2d_rgba8888_copy_mono4(bb))
|
||||
#endif
|
||||
{
|
||||
const gl_color32_t* gradient =
|
||||
gl_color32_gradient_a4(bb->src_fg, bb->src_bg);
|
||||
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t fg_lum = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0xF;
|
||||
dst_ptr[x] = gradient[fg_lum];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_copy_rgb565(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (!dma2d_rgba8888_copy_rgb565(bb))
|
||||
#endif
|
||||
{
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint16_t* src_ptr = (uint16_t*)bb->src_row + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = gl_color16_to_color32(src_ptr[x]);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_copy_rgba8888(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (!dma2d_rgba8888_copy_rgba8888(bb))
|
||||
#endif
|
||||
{
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint32_t* src_ptr = (uint32_t*)bb->src_row + bb->src_x;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
dst_ptr[x] = src_ptr[x];
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_ptr += bb->src_stride / sizeof(*src_ptr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void gl_rgba8888_blend_mono4(const gl_bitblt_t* bb) {
|
||||
#if defined(USE_DMA2D) && !defined(TREZOR_EMULATOR)
|
||||
if (!dma2d_rgba8888_blend_mono4(bb))
|
||||
#endif
|
||||
{
|
||||
uint32_t* dst_ptr = (uint32_t*)bb->dst_row + bb->dst_x;
|
||||
uint8_t* src_row = (uint8_t*)bb->src_row;
|
||||
uint16_t height = bb->height;
|
||||
|
||||
while (height-- > 0) {
|
||||
for (int x = 0; x < bb->width; x++) {
|
||||
uint8_t fg_data = src_row[(x + bb->src_x) / 2];
|
||||
uint8_t fg_alpha = (x + bb->src_x) & 1 ? fg_data >> 4 : fg_data & 0x0F;
|
||||
dst_ptr[x] = gl_color32_blend_a4(
|
||||
bb->src_fg, gl_color32_to_color(dst_ptr[x]), fg_alpha);
|
||||
}
|
||||
dst_ptr += bb->dst_stride / sizeof(*dst_ptr);
|
||||
src_row += bb->src_stride / sizeof(*src_row);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,49 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "gl_color.h"
|
||||
#include "colors.h"
|
||||
|
||||
const gl_color16_t* gl_color16_gradient_a4(gl_color_t fg_color,
|
||||
gl_color_t bg_color) {
|
||||
static gl_color16_t cache[16] = {0};
|
||||
|
||||
if (gl_color_to_color16(bg_color) != cache[0] ||
|
||||
gl_color_to_color16(fg_color) != cache[15]) {
|
||||
for (int alpha = 0; alpha < 16; alpha++) {
|
||||
cache[alpha] = gl_color16_blend_a4(fg_color, bg_color, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
const gl_color32_t* gl_color32_gradient_a4(gl_color_t fg_color,
|
||||
gl_color_t bg_color) {
|
||||
static gl_color32_t cache[16] = {0};
|
||||
|
||||
if (bg_color != gl_color32_to_color(cache[0]) ||
|
||||
fg_color != gl_color32_to_color(cache[15])) {
|
||||
for (int alpha = 0; alpha < 16; alpha++) {
|
||||
cache[alpha] = gl_color32_blend_a4(fg_color, bg_color, alpha);
|
||||
}
|
||||
}
|
||||
|
||||
return cache;
|
||||
}
|
@ -0,0 +1,337 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GL_COLOR_H
|
||||
#define GL_COLOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#define GL_COLOR_16BIT
|
||||
// #define GL_COLOR_32BIT
|
||||
|
||||
// Color in RGB565 format
|
||||
//
|
||||
// |15 8 | 7 0|
|
||||
// |---------------------------------|
|
||||
// |r r r r r g g g | g g g b b b b b|
|
||||
// |---------------------------------|
|
||||
|
||||
typedef uint16_t gl_color16_t;
|
||||
|
||||
// Color in RGBA8888 format
|
||||
//
|
||||
// |31 24 |23 16 |15 8 | 7 0 |
|
||||
// |----------------------------------------------------------------------|
|
||||
// |a a a a a a a a | r r r r r r r r | g g g g g g g g | b b b b b b b b |
|
||||
// |----------------------------------------------------------------------|
|
||||
//
|
||||
|
||||
typedef uint32_t gl_color32_t;
|
||||
|
||||
#ifdef GL_COLOR_16BIT
|
||||
#define gl_color_t gl_color16_t
|
||||
#define gl_color_to_color16(c) (c)
|
||||
#define gl_color16_to_color(c) (c)
|
||||
#define gl_color_to_color32(c) (gl_color16_to_color32(c))
|
||||
#define gl_color32_to_color(c) (gl_color32_to_color16(c))
|
||||
#define gl_color_lum(c) (gl_color16_lum(c))
|
||||
#elif GL_COLOR_32BIT
|
||||
#define gl_color_t gl_color32_t
|
||||
#define gl_color_to_color16(c) (gl_color32_to_color16(c))
|
||||
#define gl_color16_to_color(c) (gl_color16_to_color32(c))
|
||||
#define gl_color_to_color32(c) (c)
|
||||
#define gl_color32_to_color(c) (c)
|
||||
#define gl_color_lum(c) (gl_color32_lum(c))
|
||||
#else
|
||||
#error "GL_COLOR_16BIT/32BIT not specified"
|
||||
#endif
|
||||
|
||||
// Extracts red component from gl_color16_t and converts it to 8-bit value
|
||||
#define gl_color16_to_r(c) ((((c)&0xF800) >> 8) | (((c)&0xF800) >> 13))
|
||||
// Extracts green component from gl_color16_t and converts it to 8-bit value
|
||||
#define gl_color16_to_g(c) ((((c)&0x07E0) >> 3) | (((c)&0x07E0) >> 9))
|
||||
// Extracts blue component from gl_color16_t and converts it to 8-bit value
|
||||
#define gl_color16_to_b(c) ((((c)&0x001F) << 3) | (((c)&0x001F) >> 2))
|
||||
|
||||
// Extracts red component from gl_color32_t
|
||||
#define gl_color32_to_r(c) (((c)&0x00FF0000) >> 16)
|
||||
// Extracts green component from gl_color32_t
|
||||
#define gl_color32_to_g(c) (((c)&0x0000FF00) >> 8)
|
||||
// Extracts blue component from gl_color32_t
|
||||
#define gl_color32_to_b(c) (((c)&0x000000FF) >> 0)
|
||||
|
||||
// 4-bit linear interpolation between `fg` and `bg`
|
||||
#define a4_lerp(fg, bg, alpha) (((fg) * (alpha) + ((bg) * (15 - (alpha)))) / 15)
|
||||
// 8-bit linear interpolation between `fg` and `bg`
|
||||
#define a8_lerp(fg, bg, alpha) \
|
||||
(((fg) * (alpha) + ((bg) * (255 - (alpha)))) / 255)
|
||||
|
||||
// Constructs a 16-bit color from the given red (r),
|
||||
// green (g), and blue (b) values in the range 0..255
|
||||
static inline gl_color16_t gl_color16_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return ((r & 0xF8U) << 8) | ((g & 0xFCU) << 3) | ((b & 0xF8U) >> 3);
|
||||
}
|
||||
|
||||
// Constructs a 32-bit color from the given red (r),
|
||||
// green (g), and blue (b) values in the range 0..255.
|
||||
// Alpha is set to 255.
|
||||
static inline gl_color32_t gl_color32_rgb(uint8_t r, uint8_t g, uint8_t b) {
|
||||
return (0xFFU << 24) | ((uint32_t)r << 16) | ((uint32_t)g << 8) | b;
|
||||
}
|
||||
|
||||
// Converts a 16-bit color to a 32-bit color; alpha is set to 255
|
||||
static inline gl_color32_t gl_color16_to_color32(gl_color16_t color) {
|
||||
uint32_t r = gl_color16_to_r(color);
|
||||
uint32_t g = gl_color16_to_g(color);
|
||||
uint32_t b = gl_color16_to_b(color);
|
||||
|
||||
return gl_color32_rgb(r, g, b);
|
||||
}
|
||||
|
||||
// Converts 32-bit color to 16-bit color, alpha is ignored
|
||||
static inline gl_color16_t gl_color32_to_color16(gl_color32_t color) {
|
||||
uint16_t r = (color & 0x00F80000) >> 8;
|
||||
uint16_t g = (color & 0x0000FC00) >> 5;
|
||||
uint16_t b = (color & 0x000000F8) >> 3;
|
||||
|
||||
return r | g | b;
|
||||
}
|
||||
|
||||
// Converts 16-bit color into luminance (ranging from 0 to 255)
|
||||
static inline uint8_t gl_color16_lum(gl_color16_t color) {
|
||||
uint32_t r = gl_color16_to_r(color);
|
||||
uint32_t g = gl_color16_to_g(color);
|
||||
uint32_t b = gl_color16_to_b(color);
|
||||
|
||||
return (r + g + b) / 3;
|
||||
}
|
||||
|
||||
// Converts 32-bit color into luminance (ranging from 0 to 255)
|
||||
static inline uint8_t gl_color32_lum(gl_color16_t color) {
|
||||
uint32_t r = gl_color32_to_r(color);
|
||||
uint32_t g = gl_color32_to_g(color);
|
||||
uint32_t b = gl_color32_to_b(color);
|
||||
|
||||
return (r + g + b) / 3;
|
||||
}
|
||||
|
||||
#ifdef GL_COLOR_16BIT
|
||||
// Blends foreground and background colors with 4-bit alpha
|
||||
//
|
||||
// Returns a color in 16-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 15, the function returns the foreground color
|
||||
static inline gl_color16_t gl_color16_blend_a4(gl_color16_t fg, gl_color16_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = (fg & 0xF800) >> 11;
|
||||
uint16_t bg_r = (bg & 0xF800) >> 11;
|
||||
uint16_t r = a4_lerp(fg_r, bg_r, alpha);
|
||||
|
||||
uint16_t fg_g = (fg & 0x07E0) >> 5;
|
||||
uint16_t bg_g = (bg & 0x07E0) >> 5;
|
||||
uint16_t g = a4_lerp(fg_g, bg_g, alpha);
|
||||
|
||||
uint16_t fg_b = (fg & 0x001F) >> 0;
|
||||
uint16_t bg_b = (bg & 0x001F) >> 0;
|
||||
uint16_t b = a4_lerp(fg_b, bg_b, alpha);
|
||||
|
||||
return (r << 11) | (g << 5) | b;
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 8-bit alpha
|
||||
//
|
||||
// Returns a color in 16-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 15, the function returns the foreground color
|
||||
static inline gl_color16_t gl_color16_blend_a8(gl_color16_t fg, gl_color16_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = (fg & 0xF800) >> 11;
|
||||
uint16_t bg_r = (bg & 0xF800) >> 11;
|
||||
uint16_t r = a8_lerp(fg_r, bg_r, alpha);
|
||||
|
||||
uint16_t fg_g = (fg & 0x07E0) >> 5;
|
||||
uint16_t bg_g = (bg & 0x07E0) >> 5;
|
||||
uint16_t g = a8_lerp(fg_g, bg_g, alpha);
|
||||
|
||||
uint16_t fg_b = (fg & 0x001F) >> 0;
|
||||
uint16_t bg_b = (bg & 0x001F) >> 0;
|
||||
uint16_t b = a8_lerp(fg_b, bg_b, alpha);
|
||||
|
||||
return (r << 11) | (g << 5) | b;
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 4-bit alpha
|
||||
//
|
||||
// Returns a color in 32-bit format
|
||||
//
|
||||
// If alpha is 0, the function returns the background color
|
||||
// If alpha is 15, the function returns the foreground color
|
||||
static inline gl_color32_t gl_color32_blend_a4(gl_color16_t fg, gl_color16_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = gl_color16_to_r(fg);
|
||||
uint16_t bg_r = gl_color16_to_r(bg);
|
||||
uint16_t r = a4_lerp(fg_r, bg_r, alpha);
|
||||
|
||||
uint16_t fg_g = gl_color16_to_g(fg);
|
||||
uint16_t bg_g = gl_color16_to_g(bg);
|
||||
uint16_t g = a4_lerp(fg_g, bg_g, alpha);
|
||||
|
||||
uint16_t fg_b = gl_color16_to_b(fg);
|
||||
uint16_t bg_b = gl_color16_to_b(bg);
|
||||
uint16_t b = a4_lerp(fg_b, bg_b, alpha);
|
||||
|
||||
return gl_color32_rgb(r, g, b);
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 8-bit alpha
|
||||
//
|
||||
// Returns a color in 32-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 255, the function returns the foreground color
|
||||
static inline gl_color32_t gl_color32_blend_a8(gl_color16_t fg, gl_color16_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = gl_color16_to_r(fg);
|
||||
uint16_t bg_r = gl_color16_to_r(bg);
|
||||
uint16_t r = a8_lerp(fg_r, bg_r, alpha);
|
||||
|
||||
uint16_t fg_g = gl_color16_to_g(fg);
|
||||
uint16_t bg_g = gl_color16_to_g(bg);
|
||||
uint16_t g = a8_lerp(fg_g, bg_g, alpha);
|
||||
|
||||
uint16_t fg_b = gl_color16_to_b(fg);
|
||||
uint16_t bg_b = gl_color16_to_b(bg);
|
||||
uint16_t b = a8_lerp(fg_b, bg_b, alpha);
|
||||
|
||||
return gl_color32_rgb(r, g, b);
|
||||
}
|
||||
|
||||
#elif GL_COLOR_32BIT
|
||||
|
||||
// Blends foreground and background colors with 4-bit alpha
|
||||
//
|
||||
// Returns a color in 16-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 15, the function returns the foreground color
|
||||
static inline gl_color16_t gl_color16_blend_a4(gl_color32_t fg, gl_color32_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = gl_color32_to_r(fg);
|
||||
uint16_t bg_r = gl_color32_to_r(bg);
|
||||
uint16_t r = a4_lerp(fg_r, bg_r, alpha);
|
||||
|
||||
uint16_t fg_g = gl_color32_to_g(fg);
|
||||
uint16_t bg_g = gl_color32_to_g(bg);
|
||||
uint16_t g = a4_lerp(fg_g, bg_g, alpha);
|
||||
|
||||
uint16_t fg_b = gl_color32_to_b(fg);
|
||||
uint16_t bg_b = gl_color32_to_b(bg);
|
||||
uint16_t b = a4_lerp(fg_b, bg_b, alpha);
|
||||
|
||||
return gl_color16_rgb(r, g, b);
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 8-bit alpha
|
||||
//
|
||||
// Returns a color in 16-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 255, the function returns the foreground color
|
||||
static inline gl_color16_t gl_color16_blend_a8(gl_color32_t fg, gl_color32_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = gl_color32_to_r(fg);
|
||||
uint16_t bg_r = gl_color32_to_r(bg);
|
||||
uint16_t r = a8_lerp(fg_r, bg_r, alpha);
|
||||
|
||||
uint16_t fg_g = gl_color32_to_g(fg);
|
||||
uint16_t bg_g = gl_color32_to_g(bg);
|
||||
uint16_t g = a8_lerp(fg_g, bg_g, alpha);
|
||||
|
||||
uint16_t fg_b = gl_color32_to_b(fg);
|
||||
uint16_t bg_b = gl_color32_to_b(bg);
|
||||
uint16_t b = g = a8_lerp(fg_b, bg_b, alpha);
|
||||
|
||||
return gl_color16_rgb(r, g, b);
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 4-bit alpha
|
||||
//
|
||||
// Returns a color in 32-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 15, the function returns the foreground color
|
||||
static inline gl_color32_t gl_color32_blend_a4(gl_color32_t fg, gl_color32_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = gl_color32_to_r(fg);
|
||||
uint16_t bg_r = gl_color32_to_r(bg);
|
||||
uint16_t r = a4_lerp(fg_r, bg_r, alpha);
|
||||
|
||||
uint16_t fg_g = gl_color32_to_g(fg);
|
||||
uint16_t bg_g = gl_color32_to_g(bg);
|
||||
uint16_t g = a4_lerp(fg_g, bg_g, alpha);
|
||||
|
||||
uint16_t fg_b = gl_color32_to_b(fg);
|
||||
uint16_t bg_b = gl_color32_to_b(bg);
|
||||
uint16_t b = a4_lerp(fg_b, bg_b, alpha);
|
||||
|
||||
return gl_color32_rgb(r, g, b);
|
||||
}
|
||||
|
||||
// Blends foreground and background colors with 8-bit alpha
|
||||
//
|
||||
// Returns a color in 32-bit format
|
||||
//
|
||||
// If `alpha` is 0, the function returns the background color
|
||||
// If `alpha` is 15, the function returns the foreground color
|
||||
static inline gl_color32_t gl_color32_blend_a8(gl_color32_t fg, gl_color32_t bg,
|
||||
uint8_t alpha) {
|
||||
uint16_t fg_r = gl_color32_to_r(fg);
|
||||
uint16_t bg_r = gl_color32_to_r(bg);
|
||||
uint16_t r = a8_lerp(fg_r, bg_r, alpha);
|
||||
|
||||
uint16_t fg_g = gl_color32_to_g(fg);
|
||||
uint16_t bg_g = gl_color32_to_g(bg);
|
||||
uint16_t g = a8_lerp(fg_g, bg_g, alpha);
|
||||
|
||||
uint16_t fg_b = gl_color32_to_b(fg);
|
||||
uint16_t bg_b = gl_color32_to_b(bg);
|
||||
uint16_t b = a8_lerp(fg_b, bg_b, alpha);
|
||||
|
||||
return gl_color32_rgb(r, g, b);
|
||||
}
|
||||
|
||||
#else
|
||||
#error "GL_COLOR_16BIT/32BIT not specified"
|
||||
#endif
|
||||
|
||||
// Returns a gradient as an array of 16 consecutive 16-bit colors
|
||||
//
|
||||
// Each element in the array represents a color, with `retval[0]` being
|
||||
// the background (`bg`) color and `retval[15]` the foreground (`fg`) color
|
||||
const gl_color16_t* gl_color16_gradient_a4(gl_color_t fg, gl_color_t bg);
|
||||
|
||||
// Returns a gradient as an array of 16 consecutive 32-bit colors
|
||||
//
|
||||
// Each element in the array represents a color, with `retval[0]` being
|
||||
// the background (`bg`) color and `retval[15]` the foreground (`fg`) color
|
||||
const gl_color32_t* gl_color32_gradient_a4(gl_color_t fg, gl_color_t bg);
|
||||
|
||||
#endif // TREZORHAL_GL_COLOR_H
|
@ -0,0 +1,275 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <display.h>
|
||||
|
||||
#include "display_draw.h"
|
||||
#include "fonts/fonts.h"
|
||||
#include "gl_draw.h"
|
||||
|
||||
typedef struct {
|
||||
int16_t dst_x;
|
||||
int16_t dst_y;
|
||||
int16_t src_x;
|
||||
int16_t src_y;
|
||||
int16_t width;
|
||||
int16_t height;
|
||||
} gl_clip_t;
|
||||
|
||||
static inline gl_clip_t gl_clip(gl_rect_t dst, const gl_bitmap_t* bitmap) {
|
||||
int16_t dst_x = dst.x0;
|
||||
int16_t dst_y = dst.y0;
|
||||
|
||||
int16_t src_x = 0;
|
||||
int16_t src_y = 0;
|
||||
|
||||
if (bitmap != NULL) {
|
||||
src_x += bitmap->offset.x;
|
||||
src_y += bitmap->offset.y;
|
||||
|
||||
// Normalize negative x-offset of bitmap
|
||||
if (src_x < 0) {
|
||||
dst_x -= src_x;
|
||||
src_x = 0;
|
||||
}
|
||||
|
||||
// Normalize negative y-offset of src bitmap
|
||||
if (src_y < 0) {
|
||||
dst_y -= src_y;
|
||||
src_y = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Normalize negative top-left of destination rectangle
|
||||
if (dst_x < 0) {
|
||||
src_x -= dst_x;
|
||||
dst_x = 0;
|
||||
}
|
||||
|
||||
if (dst_y < 0) {
|
||||
src_y -= dst_y;
|
||||
dst_y = 0;
|
||||
}
|
||||
|
||||
// Calculate dimension of effective rectangle
|
||||
int16_t width = MIN(DISPLAY_RESX, dst.x1) - dst_x;
|
||||
int16_t height = MIN(DISPLAY_RESY, dst.y1) - dst_y;
|
||||
|
||||
if (bitmap != NULL) {
|
||||
width = MIN(width, bitmap->size.x - src_x);
|
||||
height = MIN(height, bitmap->size.y - src_y);
|
||||
}
|
||||
|
||||
gl_clip_t clip = {
|
||||
.dst_x = dst_x,
|
||||
.dst_y = dst_y,
|
||||
.src_x = src_x,
|
||||
.src_y = src_y,
|
||||
.width = width,
|
||||
.height = height,
|
||||
};
|
||||
|
||||
return clip;
|
||||
}
|
||||
|
||||
void gl_clear(void) {
|
||||
gl_bitblt_t bb = {
|
||||
// Destination bitmap
|
||||
.height = DISPLAY_RESX,
|
||||
.width = DISPLAY_RESY,
|
||||
.dst_row = NULL,
|
||||
.dst_x = 0,
|
||||
.dst_y = 0,
|
||||
.dst_stride = 0,
|
||||
|
||||
// Source bitmap
|
||||
.src_fg = 0,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
display_fill(&bb);
|
||||
}
|
||||
|
||||
void gl_draw_bar(gl_rect_t rect, gl_color_t color) {
|
||||
gl_clip_t clip = gl_clip(rect, NULL);
|
||||
|
||||
if (clip.width <= 0 || clip.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gl_bitblt_t bb = {
|
||||
// Destination bitmap
|
||||
.height = clip.height,
|
||||
.width = clip.width,
|
||||
.dst_row = NULL,
|
||||
.dst_x = clip.dst_x,
|
||||
.dst_y = clip.dst_y,
|
||||
.dst_stride = 0,
|
||||
|
||||
// Source bitmap
|
||||
.src_fg = color,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
display_fill(&bb);
|
||||
}
|
||||
|
||||
void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap) {
|
||||
gl_clip_t clip = gl_clip(rect, bitmap);
|
||||
|
||||
if (clip.width <= 0 || clip.height <= 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
gl_bitblt_t bb = {
|
||||
// Destination bitmap
|
||||
.height = clip.height,
|
||||
.width = clip.width,
|
||||
.dst_row = NULL,
|
||||
.dst_x = clip.dst_x,
|
||||
.dst_y = clip.dst_y,
|
||||
.dst_stride = 0,
|
||||
|
||||
// Source bitmap
|
||||
.src_row = (uint8_t*)bitmap->ptr + bitmap->stride * clip.src_y,
|
||||
.src_x = clip.src_x,
|
||||
.src_y = clip.src_y,
|
||||
.src_stride = bitmap->stride,
|
||||
.src_fg = bitmap->fg_color,
|
||||
.src_bg = bitmap->bg_color,
|
||||
.src_alpha = 255,
|
||||
};
|
||||
|
||||
// Currently, we use `gl_draw_bitmap` exclusively for text rendering.
|
||||
// Therefore, we are including the variant of `display_copy_xxx()` that is
|
||||
// specifically needed for drawing glyphs in the format we are using
|
||||
// to save some space in the flash memory.
|
||||
|
||||
#if TREZOR_FONT_BPP == 1
|
||||
if (bitmap->format == GL_FORMAT_MONO1P) {
|
||||
display_copy_mono1p(&bb);
|
||||
}
|
||||
#endif
|
||||
#if TREZOR_FONT_BPP == 4
|
||||
if (bitmap->format == GL_FORMAT_MONO4) {
|
||||
display_copy_mono4(&bb);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TREZOR_FONT_BPP == 1
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO1P
|
||||
#define GLYPH_STRIDE(w) (((w) + 7) / 8)
|
||||
#elif TREZOR_FONT_BPP == 2
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO2
|
||||
#define GLYPH_STRIDE(w) (((w) + 3) / 4)
|
||||
#elif TREZOR_FONT_BPP == 4
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO4
|
||||
#define GLYPH_STRIDE(w) (((w) + 1) / 2)
|
||||
#elif TREZOR_FONT_BPP == 8
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#define GLYPH_FORMAT GL_FORMAT_MONO8
|
||||
#define GLYPH_STRIDE(w) (w)
|
||||
#else
|
||||
#error Unsupported TREZOR_FONT_BPP value
|
||||
#endif
|
||||
|
||||
#define GLYPH_WIDTH(g) ((g)[0])
|
||||
#define GLYPH_HEIGHT(g) ((g)[1])
|
||||
#define GLYPH_ADVANCE(g) ((g)[2])
|
||||
#define GLYPH_BEARING_X(g) ((g)[3])
|
||||
#define GLYPH_BEARING_Y(g) ((g)[4])
|
||||
#define GLYPH_DATA(g) ((void*)&(g)[5])
|
||||
|
||||
void gl_draw_text(gl_offset_t pos, const char* text, size_t maxlen,
|
||||
const gl_text_attr_t* attr) {
|
||||
if (text == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
gl_bitmap_t bitmap = {
|
||||
.format = GLYPH_FORMAT,
|
||||
.fg_color = attr->fg_color,
|
||||
.bg_color = attr->bg_color,
|
||||
};
|
||||
|
||||
int max_height = font_max_height(attr->font);
|
||||
int baseline = font_baseline(attr->font);
|
||||
|
||||
for (int i = 0; i < maxlen; i++) {
|
||||
uint8_t ch = (uint8_t)text[i];
|
||||
|
||||
if (ch == 0 || pos.x >= DISPLAY_RESX) {
|
||||
break;
|
||||
}
|
||||
|
||||
const uint8_t* glyph = font_get_glyph(attr->font, ch);
|
||||
|
||||
if (glyph == NULL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bitmap.ptr = GLYPH_DATA(glyph);
|
||||
bitmap.stride = GLYPH_STRIDE(GLYPH_WIDTH(glyph));
|
||||
bitmap.size.x = GLYPH_WIDTH(glyph);
|
||||
bitmap.size.y = GLYPH_HEIGHT(glyph);
|
||||
|
||||
bitmap.offset.x = -GLYPH_BEARING_X(glyph);
|
||||
bitmap.offset.y = -(max_height - baseline - GLYPH_BEARING_Y(glyph));
|
||||
|
||||
gl_draw_bitmap(gl_rect(pos.x, pos.y, DISPLAY_RESX, DISPLAY_RESY), &bitmap);
|
||||
|
||||
pos.x += GLYPH_ADVANCE(glyph);
|
||||
}
|
||||
}
|
||||
|
||||
// ===============================================================
|
||||
// emulation of legacy functions
|
||||
|
||||
void display_clear(void) { gl_clear(); }
|
||||
|
||||
void display_bar(int x, int y, int w, int h, uint16_t c) {
|
||||
gl_draw_bar(gl_rect_wh(x, y, w, h), c);
|
||||
}
|
||||
|
||||
void display_text(int x, int y, const char* text, int textlen, int font,
|
||||
uint16_t fg_color, uint16_t bg_color) {
|
||||
gl_text_attr_t attr = {
|
||||
.font = font,
|
||||
.fg_color = fg_color,
|
||||
.bg_color = bg_color,
|
||||
};
|
||||
|
||||
size_t maxlen = textlen < 0 ? UINT32_MAX : textlen;
|
||||
gl_draw_text(gl_offset(x, y), text, maxlen, &attr);
|
||||
}
|
||||
|
||||
void display_text_center(int x, int y, const char* text, int textlen, int font,
|
||||
uint16_t fg_color, uint16_t bg_color) {
|
||||
gl_text_attr_t attr = {
|
||||
.font = font,
|
||||
.fg_color = fg_color,
|
||||
.bg_color = bg_color,
|
||||
};
|
||||
|
||||
size_t maxlen = textlen < 0 ? UINT32_MAX : textlen;
|
||||
int w = font_text_width(font, text, textlen);
|
||||
gl_draw_text(gl_offset(x - w / 2, y), text, maxlen, &attr);
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
/*
|
||||
* This file is part of the Trezor project, https://trezor.io/
|
||||
*
|
||||
* Copyright (c) SatoshiLabs
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef GL_DRAW_H
|
||||
#define GL_DRAW_H
|
||||
|
||||
#include "gl_color.h"
|
||||
|
||||
// 2D rectangle coordinates
|
||||
//
|
||||
// `x0`, `y0` - top-left coordinates
|
||||
// `x1`, `y1` - bottom-right coordinates point (not included)
|
||||
typedef struct {
|
||||
int16_t x0;
|
||||
int16_t y0;
|
||||
int16_t x1;
|
||||
int16_t y1;
|
||||
} gl_rect_t;
|
||||
|
||||
// Builds a rectangle (`gl_rect_t`) from top-left coordinates and dimensions
|
||||
static inline gl_rect_t gl_rect_wh(int16_t x, int16_t y, int16_t w, int16_t h) {
|
||||
gl_rect_t rect = {
|
||||
.x0 = x,
|
||||
.y0 = y,
|
||||
.x1 = x + w,
|
||||
.y1 = y + h,
|
||||
};
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// Builds a rectangle (`gl_rect_t`) from top-left and bottom-right coordinates
|
||||
static inline gl_rect_t gl_rect(int16_t x0, int16_t y0, int16_t x1,
|
||||
int16_t y1) {
|
||||
gl_rect_t rect = {
|
||||
.x0 = x0,
|
||||
.y0 = y0,
|
||||
.x1 = x1,
|
||||
.y1 = y1,
|
||||
};
|
||||
|
||||
return rect;
|
||||
}
|
||||
|
||||
// 2D offset/ coordinates
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} gl_offset_t;
|
||||
|
||||
// Builds a `gl_offset_t` structure
|
||||
static inline gl_offset_t gl_offset(int16_t x, int16_t y) {
|
||||
gl_offset_t offset = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
// 2D size in pixels
|
||||
typedef struct {
|
||||
int16_t x;
|
||||
int16_t y;
|
||||
} gl_size_t;
|
||||
|
||||
// Builds a `gl_size_t` structure
|
||||
static inline gl_size_t gl_size(int16_t x, int16_t y) {
|
||||
gl_size_t size = {
|
||||
.x = x,
|
||||
.y = y,
|
||||
};
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// Format of pixels in a bitmap
|
||||
typedef enum {
|
||||
GL_FORMAT_UNKNOWN, //
|
||||
GL_FORMAT_MONO1P, // 1-bpp per pixel (packed)
|
||||
GL_FORMAT_MONO4, // 4-bpp per pixel
|
||||
GL_FORMAT_RGB565, // 16-bpp per pixel
|
||||
GL_FORMAT_RGBA8888, // 32-bpp
|
||||
} gl_format_t;
|
||||
|
||||
// 2D bitmap reference
|
||||
typedef struct {
|
||||
// pointer to top-left pixel
|
||||
void* ptr;
|
||||
// stride in bytes
|
||||
size_t stride;
|
||||
// size in pixels
|
||||
gl_size_t size;
|
||||
// format of pixels, GL_FORMAT_xxx
|
||||
uint8_t format;
|
||||
// offset used when bitmap is drawed using gl_draw_bitmap()
|
||||
gl_offset_t offset;
|
||||
// foreground color (used with MONOx formats)
|
||||
gl_color_t fg_color;
|
||||
// background color (used with MONOx formats)
|
||||
gl_color_t bg_color;
|
||||
} gl_bitmap_t;
|
||||
|
||||
// Text attributes (font and color)
|
||||
typedef struct {
|
||||
// Font identifier
|
||||
int font;
|
||||
// Foreground color
|
||||
gl_color_t fg_color;
|
||||
// Background color
|
||||
gl_color_t bg_color;
|
||||
} gl_text_attr_t;
|
||||
|
||||
// Fills a rectangle with a specified color.
|
||||
void gl_draw_bar(gl_rect_t rect, gl_color_t color);
|
||||
|
||||
// Draws a bitmap into the specified rectangle.
|
||||
//
|
||||
// The destination rectangle may not be fully filled if the source bitmap
|
||||
// is smaller than destination rectangle or if the bitmap is translated by
|
||||
// an offset partially or completely outside the destination rectangle.
|
||||
//
|
||||
// Currently, we use `gl_draw_bitmap` exclusively for text rendering.
|
||||
// Not all bitmap formats are supported now. Please see the implementation.
|
||||
void gl_draw_bitmap(gl_rect_t rect, const gl_bitmap_t* bitmap);
|
||||
|
||||
// Draws a text to the specified position.
|
||||
//
|
||||
// `offset` - the most left point on the font baseline
|
||||
// `text` - utf-8 text
|
||||
// `maxlen` - maximum number of characters displayed (use SIZE_MAX when not
|
||||
// specified) `attr` - font & text color
|
||||
void gl_draw_text(gl_offset_t offset, const char* text, size_t maxlen,
|
||||
const gl_text_attr_t* attr);
|
||||
|
||||
#endif // GL_DRAW_H
|
@ -1,5 +1,6 @@
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#include "rust_ui_bootloader.h"
|
||||
#include "rust_ui_common.h"
|
||||
|
@ -0,0 +1,216 @@
|
||||
use super::ffi;
|
||||
|
||||
use crate::ui::{
|
||||
display::Color,
|
||||
geometry::Rect,
|
||||
shape::{Bitmap, BitmapFormat, BitmapView},
|
||||
};
|
||||
|
||||
pub type BitBlt = ffi::gl_bitblt_t;
|
||||
|
||||
impl Default for BitBlt {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
width: 0,
|
||||
height: 0,
|
||||
dst_row: core::ptr::null_mut(),
|
||||
dst_stride: 0,
|
||||
dst_x: 0,
|
||||
dst_y: 0,
|
||||
src_row: core::ptr::null_mut(),
|
||||
src_bg: 0,
|
||||
src_fg: 0,
|
||||
src_stride: 0,
|
||||
src_x: 0,
|
||||
src_y: 0,
|
||||
src_alpha: 255,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl BitBlt {
|
||||
pub fn new_fill(r: Rect, clip: Rect, color: Color, alpha: u8) -> Option<Self> {
|
||||
let r = r.clamp(clip);
|
||||
if !r.is_empty() {
|
||||
Some(
|
||||
Self::default()
|
||||
.with_rect(r)
|
||||
.with_fg(color)
|
||||
.with_alpha(alpha),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new_copy(r: Rect, clip: Rect, src: &BitmapView) -> Option<Self> {
|
||||
let mut offset = src.offset;
|
||||
let mut r_dst = r;
|
||||
|
||||
// Normalize negative x & y-offset of the bitmap
|
||||
if offset.x < 0 {
|
||||
r_dst.x0 -= offset.x;
|
||||
offset.x = 0;
|
||||
}
|
||||
|
||||
if offset.y < 0 {
|
||||
r_dst.y0 -= offset.y;
|
||||
offset.y = 0;
|
||||
}
|
||||
|
||||
// Clip with the canvas viewport
|
||||
let mut r = r_dst.clamp(clip);
|
||||
|
||||
// Clip with the bitmap top-left
|
||||
if r.x0 > r_dst.x0 {
|
||||
offset.x += r.x0 - r_dst.x0;
|
||||
}
|
||||
|
||||
if r.y0 > r_dst.y0 {
|
||||
offset.y += r.y0 - r_dst.y0;
|
||||
}
|
||||
|
||||
// Clip with the bitmap size
|
||||
r.x1 = core::cmp::min(r.x0 + src.size().x - offset.x, r.x1);
|
||||
r.y1 = core::cmp::min(r.y0 + src.size().y - offset.y, r.y1);
|
||||
|
||||
if !r.is_empty() {
|
||||
Some(
|
||||
BitBlt::default()
|
||||
.with_rect(r)
|
||||
.with_src(src.bitmap, offset.x, offset.y)
|
||||
.with_bg(src.bg_color)
|
||||
.with_fg(src.fg_color),
|
||||
)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_dst(self, dst: &mut Bitmap) -> Self {
|
||||
Self {
|
||||
dst_row: unsafe { dst.row_ptr(self.dst_y) },
|
||||
dst_stride: dst.stride() as u16,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
fn with_rect(self, r: Rect) -> Self {
|
||||
Self {
|
||||
width: r.width() as u16,
|
||||
height: r.height() as u16,
|
||||
dst_x: r.x0 as u16,
|
||||
dst_y: r.y0 as u16,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
fn with_src(self, bitmap: &Bitmap, x: i16, y: i16) -> Self {
|
||||
let bitmap_stride = match bitmap.format() {
|
||||
BitmapFormat::MONO1P => bitmap.width() as u16, // packed bits
|
||||
_ => bitmap.stride() as u16,
|
||||
};
|
||||
|
||||
Self {
|
||||
src_row: unsafe { bitmap.row_ptr(y as u16) },
|
||||
src_stride: bitmap_stride,
|
||||
src_x: x as u16,
|
||||
src_y: y as u16,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
fn with_fg(self, fg_color: Color) -> Self {
|
||||
Self {
|
||||
src_fg: fg_color.into(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
fn with_bg(self, bg_color: Color) -> Self {
|
||||
Self {
|
||||
src_bg: bg_color.into(),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
fn with_alpha(self, alpha: u8) -> Self {
|
||||
Self {
|
||||
src_alpha: alpha,
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn wait_for_transfer() {
|
||||
#[cfg(feature = "dma2d")]
|
||||
unsafe {
|
||||
ffi::dma2d_wait()
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn rgb565_fill(&self) {
|
||||
unsafe { ffi::gl_rgb565_fill(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn rgb565_copy_mono4(&self) {
|
||||
unsafe { ffi::gl_rgb565_copy_mono4(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn rgb565_copy_rgb565(&self) {
|
||||
unsafe { ffi::gl_rgb565_copy_rgb565(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn rgb565_blend_mono4(&self) {
|
||||
unsafe { ffi::gl_rgb565_blend_mono4(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn rgba8888_fill(&self) {
|
||||
unsafe { ffi::gl_rgba8888_fill(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn rgba8888_copy_mono4(&self) {
|
||||
unsafe { ffi::gl_rgba8888_copy_mono4(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn rgba8888_copy_rgb565(&self) {
|
||||
unsafe { ffi::gl_rgba8888_copy_rgb565(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn rgba8888_copy_rgba8888(&self) {
|
||||
unsafe { ffi::gl_rgba8888_copy_rgba8888(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn rgba8888_blend_mono4(&self) {
|
||||
unsafe { ffi::gl_rgba8888_blend_mono4(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn mono8_fill(&self) {
|
||||
unsafe { ffi::gl_mono8_fill(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn mono8_copy_mono1p(&self) {
|
||||
unsafe { ffi::gl_mono8_copy_mono1p(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn mono8_copy_mono4(&self) {
|
||||
unsafe { ffi::gl_mono8_copy_mono4(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn mono8_blend_mono1p(&self) {
|
||||
unsafe { ffi::gl_mono8_blend_mono1p(self) };
|
||||
}
|
||||
|
||||
pub unsafe fn mono8_blend_mono4(&self) {
|
||||
unsafe { ffi::gl_mono8_blend_mono4(self) };
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "xframebuffer"), feature = "new_rendering"))]
|
||||
pub unsafe fn display_fill(&self) {
|
||||
unsafe { ffi::display_fill(self) };
|
||||
}
|
||||
|
||||
#[cfg(all(not(feature = "xframebuffer"), feature = "new_rendering"))]
|
||||
pub unsafe fn display_copy_rgb565(&self) {
|
||||
unsafe { ffi::display_copy_rgb565(self) };
|
||||
}
|
||||
}
|
@ -0,0 +1,62 @@
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display,
|
||||
display::Color,
|
||||
geometry::Rect,
|
||||
shape,
|
||||
shape::Renderer,
|
||||
};
|
||||
|
||||
pub struct Bar {
|
||||
area: Rect,
|
||||
color: Color,
|
||||
bg_color: Color,
|
||||
radius: i16,
|
||||
}
|
||||
|
||||
impl Bar {
|
||||
pub fn new(color: Color, bg_color: Color, radius: i16) -> Self {
|
||||
Self {
|
||||
area: Rect::zero(),
|
||||
color,
|
||||
bg_color,
|
||||
radius,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Bar {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
self.area
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
display::rect_fill_rounded(self.area, self.color, self.bg_color, self.radius as u8);
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::Bar::new(self.area)
|
||||
.with_bg(self.color)
|
||||
.with_radius(self.radius)
|
||||
.render(target);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
sink(self.area)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Bar {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("Bar");
|
||||
}
|
||||
}
|
@ -0,0 +1,98 @@
|
||||
use crate::{
|
||||
error::Error,
|
||||
micropython::{buffer::get_buffer, obj::Obj},
|
||||
};
|
||||
|
||||
use crate::ui::{
|
||||
component::{Component, Event, EventCtx, Never},
|
||||
display,
|
||||
geometry::{Alignment2D, Offset, Rect},
|
||||
shape,
|
||||
shape::Renderer,
|
||||
};
|
||||
|
||||
pub enum ImageBuffer {
|
||||
Object { obj: Obj },
|
||||
Slice { data: &'static [u8] },
|
||||
}
|
||||
|
||||
impl ImageBuffer {
|
||||
pub fn from_object(obj: Obj) -> Result<Self, Error> {
|
||||
if !obj.is_bytes() {
|
||||
return Err(Error::TypeError);
|
||||
}
|
||||
Ok(ImageBuffer::Object { obj })
|
||||
}
|
||||
|
||||
pub fn from_slice(data: &'static [u8]) -> Self {
|
||||
ImageBuffer::Slice { data }
|
||||
}
|
||||
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.data().is_empty()
|
||||
}
|
||||
|
||||
pub fn data(&self) -> &[u8] {
|
||||
match self {
|
||||
// SAFETY: We expect no existing mutable reference. Resulting reference is
|
||||
// discarded before returning to micropython.
|
||||
ImageBuffer::Object { obj } => unsafe { unwrap!(get_buffer(*obj)) },
|
||||
ImageBuffer::Slice { data } => data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Jpeg {
|
||||
area: Rect,
|
||||
data: ImageBuffer,
|
||||
scale: u8,
|
||||
}
|
||||
|
||||
impl Jpeg {
|
||||
pub fn new(data: ImageBuffer, scale: u8) -> Self {
|
||||
Self {
|
||||
area: Rect::zero(),
|
||||
data,
|
||||
scale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Component for Jpeg {
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
self.area
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
if let Some((size, _)) = display::tjpgd::jpeg_info(self.data.data()) {
|
||||
let off = Offset::new(size.x / (2 << self.scale), size.y / (2 << self.scale));
|
||||
display::tjpgd::jpeg(self.data.data(), self.area.center() - off, self.scale);
|
||||
}
|
||||
}
|
||||
|
||||
fn render<'s>(&'s self, target: &mut impl Renderer<'s>) {
|
||||
shape::JpegImage::new(self.area.center(), self.data.data())
|
||||
.with_align(Alignment2D::CENTER)
|
||||
.with_scale(self.scale)
|
||||
.render(target);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
sink(self.area)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl crate::trace::Trace for Jpeg {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("Jpeg");
|
||||
}
|
||||
}
|
@ -1,74 +0,0 @@
|
||||
#[cfg(feature = "jpeg")]
|
||||
use crate::ui::geometry::Offset;
|
||||
use crate::ui::{
|
||||
component::{image::Image, Component, Event, EventCtx, Never},
|
||||
display,
|
||||
geometry::{Alignment2D, Rect},
|
||||
};
|
||||
|
||||
pub struct Painter<F> {
|
||||
area: Rect,
|
||||
func: F,
|
||||
}
|
||||
|
||||
impl<F> Painter<F> {
|
||||
pub fn new(func: F) -> Self {
|
||||
Self {
|
||||
func,
|
||||
area: Rect::zero(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<F> Component for Painter<F>
|
||||
where
|
||||
F: FnMut(Rect),
|
||||
{
|
||||
type Msg = Never;
|
||||
|
||||
fn place(&mut self, bounds: Rect) -> Rect {
|
||||
self.area = bounds;
|
||||
self.area
|
||||
}
|
||||
|
||||
fn event(&mut self, _ctx: &mut EventCtx, _event: Event) -> Option<Self::Msg> {
|
||||
None
|
||||
}
|
||||
|
||||
fn paint(&mut self) {
|
||||
(self.func)(self.area);
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_bounds")]
|
||||
fn bounds(&self, sink: &mut dyn FnMut(Rect)) {
|
||||
sink(self.area)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "ui_debug")]
|
||||
impl<F> crate::trace::Trace for Painter<F> {
|
||||
fn trace(&self, t: &mut dyn crate::trace::Tracer) {
|
||||
t.component("Painter");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn image_painter(image: Image) -> Painter<impl FnMut(Rect)> {
|
||||
let f = move |area: Rect| image.draw(area.center(), Alignment2D::CENTER);
|
||||
Painter::new(f)
|
||||
}
|
||||
|
||||
#[cfg(feature = "jpeg")]
|
||||
pub fn jpeg_painter<'a>(
|
||||
image: impl Fn() -> &'a [u8],
|
||||
size: Offset,
|
||||
scale: u8,
|
||||
) -> Painter<impl FnMut(Rect)> {
|
||||
let off = Offset::new(size.x / (2 << scale), size.y / (2 << scale));
|
||||
let f = move |area: Rect| display::tjpgd::jpeg(image(), area.center() - off, scale);
|
||||
Painter::new(f)
|
||||
}
|
||||
|
||||
pub fn rect_painter(fg: display::Color, bg: display::Color) -> Painter<impl FnMut(Rect)> {
|
||||
let f = move |area: Rect| display::rect_fill_rounded(area, fg, bg, 2);
|
||||
Painter::new(f)
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue