Forked from
card10 / firmware
1417 commits behind the upstream repository.
-
rahix authored
Text was displayed one character further right than intended because the offset was incremented before drawing. This commit reverses the two operations and thus restores proper display of text. Signed-off-by:
Rahix <rahix@rahix.de>
rahix authoredText was displayed one character further right than intended because the offset was incremented before drawing. This commit reverses the two operations and thus restores proper display of text. Signed-off-by:
Rahix <rahix@rahix.de>
gfx.c 5.19 KiB
#include "gfx.h"
#include "framebuffer.h"
#include <stddef.h>
#include <stdlib.h>
#include <math.h>
const struct gfx_color_rgb gfx_colors_rgb[COLORS] = {
{ 255, 255, 255 }, /* WHITE */
{ 0, 0, 0 }, /* BLACK */
{ 255, 0, 0 }, /* RED */
{ 0, 255, 0 }, /* GREEN */
{ 0, 0, 255 }, /* BLUE */
{ 255, 255, 0 } /* YELLOW */
};
void gfx_setpixel(struct gfx_region *r, int x, int y, Color c)
{
if (x < 0 || y < 0)
return;
if (x >= r->width || y >= r->height)
return;
fb_setpixel(r->fb, r->x + x, r->y + y, c);
}
struct gfx_region gfx_screen(struct framebuffer *fb)
{
struct gfx_region r = { .fb = fb,
.x = 0,
.y = 0,
.width = fb->width,
.height = fb->height };
return r;
}
static inline int letter_bit(sFONT *font, char c, int x, int y)
{
if (x < 0 || y < 0)
return 0;
if (x >= font->Width || y >= font->Height)
return 0;
if (c < ' ' || c > '~')
return 0;
size_t bytes_per_row = font->Width / 8 + 1;
size_t bytes_per_letter = bytes_per_row * font->Height;
int letter = c - ' ';
const uint8_t *letter_ptr = font->table + bytes_per_letter * letter;
int horz_byte = x / 8;
int horz_bit = 7 - x % 8;
return (*(letter_ptr + y * bytes_per_row + horz_byte) >> horz_bit) & 1;
}
void gfx_putchar(
sFONT *font,
struct gfx_region *r,
int x,
int y,
char ch,
Color fg,
Color bg
) {
for (int yo = 0; yo < font->Height; yo++) {
for (int xo = 0; xo < font->Width; xo++) {
int lb = letter_bit(font, ch, xo, yo);
if (fg != bg) {
Color c = lb ? fg : bg;
gfx_setpixel(r, x + xo, y + yo, c);
} else {
if (lb) {
gfx_setpixel(r, x + xo, y + yo, fg);
}
}
}
}
}
void gfx_puts(
sFONT *font,
struct gfx_region *r,
int x,
int y,
const char *str,
Color fg,
Color bg
) {
while (*str) {
gfx_putchar(font, r, x, y, *str, fg, bg);
str++;
x += font->Width;
if (x >= r->width) {
x = 0;
y += font->Height;
}
if (y >= r->height)
return;
}
}
Color gfx_color_rgb_f(struct gfx_region *reg, float r, float g, float b)
{
return fb_encode_color_rgb_f(reg->fb, r, g, b);
}
Color gfx_color_rgb(struct gfx_region *reg, uint8_t r, uint8_t g, uint8_t b)
{
return fb_encode_color_rgb(reg->fb, r, g, b);
}
void gfx_update(struct gfx_region *reg)
{
reg->fb->update(reg->fb);
}
void gfx_clear_to_color(struct gfx_region *reg, Color c)
{
fb_clear_to_color(reg->fb, c);
}
void gfx_clear(struct gfx_region *reg)
{
gfx_clear_to_color(reg, gfx_color(reg, BLACK));
}
void gfx_circle(struct gfx_region *reg, int x, int y, int r, int t, Color c)
{
for (int y_ = y - r; y_ <= y + r; y_++) {
for (int x_ = x - r; x_ <= x + r; x_++) {
int dx = (x_ - x) * (x_ - x);
int dy = (y_ - y) * (y_ - y);
int outer = (r + t) * (r + t);
int inner = r * r;
int edge = ((dx + dy) >= inner) && ((dx + dy) <= outer);
if (edge)
gfx_setpixel(reg, x_, y_, c);
}
}
}
void gfx_circle_fill(struct gfx_region *reg, int x, int y, int r, Color c)
{
for (int y_ = y - r; y_ <= y + r; y_++) {
for (int x_ = x - r; x_ <= x + r; x_++) {
int dx = (x_ - x) * (x_ - x);
int dy = (y_ - y) * (y_ - y);
int edge = r * r;
int fill = (dx + dy) <= edge;
if (fill)
gfx_setpixel(reg, x_, y_, c);
}
}
}
void gfx_rectangle(
struct gfx_region *reg, int x, int y, int w, int h, int t, Color c
) {
if (t > 1) {
gfx_thick_line(reg, x, y, x + w, y, t, c);
gfx_thick_line(reg, x, y + h, x + w, y + h, t, c);
gfx_thick_line(reg, x, y, x, y + h, t, c);
gfx_thick_line(reg, x + w, y, x + w, y + h, t, c);
} else {
gfx_line(reg, x, y, x + w, y, c);
gfx_line(reg, x, y + h, x + w, y + h, c);
gfx_line(reg, x, y, x, y + h, c);
gfx_line(reg, x + w, y, x + w, y + h, c);
}
}
void gfx_rectangle_fill(
struct gfx_region *reg, int x, int y, int w, int h, Color c
) {
for (int y_ = y; y_ < y + h; y_++) {
for (int x_ = x; x_ < x + w; x_++)
gfx_setpixel(reg, x_, y_, c);
}
}
void gfx_line(struct gfx_region *reg, int x1, int y1, int x2, int y2, Color c)
{
float dx = x2 - x1;
float dy = y2 - y1;
float de = fabs(dy / dx);
float e = .0f;
int y = y1;
for (int x = x1; x < x2; x++) {
gfx_setpixel(reg, x, y, c);
e += de;
if (e >= .5f) {
y += dy >= .0f ? 1 : -1;
e -= 1.0f;
}
}
}
void gfx_thick_line(
struct gfx_region *reg, int x1, int y1, int x2, int y2, int t, Color c
) {
float dx = x2 - x1;
float dy = y2 - y1;
float de = fabs(dy / dx);
float e = .0f;
int y = y1;
for (int x = x1; x < x2; x++) {
gfx_circle_fill(reg, x, y, t, c);
e += de;
if (e >= .5f) {
y += dy >= .0f ? 1 : -1;
e -= 1.0f;
}
}
}
Color gfx_color(struct gfx_region *reg, enum gfx_color color)
{
if ((int)(color) >= COLORS)
return 0;
const struct gfx_color_rgb *c = &gfx_colors_rgb[color];
return gfx_color_rgb(reg, c->r, c->g, c->b);
}
void gfx_copy_region_raw(
struct gfx_region *reg,
int x,
int y,
int w,
int h,
size_t bpp,
const void *p
) {
for (int y_ = 0; y_ < h; y_++) {
for (int x_ = 0; x_ < w; x_++) {
Color c;
switch (bpp) {
default:
case 2:
c = *(const uint16_t *)(p);
break;
}
gfx_setpixel(reg, x + x_, y + y_, c);
p += bpp;
}
}
}
void gfx_copy_raw(struct gfx_region *reg, const void *p, size_t size)
{
fb_copy_raw(reg->fb, p, size);
}