diff --git a/.gitignore b/.gitignore index 08ec64c..d91f6ce 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ builddir/ build/ - +*.json +*.jsonc diff --git a/.vscode/settings.json b/.vscode/settings.json index 65f3c12..65dbf06 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -10,6 +10,8 @@ "vector": "c", "string_view": "c", "initializer_list": "c", - "valarray": "c" + "valarray": "c", + "random": "c", + "nanosvgrast.h": "c" } } \ No newline at end of file diff --git a/include/nanosvg.h b/include/nanosvg.h index 1780aab..93d27ca 100644 --- a/include/nanosvg.h +++ b/include/nanosvg.h @@ -71,6 +71,8 @@ extern "C" { nsvgDelete(image); */ +#define NSVG_MAX_UNICODE_LEN 32 + enum NSVGpaintType { NSVG_PAINT_NONE = 0, NSVG_PAINT_COLOR = 1, @@ -151,7 +153,7 @@ typedef struct NSVGshape char fillRule; // Fill rule, see NSVGfillRule. unsigned char flags; // Logical or of NSVG_FLAGS_* flags float bounds[4]; // Tight bounding box of the shape [minx,miny,maxx,maxy]. - const char *unicode; // Unicode character code. + char unicode[NSVG_MAX_UNICODE_LEN]; // Unicode character code. int horizAdvX; // Horizontal distance to advance after rendering glyph. NSVGpath* paths; // Linked list of paths in the image. struct NSVGshape* next; // Pointer to next shape, or NULL if last element. @@ -457,7 +459,7 @@ typedef struct NSVGparser float dpi; char pathFlag; char defsFlag; - char *unicodeFlag; + char unicodeFlag[NSVG_MAX_UNICODE_LEN]; const char *horizAdvFlag; } NSVGparser; @@ -977,7 +979,7 @@ static void nsvg__addShape(NSVGparser* p) shape->opacity = attr->opacity; if (p->unicodeFlag) { - shape->unicode = p->unicodeFlag; + strcat(shape->unicode, p->unicodeFlag); if (p->horizAdvFlag) { shape->horizAdvX = strtol(p->horizAdvFlag, &end, 10); if (end == p->horizAdvFlag) @@ -986,7 +988,7 @@ static void nsvg__addShape(NSVGparser* p) if (shape->horizAdvX == 0) { shape->horizAdvX = p->image->defaultHorizAdv; } - p->unicodeFlag = NULL; + p->unicodeFlag[0] = '\0'; p->horizAdvFlag = NULL; } @@ -2254,8 +2256,8 @@ static void nsvg__parsePath(NSVGparser* p, const char** attr) for (i = 0; attr[i]; i += 2) { if (strcmp(attr[i], "d") == 0) { s = attr[i + 1]; - } else if (strcmp(attr[i], "unicode") == 0) { - p->unicodeFlag = malloc(strlen(attr[i+1])); + } else if (strcmp(attr[i], "unicode") == 0 + && strlen(attr[i+1]) < NSVG_MAX_UNICODE_LEN) { strcpy(p->unicodeFlag, attr[i+1]); } else if (strcmp(attr[i], "horiz-adv-x") == 0) { p->horizAdvFlag = attr[i+1]; @@ -3032,7 +3034,7 @@ NSVGimage* nsvgParseFromFile(const char* filename, const char* units, float dpi) error: if (fp) fclose(fp); if (data) free(data); - if (image) nsvgDelete(image); + nsvgDelete(image); return NULL; } diff --git a/include/nanosvgrast.h b/include/nanosvgrast.h index aab8c34..c080ea2 100644 --- a/include/nanosvgrast.h +++ b/include/nanosvgrast.h @@ -854,7 +854,7 @@ static int nsvg__cmpEdge(const void *p, const void *q) static NSVGactiveEdge* nsvg__addActive(NSVGrasterizer* r, NSVGedge* e, float startPoint) { - NSVGactiveEdge* z; + NSVGactiveEdge* z; if (r->freelist != NULL) { // Restore from freelist. diff --git a/include/pbsplash.h b/include/pbsplash.h new file mode 100644 index 0000000..bb2ba0a --- /dev/null +++ b/include/pbsplash.h @@ -0,0 +1,15 @@ +#ifndef __pbsplash_h__ +#define __pbsplash_h__ + +struct col { + union { + unsigned int rgba; + struct { + unsigned char r, g, b, a; + }; + }; +}; + +void animate_frame(int frame, int w, int y_off); + +#endif \ No newline at end of file diff --git a/src/animate.c b/src/animate.c new file mode 100644 index 0000000..4d0ea93 --- /dev/null +++ b/src/animate.c @@ -0,0 +1,27 @@ +#include +#include +#include +#include +#include "pbsplash.h" + +struct col color = {.r = 255, .g = 255, .b = 255, .a = 255}; + +// FIXME: calculate constants based on display size/resolution + +#define n_circles 5 +#define amplitude 40 +#define rad 12 + +void animate_frame(int frame, int w, int y_off) +{ + unsigned int t_col = tfb_make_color(color.r, color.g, color.b); + for (unsigned int i = 0; i < n_circles; i++) + { + int c_dist = w * 0.05; + int x = i * c_dist + w / 2 - c_dist * n_circles / 2.f; + double s = sin(frame / 30.0 * 3.1415 + i * 0.5); + int y = y_off + s * amplitude; + tfb_fill_rect(x - rad- 1, y_off - amplitude - rad, rad* 2 + 2, 400 +rad* 2, tfb_black); + tfb_fill_circle(x, y, rad, t_col); + } +} diff --git a/src/meson.build b/src/meson.build index 86fb3c1..77f2b51 100644 --- a/src/meson.build +++ b/src/meson.build @@ -1,5 +1,6 @@ src = [ 'pbsplash.c', + 'animate.c', ] executable('pbsplash', src, diff --git a/src/pbsplash.c b/src/pbsplash.c index 0e83ea6..fb942aa 100644 --- a/src/pbsplash.c +++ b/src/pbsplash.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,8 @@ #define NANOSVGRAST_IMPLEMENTATION #include "nanosvgrast.h" +#include "pbsplash.h" + #define MSG_MAX_LEN 4096 #define DEFAULT_FONT_PATH "/usr/share/pbsplash/OpenSans-Regular.svg" #define LOGO_SIZE_MAX_MM 90 @@ -22,11 +25,12 @@ #define PT_TO_MM 0.38f #define TTY_PATH_LEN 11 -#define DEBUGRENDER 1 +#define DEBUGRENDER 0 volatile sig_atomic_t terminate = 0; bool debug = true; +struct col background_color = {.r = 0, .g = 0, .b = 0, .a = 255}; #define LOG(fmt, ...) do { if (debug) fprintf(stdout, fmt, ##__VA_ARGS__); } while (0) @@ -51,18 +55,10 @@ void term(int signum) terminate = 1; } - -// Blit an SVG to the framebuffer using tfblib. The image is -// scaled based on the target width and height. -static void draw_svg(NSVGimage *image, int x, int y, int w, int h) +static void blit_buf(unsigned char* buf, int x, int y, int w, int h, bool vflip, bool redraw) { - float sz = (int)((float)w / (float)image->width * 100.f) / 100.f; - LOG("%f\n", sz); - //sz = 1.5; - NSVGrasterizer *rast = nsvgCreateRasterizer(); - unsigned char *img = malloc(w * h * 4); - nsvgRasterize(rast, image, 0, 0, sz, img, w, h, w * 4); - + unsigned int bg_col = tfb_make_color(background_color.r, background_color.g, background_color.b); + unsigned int col; for (size_t i = 0; i < w; i++) { for (size_t j = 0; j < h; j++) @@ -73,15 +69,59 @@ static void draw_svg(NSVGimage *image, int x, int y, int w, int h) continue; } #endif - unsigned int col = tfb_make_color(img[(j * w + i) * 4 + 0], img[(j * w + i) * 4 + 1], img[(j * w + i) * 4 + 2]); - tfb_draw_pixel(x + i, y + j, col); + struct col rgba = *(struct col *)(buf + (j * w + i) * 4); + if (!redraw && rgba.a == 0) + continue; + + if (redraw && rgba.a == 0) { + col = bg_col; + } else { + rgba.r = (rgba.r * rgba.a + background_color.r * (255 - rgba.a)) >> 8; + rgba.g = (rgba.g * rgba.a + background_color.g * (255 - rgba.a)) >> 8; + rgba.b = (rgba.b * rgba.a + background_color.b * (255 - rgba.a)) >> 8; + col = tfb_make_color(rgba.r, rgba.g, rgba.b); + } + if (vflip) + tfb_draw_pixel(x + i, y + h - j, col); + else + tfb_draw_pixel(x + i, y + j, col); } } - - free(img); } -/** +static void draw_svg(NSVGimage *image, int x, int y, int w, int h) +{ + float sz = (int)((float)w / (float)image->width * 100.f) / 100.f; + LOG("draw_svg: %dx%d, %dx%d, %f\n", x, y, w, h, sz); + //sz = 1.5; + NSVGrasterizer *rast = nsvgCreateRasterizer(); + unsigned char *img = malloc(w * h * 4); + nsvgRasterize(rast, image, 0, 0, sz, img, w, h, w * 4); + + blit_buf(img, x, y, w, h, false, false); + + free(img); + nsvgDeleteRasterizer(rast); +} + +static void draw_text(NSVGimage *font, char *text, int x, int y, int width, int height, float scale, unsigned int tfb_col) +{ + LOG("text '%s': fontsz=%f, x=%d, y=%d, dimensions: %d x %d\n", text, + scale, x, y, width, height); + NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text)); + unsigned char *img = malloc(width * height * 4); + NSVGrasterizer *rast = nsvgCreateRasterizer(); + + nsvgRasterizeText(rast, font, 0, 0, scale, img, width, height, width * 4, text); + + blit_buf(img, x, y, width, height, true, false); + + free(img); + free(shapes); + nsvgDeleteRasterizer(rast); +} + +/* * Get the dimensions of a string in pixels. * based on the font size and the font SVG file. */ @@ -105,37 +145,8 @@ static void getTextDimensions(NSVGimage *font, char *text, float scale, int *wid } else { *width += font->defaultHorizAdv * scale; } - - } -} - -static void draw_text(NSVGimage *font, char *text, int x, int y, int width, int height, float scale, unsigned int tfb_col) -{ - LOG("text '%s': fontsz=%f, x=%d, y=%d, dimensions: %d x %d\n", text, - scale, x, y, width, height); - NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text)); - unsigned char *img = malloc(width * height * 4); - NSVGrasterizer *rast = nsvgCreateRasterizer(); - - nsvgRasterizeText(rast, font, 0, 0, scale, img, width, height, width * 4, text); - - for (size_t i = 0; i < width; i++) - { - for (size_t j = 0; j < height; j++) - { -#if DEBUGRENDER == 1 - if (i == 0 || i == width - 1 || j == 0 || j == height-1) { - tfb_draw_pixel(x + i, y + height - j, tfb_red); - continue; - } -#endif - unsigned int col = tfb_make_color(img[(j * width + i) * 4 + 0], img[(j * width + i) * 4 + 1], img[(j * width + i) * 4 + 2]); - if (col != tfb_black) - tfb_draw_pixel(x + i, y + height - j, tfb_col); - } } - free(img); free(shapes); } @@ -145,7 +156,7 @@ int main(int argc, char **argv) char *message = NULL; char *splash_image = NULL; char *font_path = DEFAULT_FONT_PATH; - char active_tty[TTY_PATH_LEN + 5]; + char active_tty[TTY_PATH_LEN + 1]; NSVGimage *image; NSVGimage *font; struct sigaction action; @@ -208,23 +219,20 @@ int main(int argc, char **argv) } { - FILE *fp = fopen("/sys/devices/virtual/tty/tty0/active", "r"); - char ch; - if(fp != NULL) - { - while((ch = getc(fp)) != EOF && strlen(active_tty) < TTY_PATH_LEN) - { - if (ch == '\n') - break; - strcat(active_tty, &ch); - } - fclose(fp); - } + FILE *fp = fopen("/sys/devices/virtual/tty/tty0/active", "r"); + int len = strlen(active_tty); + char *ptr = active_tty + len; + if(fp != NULL) + { + fgets(ptr, TTY_PATH_LEN - len, fp); + *(ptr + strlen(ptr) - 1) = '\0'; + fclose(fp); + } } LOG("active tty: '%s'\n", active_tty); - if ((rc = tfb_acquire_fb(0, "/dev/fb0", active_tty)) != TFB_SUCCESS) + if ((rc = tfb_acquire_fb(/*TFB_FL_USE_DOUBLE_BUFFER*/ 0, "/dev/fb0", active_tty)) != TFB_SUCCESS) { fprintf(stderr, "tfb_acquire_fb() failed with error code: %d\n", rc); rc = 1; @@ -260,7 +268,7 @@ int main(int argc, char **argv) LOG("%dx%d @ %dx%dmm, dpi=%ld, logo_size_px=%f\n", w, h, w_mm, h_mm, dpi, logo_size_px); - image = nsvgParseFromFile(splash_image, "px", logo_size_px); + image = nsvgParseFromFile(splash_image, "", logo_size_px); if (!image) { fprintf(stderr, "failed to load SVG image\n"); @@ -277,7 +285,7 @@ int main(int argc, char **argv) x -= image_w * 0.5f; y -= image_h * 0.5f; - tfb_clear_screen(tfb_black); + tfb_clear_screen(tfb_make_color(background_color.r, background_color.g, background_color.b)); draw_svg(image, x, y, image_w, image_h); @@ -306,11 +314,22 @@ int main(int argc, char **argv) tfb_flush_window(); tfb_flush_fb(); +#define ANIM_HEIGHT 600 + //unsigned char* animation_buf = malloc(w * ANIM_HEIGHT * 4); + int frame = 0; while (!terminate) { - sleep(1); + //printf("FRAME: %d\n", frame); + animate_frame(frame++, w, y + image_h + 500); + //blit_buf(animation_buf, 0, y + image_h + 200, w, ANIM_HEIGHT, false, true); + //memset(animation_buf, 0, w * ANIM_HEIGHT * 4); + //tfb_flush_window(); + tfb_flush_fb(); + //usleep(1666); } + //free(animation_buf); + out: nsvgDelete(font); nsvgDelete(image);