On 5.12.20 г. 1:31 ч., Steven Rostedt wrote:
On Fri, 20 Nov 2020 11:50:28 +0200 "Yordan Karadzhov (VMware)" <y.karadz@xxxxxxxxx> wrote:OpenGL doesn't provide support for text rendering. Here we first re-enable the compilation of the OpenGL wrapper and add the capability of printing text to the OpenGL scene by using the single-file public domain library "stb_truetype": https://github.com/nothings/stb/blob/master/stb_truetype.h Signed-off-by: Yordan Karadzhov (VMware) <y.karadz@xxxxxxxxx> --- CMakeLists.txt | 6 +- Documentation/doxygen/dox_config | 1 + src/CMakeLists.txt | 4 +- src/libkshark-plot.c | 244 +- src/libkshark-plot.h | 57 + src/stb_truetype.h | 5011 ++++++++++++++++++++++++++++++ 6 files changed, 5312 insertions(+), 11 deletions(-) create mode 100644 src/stb_truetype.h diff --git a/CMakeLists.txt b/CMakeLists.txt index ccca95c1..3d179778 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -26,9 +26,9 @@ include(${KS_DIR}/build/FindJSONC.cmake)find_package(Doxygen) -# set(OpenGL_GL_PREFERENCE LEGACY)-# find_package(OpenGL) -# find_package(GLUT) +set(OpenGL_GL_PREFERENCE LEGACY) +find_package(OpenGL) +find_package(GLUT)# find_package(Qt5Widgets 5.7.1)# find_package(Qt5Network) diff --git a/Documentation/doxygen/dox_config b/Documentation/doxygen/dox_config index 89b92842..0bbeb3f0 100644 --- a/Documentation/doxygen/dox_config +++ b/Documentation/doxygen/dox_config @@ -14,3 +14,4 @@ SORT_MEMBER_DOCS = NO STRICT_PROTO_MATCHING = YES DOT_MULTI_TARGETS = YES PROJECT_LOGO = ../../icons/KS_logo_stacked.svg +EXCLUDE = ../../src/stb_truetype.h diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ae5de54d..3a07d824 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -22,8 +22,8 @@ install(TARGETS kshark LIBRARY DESTINATION ${_LIBDIR}/${KS_APP_NAME}) if (OPENGL_FOUND AND GLUT_FOUND)message(STATUS "libkshark-plot")- add_library(kshark-plot SHARED libkshark-plot.c - KsPlotTools.cpp) + add_library(kshark-plot SHARED libkshark-plot.c) +# KsPlotTools.cpp)target_link_libraries(kshark-plot kshark${GLUT_LIBRARY} diff --git a/src/libkshark-plot.c b/src/libkshark-plot.c index 17d3b903..06483334 100644 --- a/src/libkshark-plot.c +++ b/src/libkshark-plot.c @@ -1,13 +1,22 @@ /* SPDX-License-Identifier: LGPL-2.1 *//*- * Copyright (C) 2018 VMware Inc, Yordan Karadzhov <y.karadz@xxxxxxxxx> + * Copyright (C) 2018 VMware Inc, Yordan Karadzhov (VMware) <y.karadz@xxxxxxxxx> */- /**- * @file libkshark-plot.c - * @brief Basic tools for OpenGL plotting. - */ +/** + * @file libkshark-plot.c + * @brief Basic tools for OpenGL plotting. + */ + +// C +#ifndef _GNU_SOURCE +/** Use GNU C Library. */ +#define _GNU_SOURCE +#endif // _GNU_SOURCE + +#include <string.h> +#include <stdio.h>// OpenGL#include <GL/freeglut.h> @@ -16,6 +25,17 @@ // KernelShark #include "libkshark-plot.h"+/*+ * STB TrueType (single-file public domain library) + * https://github.com/nothings/stb + */ +/** Generate implementation. */ +#define STB_TRUETYPE_IMPLEMENTATION + +/** Make the implementation private. */ +#define STBTT_STATIC +#include "stb_truetype.h" + /** * @brief Create an empty scene for drawing. * @@ -66,7 +86,7 @@ void ksplot_init_opengl(int dpr) glEnable(GL_POLYGON_SMOOTH); glLineWidth(1.5 * dpr); glPointSize(2.5 * dpr); - glClearColor(1, 1, 1, 1); + glClearColor(1, 1, 1, 1); // White }/**@@ -210,3 +230,215 @@ void ksplot_draw_polygon_contour(const struct ksplot_point *points, col, size); } + +/** + * @brief Find a TrueType font file. + * + * @param font_family: The family name of the font. + * @param font_name: The name of the font file without the extention. + * + * @returns A string containing the absolute path to the TrueType font file + * on success, or NULL on failure. The user is responsible for freeing + * the string. + */ +char *ksplot_find_font_file(const char *font_family, const char *font_name) +{ + char buffer[1024], *end; + char *cmd = NULL; + int ret; + FILE *f; + + ret = asprintf(&cmd, "fc-list \'%s\' |grep %s.ttf", font_family, + font_name);This is sorta a hack, but for now we can keep it and improve it later, as it is wrapped in this function. Perhaps add a comment /* FIXME: Do this a bit more properly */
OK, I will add the comment.
+ if (ret <= 0) + goto fail; + + f = popen(cmd, "r"); + free(cmd); + if (f == NULL) + goto fail; + + end = fgets(buffer, sizeof(buffer), f); + pclose(f); + if (!end) + goto fail; + + end = strchr(buffer, ':'); + if (!end) + goto fail; + + return strndup(buffer, end - buffer); + + fail: + fprintf(stderr, "Failed to find font file.\n" ); + return NULL; +} + +/** The size of the bitmap matrix used to load the font. */ +#define KS_FONT_BITMAP_SIZE 1024 + +/** + * @brief Initialize a font. + * + * @param font: Output location for the font descriptor. + * @param size: The size of the font. + * @param file: Input location for the truetype font file. + */ +bool ksplot_init_font(struct ksplot_font *font, float size, const char *file) +{ + unsigned char bitmap[KS_FONT_BITMAP_SIZE * KS_FONT_BITMAP_SIZE]; + int ascent, descent, line_gap, lsb; + ssize_t buff_size, ret; + unsigned char *buffer; + stbtt_fontinfo info; + FILE *font_file; + float scale; + + font_file = fopen(file, "rb"); + if (!font_file) { + fprintf(stderr, "Failed to open font file!\n"); + return false; + } + + /* Get the size of the file. */ + fseek(font_file, 0, SEEK_END); + buff_size = ftell(font_file);I would use stat(2) to find the file size.
I will fix this, thanks!
+ fseek(font_file, 0, SEEK_SET); + + buffer = malloc(buff_size); + if (!buffer) { + fprintf(stderr, "Failed to allocat memory for font!\n"); + goto close_file; + } + + ret = fread(buffer, buff_size, 1, font_file); + fclose(font_file); + + if (ret == 0) { + fprintf(stderr, "Failed to read from font file!\n"); + goto free_buffer; + } + + if (!stbtt_InitFont(&info, buffer, 0)) { + fprintf(stderr, "Failed to init font!\n"); + goto free_buffer; + } + + /* Get the font's metrics. */ + scale = stbtt_ScaleForMappingEmToPixels(&info, size); + stbtt_GetFontVMetrics(&info, &ascent, &descent, &line_gap); + if (line_gap == 0) + line_gap = - descent; + /* + * Calculate the dimensions of the font. Note that the descent has + * a negative value. + */ + font->height = (- descent + ascent + line_gap) * scale; + font->base = (- descent + line_gap / 2) * scale; + font->size = size; + + /* + * The width of the 'z' character will be considered as an average + * character width. + */ + stbtt_GetCodepointHMetrics(&info, 'z', &font->char_width, &lsb); + font->char_width *= scale; + + ret = stbtt_BakeFontBitmap(buffer, + 0, + size, + bitmap, + KS_FONT_BITMAP_SIZE, + KS_FONT_BITMAP_SIZE, + KS_SPACE_CHAR, + KS_N_CHAR, + font->cdata); + + if (ret <= 0) { + fprintf(stderr, "Failed to bake font bitmap!\n"); + goto free_buffer; + } + + free(buffer); + + glGenTextures(1, &font->texture_id); + glBindTexture(GL_TEXTURE_2D, font->texture_id); + + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_ALPHA, + KS_FONT_BITMAP_SIZE, + KS_FONT_BITMAP_SIZE, + 0, + GL_ALPHA, + GL_UNSIGNED_BYTE, + bitmap); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); +I don't really understand any of the above, so I'm assuming you know what it is doing ;-)
;-)
+ return true; + + close_file: + fclose(font_file); + + free_buffer: + free(buffer); + return false; +} + +/** + * @brief Print(draw) a text. + * + * @param font: Intput location for the font descriptor. + * @param col: The color of the polygon. + * @param x: Horizontal coordinate of the beginning of the text. + * @param y: Verticalal coordinate of the beginning of the text. + * @param text: The text to be drawn. + */ +void ksplot_print_text(const struct ksplot_font *font, + const struct ksplot_color *col, + float x, float y, + const char *text) +{ + glEnable(GL_TEXTURE_2D); + + /* Set the color of the text. */ + if (col) + glColor3ub(col->red, col->green, col->blue); + else + glColor3ub(0, 0, 0); // Black + + glBindTexture(GL_TEXTURE_2D, font->texture_id); + glBegin(GL_QUADS); + for (; *text; ++text) { + if (*text < KS_SPACE_CHAR && *text > KS_TILDA_CHAR) + continue; + + stbtt_aligned_quad quad; + stbtt_GetBakedQuad(font->cdata, + KS_FONT_BITMAP_SIZE, + KS_FONT_BITMAP_SIZE, + *text - KS_SPACE_CHAR, + &x, &y, + &quad, + 1); + + glTexCoord2f(quad.s0, quad.t1); + glVertex2f(quad.x0, quad.y1); + + glTexCoord2f(quad.s1, quad.t1); + glVertex2f(quad.x1, quad.y1); + + glTexCoord2f(quad.s1, quad.t0); + glVertex2f(quad.x1, quad.y0); + + glTexCoord2f(quad.s0, quad.t0); + glVertex2f(quad.x0, quad.y0);How is the x and y moved to the next location?
Actually the "y" does not change at all here, because for the moment we can't draw multi-line text. "x" gets incremented inside stbtt_GetBakedQuad(). The horizontal advance of the character is used to calculate the new position.
Thanks a lot! Yordan
+ } + + glEnd(); + glDisable(GL_TEXTURE_2D); +} diff --git a/src/libkshark-plot.h b/src/libkshark-plot.h index 9a4dbc02..0edf5d50 100644 --- a/src/libkshark-plot.h +++ b/src/libkshark-plot.h @@ -12,6 +12,15 @@ #ifndef _LIB_KSHARK_PLOT_H #define _LIB_KSHARK_PLOT_H+// C+#include <stdbool.h> + +/* + * STB TrueType (single-file public domain library) + * https://github.com/nothings/stb + */ +#include "stb_truetype.h" + #ifdef __cplusplus extern "C" { #endif @@ -62,6 +71,54 @@ void ksplot_draw_polygon_contour(const struct ksplot_point *points, const struct ksplot_color *col, float size);+/** The index of the "Space" character. */+#define KS_SPACE_CHAR 32 + +/** The index of the "Tilda" character. */ +#define KS_TILDA_CHAR 126 + +/** Total number of characters supported for drawing. */ +#define KS_N_CHAR (KS_TILDA_CHAR - KS_SPACE_CHAR + 1) + +/** Structure defining a font. */ +struct ksplot_font { + /** Identifier of the font's texture. */ + GLuint texture_id; + + /** Font's texture baking data. */ + stbtt_bakedchar cdata[KS_N_CHAR]; + + /** The height of a text line. */ + int height; + + /** The vertical position of the font's baseline. */ + int base; + + /** The size of the font. */ + int size; + + /** + * The width of the 'z' character. To be use as an average character + * width. + */ + int char_width; +}; + +/** Check if the texture of the font is loaded. */ +static inline bool ksplot_font_is_loaded(struct ksplot_font *f) +{ + return f->texture_id > 1; +} + +char *ksplot_find_font_file(const char *font_family, const char *font_name); + +bool ksplot_init_font(struct ksplot_font *font, float size, const char *file); + +void ksplot_print_text(const struct ksplot_font *font, + const struct ksplot_color *col, + float x, float y, + const char *text); + #ifdef __cplusplus } #endif diff --git a/src/stb_truetype.h b/src/stb_truetype.h new file mode 100644 index 00000000..62595a15 --- /dev/null +++ b/src/stb_truetype.hI'm assuming the rest is what you took from public domain?@@ -0,0 +1,5011 @@ +// stb_truetype.h - v1.24 - public domain +// authored from 2009-2020 by Sean Barrett / RAD Game Tools +// +// ======================================================================= +// +// NO SECURITY GUARANTEE -- DO NOT USE THIS ON UNTRUSTED FONT FILES +// +// This library does no range checking of the offsets found in the file, +// meaning an attacker can use it to read arbitrary memory. +// +// ======================================================================= +// +// This library processes TrueType files: +// parse files +// extract glyph metrics +// extract glyph shapes +// render glyphs to one-channel bitmaps with antialiasing (box filter) +// render glyphs to one-channel SDF bitmaps (signed-distance field/function) +// +// Todo: +// non-MS cmaps +// crashproof on bad data +// hinting? (no longer patented) +// cleartype-style AA? +// optimize: use simple memory allocator for intermediates +// optimize: build edge-list directly from curves +// optimize: rasterize directly from curves? +// +// ADDITIONAL CONTRIBUTORS +// +// Mikko Mononen: compound shape support, more cmap formats +// Tor Andersson: kerning, subpixel rendering +// Dougall Johnson: OpenType / Type 2 font handling +// Daniel Ribeiro Maciel: basic GPOS-based kerning[..]