* new rendering system for volatile text

(symbols rendered to atlas texture)
deliver position via glRasterPos + glGet GL_CURRENT_RASTER_POSITION to avoid adding calculations of screen coords in many spots
solves problem: pango 1.44 switch freetype->harfbuzz = bitmap fonts aren't available, in particular no gdk_gl_font_use_pango_font()
text is rendered from font bottom (was from baseline)(latter is wanted less often)
wgl bitmap<->pango sizes do not match, thus realign all text positions, increase default font size
make 2D axes labels, view type text, sizing info adaptive to font size
#24
fixes #42
This commit is contained in:
Garux
2020-05-14 07:51:34 +03:00
parent 33f7e66b87
commit a0a47640b0
6 changed files with 178 additions and 56 deletions

View File

@@ -93,25 +93,62 @@ void gray_to_texture( const unsigned int x_max, const unsigned int y_max, const
class GLFontCallList final : public GLFont
{
GLuint m_displayList;
GLuint m_atlas;
int m_pixelHeight;
int m_pixelAscent;
int m_pixelDescent;
PangoFontMap *m_fontmap;
PangoContext *m_ft2_context;
public:
GLFontCallList( GLuint displayList, int asc, int desc, int pixelHeight, PangoFontMap *fontmap, PangoContext *ft2_context ) :
m_displayList( displayList ), m_pixelHeight( pixelHeight ), m_pixelAscent( asc ), m_pixelDescent( desc ), m_fontmap( fontmap ), m_ft2_context( ft2_context ){
GLFontCallList( GLuint displayList, GLuint atlas, int asc, int desc, int pixelHeight, PangoFontMap *fontmap, PangoContext *ft2_context ) :
m_displayList( displayList ), m_atlas( atlas ), m_pixelHeight( pixelHeight ), m_pixelAscent( asc ), m_pixelDescent( desc ), m_fontmap( fontmap ), m_ft2_context( ft2_context ){
}
~GLFontCallList(){
glDeleteLists( m_displayList, 256 );
glDeleteLists( m_displayList, 128 );
glDeleteTextures( 1, &m_atlas );
if( m_ft2_context )
g_object_unref( G_OBJECT( m_ft2_context ) );
if( m_fontmap )
g_object_unref( G_OBJECT( m_fontmap ) );
}
void printString( const char *s ){
GLboolean rasterPosValid;
glGetBooleanv( GL_CURRENT_RASTER_POSITION_VALID, &rasterPosValid );
if( !rasterPosValid )
return;
GLfloat rasterPos[4];
glGetFloatv( GL_CURRENT_RASTER_POSITION, rasterPos );
GLint viewport[4];
glGetIntegerv( GL_VIEWPORT, viewport );
glMatrixMode( GL_PROJECTION );
glPushMatrix();
glLoadIdentity();
glOrtho( viewport[0], viewport[2], viewport[1], viewport[3], -1, 1 );
glMatrixMode( GL_MODELVIEW );
glPushMatrix();
glLoadIdentity();
glTranslatef( rasterPos[0], rasterPos[1], 0 );
glPushAttrib( GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT | GL_POLYGON_BIT );
glDisable( GL_LIGHTING );
glEnable( GL_TEXTURE_2D );
glDisable( GL_DEPTH_TEST );
glEnable( GL_BLEND );
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glBindTexture( GL_TEXTURE_2D, m_atlas );
GlobalOpenGL().m_glListBase( m_displayList );
GlobalOpenGL().m_glCallLists( GLsizei( strlen( s ) ), GL_UNSIGNED_BYTE, reinterpret_cast<const GLubyte*>( s ) );
glPopAttrib();
glMatrixMode( GL_PROJECTION );
glPopMatrix();
glMatrixMode( GL_MODELVIEW ); //! must leave GL_MODELVIEW mode, as renderer relies on this during Renderer.render()
glPopMatrix();
}
void renderString( const char *s, const GLuint& tex, const unsigned char colour[3], unsigned int& wid, unsigned int& hei ){
@@ -669,55 +706,53 @@ GLFont *glfont_create( const char* font_string ){
#include <pango/pangoft2.h>
#include <pango/pango-utils.h>
#include <gtk/gtkglwidget.h>
#include <gtk/gtksettings.h>
PangoFont* tryFont( const char* font_string, PangoFontDescription*& font_desc, GLuint font_list_base ){
PangoFont* tryFont( const char* font_string, PangoFontMap *fontmap, PangoContext *context, PangoFontDescription*& font_desc ){
pango_font_description_free( font_desc );
font_desc = pango_font_description_from_string( font_string );
return gdk_gl_font_use_pango_font( font_desc, 0, 256, font_list_base );
return pango_font_map_load_font( fontmap, context, font_desc );
}
GLFont *glfont_create( const char* font_string ){
GLuint font_list_base = glGenLists( 256 );
GLuint font_list_base = glGenLists( 128 );
int font_height = 0, font_ascent = 0, font_descent = 0;
PangoFontDescription* font_desc = 0;
PangoFont* font = 0;
PangoFontMap *fontmap = pango_ft2_font_map_new();
pango_ft2_font_map_set_resolution( PANGO_FT2_FONT_MAP( fontmap ), 72, 72 );
PangoContext *ft2_context = pango_font_map_create_context( fontmap );
do
{
if( *font_string != '\0' )
if( ( font = tryFont( font_string, font_desc, font_list_base ) ) )
if( ( font = tryFont( font_string, fontmap, ft2_context, font_desc ) ) )
break;
#ifdef WIN32
if( ( font = tryFont( "arial 8", font_desc, font_list_base ) ) )
if( ( font = tryFont( "arial 12", fontmap, ft2_context, font_desc ) ) )
break;
if( ( font = tryFont( "fixed 8", font_desc, font_list_base ) ) )
if( ( font = tryFont( "fixed 12", fontmap, ft2_context, font_desc ) ) )
break;
if( ( font = tryFont( "courier new 8", font_desc, font_list_base ) ) )
if( ( font = tryFont( "courier new 12", fontmap, ft2_context, font_desc ) ) )
break;
#endif
GtkSettings *settings = gtk_settings_get_default();
gchar *fontname;
g_object_get( settings, "gtk-font-name", &fontname, NULL );
font = tryFont( fontname, font_desc, font_list_base );
font = tryFont( fontname, fontmap, ft2_context, font_desc );
g_free( fontname );
if( !font ){
const char* guessFonts[] = { "serif 8", "sans 8", "clean 8", "courier 8", "helvetica 8", "arial 8", "dejavu sans 8" };
const char* guessFonts[] = { "serif 12", "sans 12", "clean 12", "courier 12", "helvetica 12", "arial 12", "dejavu sans 12" };
for( const auto str : guessFonts ){
if( ( font = tryFont( str, font_desc, font_list_base ) ) )
if( ( font = tryFont( str, fontmap, ft2_context, font_desc ) ) )
break;
}
}
} while ( 0 );
PangoFontMap *fontmap = 0;
PangoContext *ft2_context = 0;
if ( font != 0 ) {
fontmap = pango_ft2_font_map_new();
pango_ft2_font_map_set_resolution( PANGO_FT2_FONT_MAP( fontmap ), 72, 72 );
ft2_context = pango_font_map_create_context( fontmap );
pango_context_set_font_description( ft2_context, font_desc );
PangoLayout *layout = pango_layout_new( ft2_context );
@@ -732,13 +767,6 @@ GLFont *glfont_create( const char* font_string ){
g_object_unref( G_OBJECT( layout ) );
int font_descent_pango_units = log_rect.height - font_ascent_pango_units;
/* settings for render to tex; need to multiply size, so that bitmap callLists way size would be approximately = texture way */
gint fontsize = pango_font_description_get_size( font_desc );
fontsize *= 3;
fontsize /= 2; //*15/11 is equal to bitmap callLists size
pango_font_description_set_size( font_desc, fontsize );
pango_context_set_font_description( ft2_context, font_desc );
// globalOutputStream() << pango_font_description_get_family( font_desc ) << " " << pango_font_description_get_size( font_desc ) << "\n";
// g_object_unref( G_OBJECT( ft2_context ) );
@@ -748,12 +776,103 @@ GLFont *glfont_create( const char* font_string ){
font_descent = PANGO_PIXELS_CEIL( font_descent_pango_units );
font_height = font_ascent + font_descent;
}
/* render displaylists */
GLuint atlas;
if ( font != 0 ) {
PangoLayout *layout;
PangoRectangle log_rect;
FT_Bitmap bitmap;
layout = pango_layout_new( ft2_context );
pango_layout_set_width( layout, -1 ); // -1 no wrapping. All text on one line.
GLint alignment;
glGetIntegerv( GL_UNPACK_ALIGNMENT, &alignment );
glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
glGenTextures( 1, &atlas );
//Now we just setup some texture paramaters.
glBindTexture( GL_TEXTURE_2D, atlas );
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_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0 );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0 );
//Here we actually create the texture itself
glTexImage2D( GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, font_height * 12, font_height * 12, // riskily assuming, that height >= max width
0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, 0 );
for( unsigned char c = 0; c < 128; ++c ){
pango_layout_set_text( layout, reinterpret_cast<const char*>( &c ), 1 );
pango_layout_get_extents( layout, NULL, &log_rect );
if ( log_rect.width > 0 && log_rect.height > 0 ) {
bitmap.rows = PANGO_PIXELS_CEIL( log_rect.height );
bitmap.width = PANGO_PIXELS_CEIL( log_rect.width );
bitmap.pitch = bitmap.width;
unsigned char *boo = (unsigned char *) malloc( bitmap.rows * bitmap.width );
memset( boo, 0, bitmap.rows * bitmap.width );
bitmap.buffer = boo;
bitmap.num_grays = 0xff;
bitmap.pixel_mode = FT_PIXEL_MODE_GRAY;
pango_ft2_render_layout_subpixel( &bitmap, layout, -log_rect.x, 0 );
/* convert grayscale byte per pixel to two bytes per pixel (white + alpha) */
unsigned char *buf = (unsigned char *) malloc( bitmap.rows * bitmap.width * 2 );
for( unsigned int i = 0; i < bitmap.rows * bitmap.width; ++i ){
buf[i * 2] = 255;
buf[i * 2 + 1] = boo[i];
}
glTexSubImage2D( GL_TEXTURE_2D,
0,
c % 12 * font_height,
c / 12 * font_height,
bitmap.width,
bitmap.rows,
GL_LUMINANCE_ALPHA,
GL_UNSIGNED_BYTE,
buf );
glNewList( font_list_base + c, GL_COMPILE );
glBegin( GL_QUADS );
const float x0 = 0;
const float x1 = bitmap.width + .01f;
const float y0 = 0;
const float y1 = bitmap.rows + .01f;
const float tx0 = ( c % 12 ) / 12.f;
const float tx1 = ( c % 12 + static_cast<float>( bitmap.width ) / font_height ) / 12.f;
const float ty0 = ( c / 12 ) / 12.f;
const float ty1 = ( c / 12 + static_cast<float>( bitmap.rows ) / font_height ) / 12.f;
glTexCoord2f( tx0, ty1 );
glVertex2f( x0, y0 );
glTexCoord2f( tx0, ty0 );
glVertex2f( x0, y1 );
glTexCoord2f( tx1, ty0 );
glVertex2f( x1, y1 );
glTexCoord2f( tx1, ty1 );
glVertex2f( x1, y0 );
glEnd();
glTranslatef( bitmap.width, 0, 0 );
glEndList();
free( boo );
free( buf );
}
}
glPixelStorei( GL_UNPACK_ALIGNMENT, alignment );
g_object_unref( G_OBJECT( layout ) );
}
pango_font_description_free( font_desc );
ASSERT_MESSAGE( font != 0, "font for OpenGL rendering was not created" );
return new GLFontCallList( font_list_base, font_ascent, font_descent, font_height, fontmap, ft2_context );
return new GLFontCallList( font_list_base, atlas, font_ascent, font_descent, font_height, fontmap, ft2_context );
}