Re: [PATCH 1/4] kernel-shark: Add support for drawing text

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 





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.h

I'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

[..]




[Index of Archives]     [Linux USB Development]     [Linux USB Development]     [Linux Audio Users]     [Yosemite Hiking]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux