mirror of
https://git.sr.ht/~calebccff/pbsplash
synced 2026-01-12 20:48:40 -09:00
sorta works
things run, text and logos work, it's a start
This commit is contained in:
parent
1d29b4d87a
commit
c13d5fd6ba
3 changed files with 98 additions and 66 deletions
|
|
@ -161,6 +161,9 @@ typedef struct NSVGimage
|
||||||
{
|
{
|
||||||
float width; // Width of the image.
|
float width; // Width of the image.
|
||||||
float height; // Height of the image.
|
float height; // Height of the image.
|
||||||
|
int fontAscent;
|
||||||
|
int fontDescent;
|
||||||
|
int defaultHorizAdv;
|
||||||
NSVGshape* shapes; // Linked list of shapes in the image.
|
NSVGshape* shapes; // Linked list of shapes in the image.
|
||||||
} NSVGimage;
|
} NSVGimage;
|
||||||
|
|
||||||
|
|
@ -456,7 +459,6 @@ typedef struct NSVGparser
|
||||||
char defsFlag;
|
char defsFlag;
|
||||||
char *unicodeFlag;
|
char *unicodeFlag;
|
||||||
char *horizAdvFlag;
|
char *horizAdvFlag;
|
||||||
char *defaultHorizAdv;
|
|
||||||
} NSVGparser;
|
} NSVGparser;
|
||||||
|
|
||||||
static void nsvg__xformIdentity(float* t)
|
static void nsvg__xformIdentity(float* t)
|
||||||
|
|
@ -982,7 +984,7 @@ static void nsvg__addShape(NSVGparser* p)
|
||||||
shape->horizAdvX = 0;
|
shape->horizAdvX = 0;
|
||||||
}
|
}
|
||||||
if (shape->horizAdvX == 0) {
|
if (shape->horizAdvX == 0) {
|
||||||
shape->horizAdvX = p->defaultHorizAdv;
|
shape->horizAdvX = p->image->defaultHorizAdv;
|
||||||
}
|
}
|
||||||
p->unicodeFlag = NULL;
|
p->unicodeFlag = NULL;
|
||||||
p->horizAdvFlag = NULL;
|
p->horizAdvFlag = NULL;
|
||||||
|
|
@ -1880,10 +1882,17 @@ static void nsvg__parseAttribs(NSVGparser* p, const char** attr)
|
||||||
if (strcmp(attr[i], "style") == 0) {
|
if (strcmp(attr[i], "style") == 0) {
|
||||||
nsvg__parseStyle(p, attr[i + 1]);
|
nsvg__parseStyle(p, attr[i + 1]);
|
||||||
} else if (strcmp(attr[i], "horiz-adv-x") == 0) {
|
} else if (strcmp(attr[i], "horiz-adv-x") == 0) {
|
||||||
printf("Setting defualt horiz adv to %s\n", attr[i + 1]);
|
p->image->defaultHorizAdv = strtol(attr[i+1], &end, 10);
|
||||||
p->defaultHorizAdv = strtol(attr[i+1], &end, 10);
|
if (end == attr[i+1])
|
||||||
if (end == p->defaultHorizAdv)
|
p->image->defaultHorizAdv = 0;
|
||||||
p->defaultHorizAdv = 0;
|
} else if (strcmp(attr[i], "ascent") == 0) {
|
||||||
|
p->image->fontAscent = strtol(attr[i+1], &end, 10);
|
||||||
|
if (end == attr[i+1])
|
||||||
|
p->image->fontAscent = 0;
|
||||||
|
} else if (strcmp(attr[i], "descent") == 0) {
|
||||||
|
p->image->fontDescent = strtol(attr[i+1], &end, 10);
|
||||||
|
if (end == attr[i+1])
|
||||||
|
p->image->fontDescent = 0;
|
||||||
} else {
|
} else {
|
||||||
nsvg__parseAttr(p, attr[i], attr[i + 1]);
|
nsvg__parseAttr(p, attr[i], attr[i + 1]);
|
||||||
}
|
}
|
||||||
|
|
@ -2746,11 +2755,10 @@ static void nsvg__startElement(void* ud, const char* el, const char** attr)
|
||||||
} else if (strcmp(el, "font") == 0) { // fonts are special "g" tags
|
} else if (strcmp(el, "font") == 0) { // fonts are special "g" tags
|
||||||
nsvg__pushAttr(p);
|
nsvg__pushAttr(p);
|
||||||
nsvg__parseAttribs(p, attr);
|
nsvg__parseAttribs(p, attr);
|
||||||
|
} else if (strcmp(el, "font-face") == 0) { // for the default character width
|
||||||
|
nsvg__pushAttr(p);
|
||||||
|
nsvg__parseAttribs(p, attr);
|
||||||
}
|
}
|
||||||
// } else if (strcmp(el, "missing-glyph") == 0) { // for the default character width
|
|
||||||
// nsvg__pushAttr(p);
|
|
||||||
// nsvg__parseAttribs(p, attr);
|
|
||||||
// }
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2955,7 +2963,7 @@ NSVGshape** nsvgGetTextShapes(NSVGimage* image, char* text, int textLen)
|
||||||
{
|
{
|
||||||
NSVGshape *shape = NULL;
|
NSVGshape *shape = NULL;
|
||||||
NSVGpath *path = NULL;
|
NSVGpath *path = NULL;
|
||||||
NSVGshape **shapes = malloc(sizeof(NSVGshape*)*textLen); // array of paths, text to render
|
NSVGshape **ret = malloc(sizeof(NSVGshape*)*textLen); // array of paths, text to render
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
// make list of paths representing glyphs to render
|
// make list of paths representing glyphs to render
|
||||||
|
|
@ -2964,15 +2972,16 @@ NSVGshape** nsvgGetTextShapes(NSVGimage* image, char* text, int textLen)
|
||||||
for (shape = image->shapes; shape != NULL; shape = shape->next) {
|
for (shape = image->shapes; shape != NULL; shape = shape->next) {
|
||||||
if (!(shape->flags & NSVG_FLAGS_VISIBLE))
|
if (!(shape->flags & NSVG_FLAGS_VISIBLE))
|
||||||
continue;
|
continue;
|
||||||
if (shape->unicode)
|
if (shape->unicode && shape->unicode[0] == text[i]) {
|
||||||
if (shape->unicode[0] == text[i]) {
|
ret[i] = shape;
|
||||||
shapes[i] = shape;
|
goto found;
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
found:
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return shapes;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
NSVGimage* nsvgParse(char* input, const char* units, float dpi)
|
NSVGimage* nsvgParse(char* input, const char* units, float dpi)
|
||||||
|
|
|
||||||
|
|
@ -1371,7 +1371,7 @@ void nsvgRasterizeText(NSVGrasterizer* r,
|
||||||
NSVGedge *e = NULL;
|
NSVGedge *e = NULL;
|
||||||
NSVGcachedPaint cache;
|
NSVGcachedPaint cache;
|
||||||
NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text));
|
NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text));
|
||||||
int i = 0, textLen = strlen(text);
|
int i = 0, j = 0, textLen = strlen(text);
|
||||||
|
|
||||||
r->bitmap = dst;
|
r->bitmap = dst;
|
||||||
r->width = w;
|
r->width = w;
|
||||||
|
|
@ -1381,26 +1381,38 @@ void nsvgRasterizeText(NSVGrasterizer* r,
|
||||||
if (w > r->cscanline) {
|
if (w > r->cscanline) {
|
||||||
r->cscanline = w;
|
r->cscanline = w;
|
||||||
r->scanline = (unsigned char*)realloc(r->scanline, w);
|
r->scanline = (unsigned char*)realloc(r->scanline, w);
|
||||||
if (r->scanline == NULL) return;
|
if (r->scanline == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < h; i++)
|
for (i = 0; i < h; i++)
|
||||||
memset(&dst[i*stride], 0, w*4);
|
memset(&dst[i*stride], 0, w*4);
|
||||||
|
|
||||||
for (shape = shapes[i]; i < textLen; i++) {
|
for (i = 0; i < textLen; i++) {
|
||||||
|
shape = shapes[i];
|
||||||
|
if (!shape) {
|
||||||
|
if (text[i] == ' ')
|
||||||
|
tx += font->defaultHorizAdv * scale;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (!(shape->flags & NSVG_FLAGS_VISIBLE))
|
if (!(shape->flags & NSVG_FLAGS_VISIBLE))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
if (i == 0 && strcmp(shape->id, "OpenSansRegular") == 0)
|
||||||
|
tx -= shape->horizAdvX * scale;
|
||||||
|
|
||||||
if (shape->fill.type != NSVG_PAINT_NONE) {
|
if (shape->fill.type != NSVG_PAINT_NONE) {
|
||||||
nsvg__resetPool(r);
|
nsvg__resetPool(r);
|
||||||
|
shape->fill.color = 0xffffffff;
|
||||||
r->freelist = NULL;
|
r->freelist = NULL;
|
||||||
r->nedges = 0;
|
r->nedges = 0;
|
||||||
|
|
||||||
nsvg__flattenShape(r, shape, scale);
|
nsvg__flattenShape(r, shape, scale);
|
||||||
|
|
||||||
// Scale and translate edges
|
// Scale and translate edges
|
||||||
for (i = 0; i < r->nedges; i++) {
|
for (j = 0; j < r->nedges; j++) {
|
||||||
e = &r->edges[i];
|
e = &r->edges[j];
|
||||||
e->x0 = tx + e->x0;
|
e->x0 = tx + e->x0;
|
||||||
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
|
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
|
||||||
e->x1 = tx + e->x1;
|
e->x1 = tx + e->x1;
|
||||||
|
|
@ -1425,8 +1437,8 @@ void nsvgRasterizeText(NSVGrasterizer* r,
|
||||||
// dumpEdges(r, "edge.svg");
|
// dumpEdges(r, "edge.svg");
|
||||||
|
|
||||||
// Scale and translate edges
|
// Scale and translate edges
|
||||||
for (i = 0; i < r->nedges; i++) {
|
for (j = 0; j < r->nedges; j++) {
|
||||||
e = &r->edges[i];
|
e = &r->edges[j];
|
||||||
e->x0 = tx + e->x0;
|
e->x0 = tx + e->x0;
|
||||||
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
|
e->y0 = (ty + e->y0) * NSVG__SUBSAMPLES;
|
||||||
e->x1 = tx + e->x1;
|
e->x1 = tx + e->x1;
|
||||||
|
|
@ -1441,10 +1453,13 @@ void nsvgRasterizeText(NSVGrasterizer* r,
|
||||||
|
|
||||||
nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
|
nsvg__rasterizeSortedEdges(r, tx,ty,scale, &cache, NSVG_FILLRULE_NONZERO);
|
||||||
}
|
}
|
||||||
|
tx += shape->horizAdvX * scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
nsvg__unpremultiplyAlpha(dst, w, h, stride);
|
nsvg__unpremultiplyAlpha(dst, w, h, stride);
|
||||||
|
|
||||||
|
free(shapes);
|
||||||
|
|
||||||
r->bitmap = NULL;
|
r->bitmap = NULL;
|
||||||
r->width = 0;
|
r->width = 0;
|
||||||
r->height = 0;
|
r->height = 0;
|
||||||
|
|
|
||||||
|
|
@ -123,11 +123,11 @@ static void drawPath(float *pts, int npts, int xoff, int yoff, float scale_x, fl
|
||||||
// scaled based on the target width and height.
|
// scaled based on the target width and height.
|
||||||
static void draw_svg(NSVGimage *image, int x, int y, int width, int height)
|
static void draw_svg(NSVGimage *image, int x, int y, int width, int height)
|
||||||
{
|
{
|
||||||
fprintf(stdout, "size: %f x %f\n", image->width, image->height);
|
//fprintf(stdout, "size: %f x %f\n", image->width, image->height);
|
||||||
float sz = (float)width / image->width;
|
float sz = (float)width / image->width;
|
||||||
int w = image->width * sz + 0.5;
|
int w = image->width * sz + 0.5;
|
||||||
int h = image->height * sz + 0.5;
|
int h = image->height * sz + 0.5;
|
||||||
fprintf(stdout, "scale: %f\n", sz);
|
//fprintf(stdout, "scale: %f\n", sz);
|
||||||
|
|
||||||
NSVGrasterizer *rast = nsvgCreateRasterizer();
|
NSVGrasterizer *rast = nsvgCreateRasterizer();
|
||||||
unsigned char *img = malloc(w * h * 4);
|
unsigned char *img = malloc(w * h * 4);
|
||||||
|
|
@ -145,73 +145,78 @@ static void draw_svg(NSVGimage *image, int x, int y, int width, int height)
|
||||||
free(img);
|
free(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void draw_text(NSVGimage *font, char *text, int x, int y, float scale)
|
static void getTextDimensions(NSVGimage *font, char *text, float scale, int *width, int *height)
|
||||||
{
|
{
|
||||||
int width, height = 200;
|
int i = 0;
|
||||||
printf("text: %s\n", text);
|
|
||||||
|
*width = 0;
|
||||||
|
*height = (font->fontAscent - font->fontDescent) * scale;
|
||||||
NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text));
|
NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text));
|
||||||
for (size_t i = 0; i < strlen(text); i++)
|
for (size_t i = 0; i < strlen(text); i++)
|
||||||
{
|
{
|
||||||
width += shapes[i]->horizAdvX * scale + 1;
|
NSVGshape *shape = shapes[i];
|
||||||
|
if (shape) {
|
||||||
|
*width += shapes[i]->horizAdvX * scale + 1;
|
||||||
|
} else {
|
||||||
|
*width += font->defaultHorizAdv * scale;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void draw_text(NSVGimage *font, char *text, int x, int y, int width, int height, float scale)
|
||||||
|
{
|
||||||
|
//printf("text: %s, scale: %f, x: %d, y: %d\n", text, scale, x, y);
|
||||||
|
NSVGshape **shapes = nsvgGetTextShapes(font, text, strlen(text));
|
||||||
unsigned char *img = malloc(width * height * 4);
|
unsigned char *img = malloc(width * height * 4);
|
||||||
NSVGrasterizer *rast = nsvgCreateRasterizer();
|
NSVGrasterizer *rast = nsvgCreateRasterizer();
|
||||||
|
|
||||||
printf("text dimensions: %d x %d\n", width, height);
|
//printf("text dimensions: %d x %d\n", width, height);
|
||||||
|
|
||||||
nsvgRasterize(rast, font, 0, 0, scale, img, width, height, width * 4);
|
nsvgRasterizeText(rast, font, 0, 0, scale, img, width, height, width * 4, text);
|
||||||
|
|
||||||
for (size_t i = 0; i < width; i++)
|
for (size_t i = 0; i < width; i++)
|
||||||
{
|
{
|
||||||
for (size_t j = 0; j < height; j++)
|
for (size_t j = 0; j < height; j++)
|
||||||
{
|
{
|
||||||
unsigned int col = tfb_make_color(img[(j * width + i) * 4 + 0], img[(j * width + i) * 4 + 1], img[(j * width + i) * 4 + 2]);
|
unsigned int col = tfb_make_color(img[(j * width + i) * 4 + 0], img[(j * width + i) * 4 + 1], img[(j * width + i) * 4 + 2]);
|
||||||
tfb_draw_pixel(x + i, y - j, col);
|
tfb_draw_pixel(x + i, y + height - j, col);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
free(img);
|
free(img);
|
||||||
|
free(shapes);
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
int rc = 0;
|
int rc = 0;
|
||||||
int opt;
|
int opt;
|
||||||
char *message = calloc(MSG_MAX_LEN, 1);
|
char *message;
|
||||||
|
char *logoText = "postmarketOS";
|
||||||
char *splash_image;
|
char *splash_image;
|
||||||
NSVGimage *image;
|
NSVGimage *image;
|
||||||
NSVGimage *font;
|
NSVGimage *font;
|
||||||
|
int textWidth, textHeight;
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++)
|
for (int i = 1; i < argc; i++)
|
||||||
{
|
{
|
||||||
printf("%d: %s\n", i, argv[i]);
|
|
||||||
if (strcmp(argv[i], "-h") == 0)
|
if (strcmp(argv[i], "-h") == 0)
|
||||||
{
|
{
|
||||||
rc = usage();
|
rc = usage();
|
||||||
goto out;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(argv[i], "-s") == 0 && i + 1 < argc)
|
if (strcmp(argv[i], "-s") == 0 && i + 1 < argc)
|
||||||
{
|
{
|
||||||
splash_image = argv[i + 1];
|
splash_image = argv[i + 1];
|
||||||
printf("splash_image path: %s\n", splash_image);
|
//printf("splash_image path: %s\n", splash_image);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strcmp(argv[i], "-m") == 0)
|
if (strcmp(argv[i], "-m") == 0)
|
||||||
{
|
{
|
||||||
if (*argv[i + 1] == '-')
|
message = argv[i + 1];
|
||||||
{
|
|
||||||
rc = read(STDIN_FILENO, message, MSG_MAX_LEN);
|
|
||||||
if (rc < 0)
|
|
||||||
goto out;
|
|
||||||
printf("%s\n", message);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
free(message);
|
|
||||||
message = argv[i + 1];
|
|
||||||
}
|
|
||||||
printf("message: %s\n", message);
|
printf("message: %s\n", message);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -221,55 +226,58 @@ int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "tfb_acquire_fb() failed with error code: %d\n", rc);
|
fprintf(stderr, "tfb_acquire_fb() failed with error code: %d\n", rc);
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto out;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
||||||
int w = (int)tfb_screen_width();
|
int w = (int)tfb_screen_width();
|
||||||
int h = (int)tfb_screen_height();
|
int h = (int)tfb_screen_height();
|
||||||
float sz = (float)(w < h ? w : h) * 0.5f;
|
float sz = (float)(w < h ? w : h) * 0.5f;
|
||||||
fprintf(stdout, "w=%du, h=%du\n", w, h);
|
//fprintf(stdout, "w=%du, h=%du\n", w, h);
|
||||||
float x = (float)w / 2 - sz / 2;
|
float x = (float)w / 2 - sz / 2;
|
||||||
float y = (float)h / 2 - sz / 2 - 300;
|
float y = (float)h / 2 - sz / 2 - 300;
|
||||||
fprintf(stdout, "x=%f, y=%f, sz=%f\n", x, y, sz);
|
//fprintf(stdout, "x=%f, y=%f, sz=%f\n", x, y, sz);
|
||||||
|
|
||||||
image = nsvgParseFromFile(splash_image, "px", 96);
|
image = nsvgParseFromFile(splash_image, "px", 96);
|
||||||
if (!image)
|
if (!image)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "failed to load SVG image\n");
|
fprintf(stderr, "failed to load SVG image\n");
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto out;
|
return rc;
|
||||||
}
|
}
|
||||||
font = nsvgParseFromFile(FONT_PATH, "px", 500);
|
font = nsvgParseFromFile(FONT_PATH, "px", 500);
|
||||||
if (!font || !font->shapes)
|
if (!font || !font->shapes)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "failed to load SVG font\n");
|
fprintf(stderr, "failed to load SVG font\n");
|
||||||
rc = 1;
|
rc = 1;
|
||||||
goto out;
|
goto free_image;
|
||||||
}
|
}
|
||||||
float fontsz = 0.05f;
|
|
||||||
fprintf(stdout, "font size: %f\n", fontsz);
|
|
||||||
|
|
||||||
/* Paint the whole screen in black */
|
/* Paint the whole screen in black */
|
||||||
tfb_clear_screen(tfb_black);
|
tfb_clear_screen(tfb_black);
|
||||||
/* Draw some text on-screen */
|
|
||||||
tfb_draw_string_scaled(x + 75, y + sz + 40, tfb_white, tfb_black, 4, 4, "postmarketOS");
|
|
||||||
|
|
||||||
if (message)
|
|
||||||
{
|
|
||||||
tfb_draw_string_scaled_wrapped(50, (int)((float)h * 0.6), tfb_white, tfb_black, 2, 2, 80, message);
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_svg(image, x, y, sz, sz);
|
draw_svg(image, x, y, sz, sz);
|
||||||
|
|
||||||
draw_text(font, "postmarketOS", 100, h / 2.f + 100, fontsz);
|
float fontsz = (sz * 0.25) / (font->fontAscent - font->fontDescent);
|
||||||
|
//fprintf(stdout, "font size: %f\n", fontsz);
|
||||||
|
|
||||||
|
getTextDimensions(font, logoText, fontsz, &textWidth, &textHeight);
|
||||||
|
|
||||||
|
draw_text(font, logoText, w / 2.f - textWidth / 2.f, y + sz + sz*0.2, textWidth, textHeight, fontsz);
|
||||||
|
|
||||||
|
fontsz = (sz * 0.1) / (font->fontAscent - font->fontDescent);
|
||||||
|
|
||||||
|
getTextDimensions(font, message, fontsz, &textWidth, &textHeight);
|
||||||
|
|
||||||
|
draw_text(font, message, w / 2.f - textWidth / 2.f, y + sz * 2, textWidth, textHeight, fontsz);
|
||||||
|
printf("Rendered text: %s\n", message);
|
||||||
|
|
||||||
tfb_flush_window();
|
tfb_flush_window();
|
||||||
tfb_flush_fb();
|
tfb_flush_fb();
|
||||||
|
|
||||||
sleep(20);
|
//sleep(20);
|
||||||
out:
|
out:
|
||||||
|
nsvgDelete(font);
|
||||||
|
free_image:
|
||||||
nsvgDelete(image);
|
nsvgDelete(image);
|
||||||
tfb_release_fb();
|
|
||||||
free(message);
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue