Browse Source

拆分部分绘制函数至fbg_utils.h,增加timer调度以减少字体计算消耗

master
jiangming1399 1 year ago
parent
commit
899149f89c
7 changed files with 241 additions and 94 deletions
  1. +2
    -1
      .vscode/settings.json
  2. +7
    -1
      Makefile
  3. +61
    -0
      fbg_utils.c
  4. +20
    -0
      fbg_utils.h
  5. +42
    -92
      main.c
  6. +87
    -0
      timer.c
  7. +22
    -0
      timer.h

+ 2
- 1
.vscode/settings.json View File

@@ -10,6 +10,7 @@
"stdint.h": "c",
"stdlib.h": "c",
"stdbool.h": "c",
"fonts_border_renderer.h": "c"
"fonts_border_renderer.h": "c",
"fbg_utils.h": "c"
}
}

+ 7
- 1
Makefile View File

@@ -13,7 +13,7 @@ FBG_LIB := $(FBG_DIR)/lodepng/lodepng.o \
$(FBG_DIR)/nanojpeg/nanojpeg.o \
$(FBG_DIR)/fbgraphics.o

LIBS = $(FBG_LIB) fonts.o fonts_border_renderer.o calendar.o
LIBS = $(FBG_LIB) fonts.o fonts_border_renderer.o calendar.o fbg_utils.o timer.o

INCS := -I $(FBG_DIR) -I $(FREETYPE_DIR)/include -I. -lfreetype

@@ -57,6 +57,12 @@ fonts_border_renderer.o: fonts_border_renderer.c
calendar.o : calendar.c
$(CC) -c calendar.c -I $(FREETYPE_DIR)/include $(CFLAGS)

fbg_utils.o : fbg_utils.c
$(CC) -c fbg_utils.c -I $(FREETYPE_DIR)/include -I $(FBG_DIR) $(CFLAGS)

timer.o: timer.c
$(CC) -c timer.c $(CFLAGS)

.PHONY : clean

clean :

+ 61
- 0
fbg_utils.c View File

@@ -0,0 +1,61 @@
#include "fbg_utils.h"
#include <stdint.h>

void swap_bgr(struct color_rgb* color)
{
uint8_t t = color->r;
color->r = color->b;
color->b = t;
}

uint8_t alpha_blend(uint8_t b, uint8_t f, uint8_t a)
{
return (f * a + b * (255 - a)) >> 8;
}

uint8_t alpha_blend_abc(uint8_t b, uint8_t f1, uint8_t f2, uint8_t a1, uint8_t a2)
{
return alpha_blend(alpha_blend(b, f1, a1), f2, a2);
}

void draw_font(struct _fbg* f, struct font_render_buffer* src, int x, int y,
struct color_rgb color)
{
if (f->bgr)
swap_bgr(&color);

for (int i = 0; i < src->height && i + y < f->height; i++) {
for (int j = 0; j < src->width && j + x < f->width; j++) {
uint_fast8_t alpha = src->data[i * src->width + j];
if (alpha == 0)
continue;
int oIndex = ((i + y) * f->width + j + x) * f->components;
f->back_buffer[oIndex] = alpha_blend(f->back_buffer[oIndex], color.r, alpha);
f->back_buffer[oIndex + 1] = alpha_blend(f->back_buffer[oIndex + 1], color.g, alpha);
f->back_buffer[oIndex + 2] = alpha_blend(f->back_buffer[oIndex + 1], color.b, alpha);
}
}
}

void draw_font_border(struct _fbg* f, struct font_render_buffer* src, int x, int y,
struct color_rgb color, struct color_rgb border_color)
{
if (f->bgr) {
swap_bgr(&color);
swap_bgr(&border_color);
}

for (int i = 0; i < src->height && i + y < f->height; i++) {
for (int j = 0; j < src->width && j + x < f->width; j++) {
uint_fast8_t alpha = src->data[i * src->width + j];
if (alpha == 0)
continue;
uint_fast8_t border_alpha = alpha & 0xf0;
uint_fast8_t font_alpha = alpha << 4;
int oIndex = ((i + y) * f->width + j + x) * f->components;
f->back_buffer[oIndex] = alpha_blend_abc(f->back_buffer[oIndex], border_color.r, color.r, border_alpha, font_alpha);
f->back_buffer[oIndex + 1] = alpha_blend_abc(f->back_buffer[oIndex + 1], border_color.g, color.g, border_alpha, font_alpha);
f->back_buffer[oIndex + 2] = alpha_blend_abc(f->back_buffer[oIndex + 1], border_color.b, color.b, border_alpha, font_alpha);
}
}
}

+ 20
- 0
fbg_utils.h View File

@@ -0,0 +1,20 @@
#if !defined(__FBG_UTILS__)
#define __FBG_UTILS__

#include "fbgraphics.h"
#include "fonts.h"

struct color_rgb {
uint8_t r;
uint8_t g;
uint8_t b;
};

void swap_bgr(struct color_rgb* color);
uint8_t alpha_blend(uint8_t b, uint8_t f, uint8_t a);
void draw_font(struct _fbg* f, struct font_render_buffer* src, int x, int y,
struct color_rgb color);
void draw_font_border(struct _fbg* f, struct font_render_buffer* src, int x, int y,
struct color_rgb color, struct color_rgb border_color);

#endif // __FBG_UTILS__

+ 42
- 92
main.c View File

@@ -14,74 +14,47 @@

#include "fonts.h"
#include "calendar.h"
#include "fbg_utils.h"
#include "timer.h"

int keep_running = 1;

struct color_rgb {
uint8_t r;
uint8_t g;
uint8_t b;
};
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 480
#define CALENDAR_HEIGHT 30
#define MESSAGE_HEIGHT 20
#define CALENDAR_Y SCREEN_HEIGHT-CALENDAR_HEIGHT
#define MESSAGE_Y CALENDAR_Y-MESSAGE_HEIGHT

void swap_bgr(struct color_rgb* color)
{
uint8_t t = color->r;
color->r = color->b;
color->b = t;
}
const struct color_rgb color_black = { 0, 0, 0 };
const struct color_rgb color_white = { 255, 255, 255 };

int keep_running = 1;
void int_handler(int dummy) { keep_running = 0; }

uint8_t alpha_blend(uint8_t b, uint8_t f, uint8_t a)
{
return (f * a + b * (255 - a)) >> 8;
}
struct font_lib font1, font2;
struct font_render_buffer time_buffer, message_buffer, calendar_buffer;

uint8_t alpha_blend_abc(uint8_t b, uint8_t f1, uint8_t f2, uint8_t a1, uint8_t a2)
{
return alpha_blend(alpha_blend(b, f1, a1), f2, a2);
void init_fonts() {
fonts_init(&font1, "URWGothic-Demi.otf");
fonts_init(&font2, "DroidSansFallbackLegacy.ttf");

fonts_make_render_buffer(&time_buffer, 240, 60);
fonts_make_render_buffer(&message_buffer, SCREEN_WIDTH, MESSAGE_HEIGHT);
fonts_make_render_buffer(&calendar_buffer, SCREEN_WIDTH, CALENDAR_HEIGHT);
}

void draw_font(struct _fbg* f, struct font_render_buffer* src, int x, int y,
struct color_rgb color)
{
if (f->bgr)
swap_bgr(&color);

for (int i = 0; i < src->height && i + y < f->height; i++) {
for (int j = 0; j < src->width && j + x < f->width; j++) {
uint_fast8_t alpha = src->data[i * src->width + j];
if (alpha == 0)
continue;
int oIndex = ((i + y) * f->width + j + x) * f->components;
f->back_buffer[oIndex] = alpha_blend(f->back_buffer[oIndex], color.r, alpha);
f->back_buffer[oIndex + 1] = alpha_blend(f->back_buffer[oIndex + 1], color.g, alpha);
f->back_buffer[oIndex + 2] = alpha_blend(f->back_buffer[oIndex + 1], color.b, alpha);
}
}
void redraw_time() {
wchar_t time_str[10];
swprintf(time_str, 10, L"%02d:%02d:%02d", time_current.tm_hour, time_current.tm_min, time_current.tm_sec);
fonts_render_border(&font1, time_str, 55, 2<<6, FONT_ALIGN_LEFT, &time_buffer);
}

void draw_font_border(struct _fbg* f, struct font_render_buffer* src, int x, int y,
struct color_rgb color, struct color_rgb border_color)
{
if (f->bgr) {
swap_bgr(&color);
swap_bgr(&border_color);
}
void redraw_calendar() {
calendar_generate(&font2, &font1, &calendar_buffer);
}

for (int i = 0; i < src->height && i + y < f->height; i++) {
for (int j = 0; j < src->width && j + x < f->width; j++) {
uint_fast8_t alpha = src->data[i * src->width + j];
if (alpha == 0)
continue;
uint_fast8_t border_alpha = alpha & 0xf0;
uint_fast8_t font_alpha = alpha << 4;
int oIndex = ((i + y) * f->width + j + x) * f->components;
f->back_buffer[oIndex] = alpha_blend_abc(f->back_buffer[oIndex], border_color.r, color.r, border_alpha, font_alpha);
f->back_buffer[oIndex + 1] = alpha_blend_abc(f->back_buffer[oIndex + 1], border_color.g, color.g, border_alpha, font_alpha);
f->back_buffer[oIndex + 2] = alpha_blend_abc(f->back_buffer[oIndex + 1], border_color.b, color.b, border_alpha, font_alpha);
}
}
void init_timers() {
timer_add_hook(HOOK_SECOND, &redraw_time);
timer_add_hook(HOOK_DAY, &redraw_calendar);
}

int main(int argc, char* argv[])
@@ -89,7 +62,7 @@ int main(int argc, char* argv[])
signal(SIGINT, int_handler);

#ifdef GLFW
struct _fbg* fbg = fbg_glfwSetup(800, 480, "glfw example", 0, 0);
struct _fbg* fbg = fbg_glfwSetup(SCREEN_WIDTH, SCREEN_HEIGHT, "glfw example", 0, 0);
#else
struct _fbg* fbg = fbg_init();
#endif
@@ -98,33 +71,14 @@ int main(int argc, char* argv[])
return 0;
}

const struct color_rgb tianyi_blue = { 0x66, 0xcc, 0xff };
const struct color_rgb color_black = { 0, 0, 0 };
const struct color_rgb color_white = { 255, 255, 255 };

struct font_lib font1;
fonts_init(&font1, "URWGothic-Demi.otf");

struct font_lib font2;
fonts_init(&font2, "DroidSansFallbackLegacy.ttf");

struct _fbg_img* bb_font_img = fbg_loadPNG(fbg, "bbmode1_8x8.png");
struct _fbg_font* bbfont = fbg_createFont(fbg, bb_font_img, 8, 8, 33);
struct _fbg_img* bkg = fbg_loadPNG(fbg, "b.png");

time_t current_time;

wchar_t time_str[10];
struct font_render_buffer font_buffer;
fonts_make_render_buffer(&font_buffer, 240, 60);

struct font_render_buffer font_buffer2;
fonts_make_render_buffer(&font_buffer2, 480, 20);
fonts_render(&font2, L"一段简短的通知消息", 14, FONT_ALIGN_LEFT, &font_buffer2);
init_fonts();
init_timers();

struct font_render_buffer calendar_buff;
fonts_make_render_buffer(&calendar_buff, 800, 30);
calendar_generate(&font2, &font1, &calendar_buff);
fonts_render(&font2, L"一段简短的通知消息", 14, FONT_ALIGN_LEFT, &message_buffer);

do {
#ifdef GLFW
@@ -138,19 +92,15 @@ int main(int argc, char* argv[])
fbg_write(fbg, "Quickstart example\nFPS:", 4, 2);
fbg_write(fbg, fbg->fps_char, 32 + 8, 2 + 8);

time(&current_time);
struct tm* lt = localtime(&current_time);
swprintf(time_str, 10, L"%02d:%02d:%02d", lt->tm_hour, lt->tm_min, lt->tm_sec);

fonts_render_border(&font1, time_str, 55, 2<<6, FONT_ALIGN_LEFT, &font_buffer);
timer_update();

draw_font_border(fbg, &font_buffer, 12, 364, color_white, color_black);
draw_font_border(fbg, &time_buffer, 12, 364, color_white, color_black);

fbg_recta(fbg, 0, 430, 800, 20, 255, 255, 255, 192);
draw_font(fbg, &font_buffer2, 12, 430, color_black);
fbg_recta(fbg, 0, MESSAGE_Y, SCREEN_WIDTH, MESSAGE_HEIGHT, 255, 255, 255, 192);
draw_font(fbg, &message_buffer, 12, MESSAGE_Y, color_black);

fbg_recta(fbg, 0, 450, 800, 30, 255, 255, 255, 192);
draw_font(fbg, &calendar_buff, 0, 450, color_black);
fbg_recta(fbg, 0, CALENDAR_Y , SCREEN_WIDTH, CALENDAR_HEIGHT, 255, 255, 255, 192);
draw_font(fbg, &calendar_buffer, 0, CALENDAR_Y, color_black);

fbg_flip(fbg);
#ifdef GLFW
@@ -161,8 +111,8 @@ int main(int argc, char* argv[])
fbg_freeImage(bb_font_img);
fbg_freeFont(bbfont);

fonts_free_render_buffer(&font_buffer2);
fonts_free_render_buffer(&font_buffer);
fonts_free_render_buffer(&message_buffer);
fonts_free_render_buffer(&time_buffer);

fbg_close(fbg);
}

+ 87
- 0
timer.c View File

@@ -0,0 +1,87 @@
#include "timer.h"
#include <stdlib.h>

struct tm time_current = {
.tm_sec = 0,
.tm_min = 0,
.tm_hour = 0
};

struct timer_hooks {
hook_callback callback;
enum timer_hook_level level;
struct timer_hooks* next;
};

struct timer_hooks* hooks = NULL;

void timer_hook_node_exec(struct timer_hooks* node, enum timer_hook_level level)
{
if (node->level == level && node->callback != NULL) {
node->callback();
}
if (node->next != NULL) {
timer_hook_node_exec(node->next, level);
}
}

void timer_hook_exec(enum timer_hook_level level)
{
if (hooks != NULL)
timer_hook_node_exec(hooks, level);
}

void timer_update()
{
struct tm time_last = time_current;
time_t t = time(NULL);
time_current = *localtime(&t);

if (time_last.tm_sec != time_current.tm_sec)
timer_hook_exec(HOOK_SECOND);
if (time_last.tm_min != time_current.tm_min)
timer_hook_exec(HOOK_MINUTE);
if (time_last.tm_hour != time_current.tm_hour)
timer_hook_exec(HOOK_HOUR);
if (time_last.tm_mday != time_current.tm_mday)
timer_hook_exec(HOOK_DAY);
if (time_last.tm_mon != time_current.tm_mon)
timer_hook_exec(HOOK_MONTH);
}

void timer_add_hook(enum timer_hook_level level, hook_callback callback)
{
struct timer_hooks* node = malloc(sizeof(struct timer_hooks));
node->level = level;
node->callback = callback;
node->next = NULL;

if (hooks == NULL) {
hooks = node;
} else {
struct timer_hooks* t = hooks;
do {
if (!t->next) {
t->next = node;
break;
} else {
t = t->next;
}

} while (1);
}
}

void timer_hook_free_node(struct timer_hooks* node)
{
if (node->next)
timer_hook_free_node(node->next);
free(node);
}

void timer_hook_free()
{
if (hooks)
timer_hook_free_node(hooks);
hooks = NULL;
}

+ 22
- 0
timer.h View File

@@ -0,0 +1,22 @@
#if !defined(__TIMER_H__)
#define __TIMER_H__

#include <time.h>

enum timer_hook_level {
HOOK_SECOND,
HOOK_MINUTE,
HOOK_HOUR,
HOOK_DAY,
HOOK_MONTH
};

extern struct tm time_current;

typedef void (*hook_callback)();

void timer_update(void);
void timer_add_hook(enum timer_hook_level level, hook_callback callback);
void timer_hook_free();

#endif // __TIMER_H__

Loading…
Cancel
Save