Initial support for bitmap fonts (OpenGL GAL).

This commit is contained in:
Maciej Suminski 2016-05-02 16:04:45 +02:00
parent 431e343201
commit bda3011519
18 changed files with 23050 additions and 12 deletions

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -27,6 +27,7 @@
*/
#include <gal/opengl/opengl_gal.h>
#include <gal/opengl/utils.h>
#include <gal/definitions.h>
#include <macros.h>
@ -41,11 +42,15 @@
using namespace KIGFX;
#include "bitmap_font_img.c"
#include "bitmap_font_desc.c"
static void InitTesselatorCallbacks( GLUtesselator* aTesselator );
static const int glAttributes[] = { WX_GL_RGBA, WX_GL_DOUBLEBUFFER, WX_GL_DEPTH_SIZE, 8, 0 };
wxGLContext* OPENGL_GAL::glContext = NULL;
int OPENGL_GAL::instanceCounter = 0;
bool OPENGL_GAL::isBitmapFontLoaded = false;
OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
wxEvtHandler* aPaintListener, const wxString& aName ) :
@ -71,6 +76,7 @@ OPENGL_GAL::OPENGL_GAL( wxWindow* aParent, wxEvtHandler* aMouseListener,
// Initialize the flags
isFramebufferInitialized = false;
isBitmapFontInitialized = false;
isGrouping = false;
groupCounter = 0;
@ -125,7 +131,11 @@ OPENGL_GAL::~OPENGL_GAL()
if( --instanceCounter == 0 )
{
glDeleteTextures( 1, &fontTexture );
isBitmapFontLoaded = false;
delete OPENGL_GAL::glContext;
glContext = NULL;
}
gluDeleteTess( tesselator );
@ -201,9 +211,6 @@ void OPENGL_GAL::BeginDrawing()
SetFillColor( fillColor );
SetStrokeColor( strokeColor );
// Unbind buffers - set compositor for direct drawing
compositor.SetBuffer( OPENGL_COMPOSITOR::DIRECT_RENDERING );
// Remove all previously stored items
nonCachedManager.Clear();
overlayManager.Clear();
@ -212,6 +219,40 @@ void OPENGL_GAL::BeginDrawing()
nonCachedManager.BeginDrawing();
overlayManager.BeginDrawing();
if( !isBitmapFontInitialized )
{
// Keep bitmap font texture always bound to the second texturing unit
const GLint FONT_TEXTURE_UNIT = 2;
if( !isBitmapFontLoaded )
{
glActiveTexture( GL_TEXTURE0 + FONT_TEXTURE_UNIT );
glGenTextures( 1, &fontTexture );
glBindTexture( GL_TEXTURE_2D, fontTexture );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RED, bitmap_font.width, bitmap_font.height,
0, GL_RED, GL_UNSIGNED_BYTE, bitmap_font.pixels );
checkGlError( "loading bitmap font" );
glActiveTexture( GL_TEXTURE0 );
isBitmapFontLoaded = true;
}
// Set shader parameter
GLint ufm_fontTexture = shader.AddParameter( "fontTexture" );
shader.Use();
shader.SetParameter( ufm_fontTexture, (int) FONT_TEXTURE_UNIT );
shader.Deactivate();
checkGlError( "setting bitmap font sampler as shader parameter" );
isBitmapFontInitialized = true;
}
// Unbind buffers - set compositor for direct drawing
compositor.SetBuffer( OPENGL_COMPOSITOR::DIRECT_RENDERING );
#ifdef __WXDEBUG__
prof_end( &totalRealTime );
wxLogTrace( "GAL_PROFILE",
@ -634,6 +675,125 @@ void OPENGL_GAL::DrawCurve( const VECTOR2D& aStartPoint, const VECTOR2D& aContro
}
void OPENGL_GAL::BitmapText( const wxString& aText, const VECTOR2D& aPosition,
double aRotationAngle )
{
wxASSERT_MSG( !IsTextMirrored(), "No support for mirrored text using bitmap fonts." );
const float TEX_X = bitmap_font.width;
const float TEX_Y = bitmap_font.height;
const int length = aText.length();
double cur_x = 0.0;
// Compute text size, so it can be properly justified
VECTOR2D textSize( 0.0, 0.0 );
for( int i = 0; i < length; ++i )
{
const bitmap_glyph& glyph = bitmap_chars[aText[i]];
textSize.x += ( glyph.x_off + glyph.width );
textSize.y = std::max( (unsigned int)( textSize.y ), glyph.y_off * 2 + glyph.height );
}
const double SCALE = GetGlyphSize().y / textSize.y * 2.0;
Save();
currentManager->Color( strokeColor.r, strokeColor.g, strokeColor.b, strokeColor.a );
currentManager->Translate( aPosition.x, aPosition.y, layerDepth );
currentManager->Rotate( aRotationAngle, 0.0f, 0.0f, -1.0f );
currentManager->Scale( SCALE, SCALE, 0 );
switch( GetHorizontalJustify() )
{
case GR_TEXT_HJUSTIFY_CENTER:
Translate( VECTOR2D( -textSize.x / 2.0, 0 ) );
break;
case GR_TEXT_HJUSTIFY_RIGHT:
//if( !IsTextMirrored() )
Translate( VECTOR2D( -textSize.x, 0 ) );
break;
case GR_TEXT_HJUSTIFY_LEFT:
//if( IsTextMirrored() )
//Translate( VECTOR2D( -textSize.x, 0 ) );
break;
}
switch( GetVerticalJustify() )
{
case GR_TEXT_VJUSTIFY_TOP:
Translate( VECTOR2D( 0, -textSize.y ) );
break;
case GR_TEXT_VJUSTIFY_CENTER:
Translate( VECTOR2D( 0, -textSize.y / 2.0 ) );
break;
case GR_TEXT_VJUSTIFY_BOTTOM:
break;
}
/* Glyph:
* v0 v1
* +--+
* | /|
* |/ |
* +--+
* v2 v3
*/
for( int i = 0; i < length; ++i )
{
const unsigned long c = aText[i];
wxASSERT_MSG( c < bitmap_chars_count, wxT( "Missing character in bitmap font atlas." ) );
if( c >= bitmap_chars_count )
continue;
wxASSERT_MSG( c != '\n' && c != '\r', wxT( "No support for multiline bitmap text yet" ) );
const bitmap_glyph& glyph = bitmap_chars[aText[i]];
const float x = glyph.x;
const float y = glyph.y;
const float xoff = glyph.x_off;
const float yoff = glyph.y_off;
const float w = glyph.width;
const float h = glyph.height;
currentManager->Reserve( 6 );
cur_x += xoff / 2;
currentManager->Shader( SHADER_FONT, x / TEX_X, y / TEX_Y );
currentManager->Vertex( cur_x, yoff, 0 ); // v0
currentManager->Shader( SHADER_FONT, ( x + w ) / TEX_X, y / TEX_Y );
currentManager->Vertex( cur_x + w, yoff, 0 ); // v1
currentManager->Shader( SHADER_FONT, x / TEX_X, ( y + h ) / TEX_Y );
currentManager->Vertex( cur_x, yoff + h, 0 ); // v2
currentManager->Shader( SHADER_FONT, ( x + w ) / TEX_X, y / TEX_Y );
currentManager->Vertex( cur_x + w, yoff, 0 ); // v1
currentManager->Shader( SHADER_FONT, x / TEX_X, ( y + h ) / TEX_Y );
currentManager->Vertex( cur_x, yoff + h, 0 ); // v2
currentManager->Shader( SHADER_FONT, ( x + w ) / TEX_X, ( y + h ) / TEX_Y );
currentManager->Vertex( cur_x + w, yoff + h, 0 ); // v3
cur_x += w + xoff / 2;
}
Restore();
}
void OPENGL_GAL::ResizeScreen( int aWidth, int aHeight )
{
screenSize = VECTOR2I( aWidth, aHeight );
@ -1172,6 +1332,17 @@ void OPENGL_GAL::OPENGL_TEST::Render( wxPaintEvent& WXUNUSED( aEvent ) )
return;
}
int maxTextureSize;
glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxTextureSize );
if( maxTextureSize < (int) bitmap_font.width || maxTextureSize < (int) bitmap_font.height )
{
// TODO implement software texture scaling
// for bitmap fonts and use a higher resolution texture?
error( "Requested texture size is not supported" );
}
m_tested = true;
}
}

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013-2016 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* Fragment shader
@ -30,9 +30,11 @@
const float SHADER_LINE = 1.0;
const float SHADER_FILLED_CIRCLE = 2.0;
const float SHADER_STROKED_CIRCLE = 3.0;
const float SHADER_FONT = 4.0;
varying vec4 shaderParams;
varying vec2 circleCoords;
uniform sampler2D fontTexture;
void filledCircle( vec2 aCoord )
{
@ -67,6 +69,15 @@ void main()
{
strokedCircle( circleCoords, shaderParams[2], shaderParams[3] );
}
else if( shaderParams[0] == SHADER_FONT )
{
vec4 texel = texture2D( fontTexture, vec2( shaderParams[1], shaderParams[2] ) );
if(texel.r < 0.01)
discard;
else
gl_FragColor = vec4(gl_Color.r, gl_Color.g, gl_Color.b, texel.r);
}
else
{
// Simple pass-through

View File

@ -1,7 +1,7 @@
/*
* This program source code file is part of KICAD, a free EDA CAD application.
*
* Copyright (C) 2013 CERN
* Copyright (C) 2013-2016 CERN
* @author Maciej Suminski <maciej.suminski@cern.ch>
*
* Vertex shader
@ -30,6 +30,7 @@
const float SHADER_LINE = 1.0;
const float SHADER_FILLED_CIRCLE = 2.0;
const float SHADER_STROKED_CIRCLE = 3.0;
const float SHADER_FONT = 4.0;
// Minimum line width
const float MIN_WIDTH = 1.0;

View File

@ -0,0 +1,42 @@
Creating bitmap fonts for GAL
=============================
Maciej Suminski <maciej.suminski@cern.ch>
12.04.2016
To create a new bitmap font atlas for Graphics Abstraction Layer, follow these steps:
* Download Bitmap Font Generator [1] (runs well under wine)
* Load default configuration stored in font.bmfc
* Adjust settings as needed
* Be sure that all glyphs fit into one page (you can check if in 'Visualize' you can move to another page (menu View))
* Export font atlas as .PNG file, and font description as XML file
* Run ./fnt2struct.py bitmap_font.fnt
* Run ./png2struct.py bitmap_font_0.png
* Copy bitmap_font_desc.c to common/gal/opengl/bitmap_font_desc.c
* Copy bitmap_font_0.png to common/gal/opengl/bitmap_font_img.c
Recommended export options:
Texture size: 1024x1024 (should be supported by majority GPUs)
Bit depth: 8
Font descriptor: XML
Textures: png
To match as closely as possible the newstroke_font glyph set,
mark the following character subsets in Bitmap Font Generator right panel:
Latin + Latin Supplement
Latin Extended A
Latin Extended B
IPA Extensions
Greek and Coptic
Cyrillic
Latin Extended Additional
Greek Extended
General Punctuation
Subscripts and Superscripts
Currency Symbols
Number Forms
Mathematical Operators
Geometric Shapes
References:
1. http://www.angelcode.com/products/bmfont/

File diff suppressed because it is too large Load Diff

Binary file not shown.

After

Width:  |  Height:  |  Size: 235 KiB

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,88 @@
#!/usr/bin/env python
# This program source code file is part of KiCad, a free EDA CAD application.
#
# Copyright (C) 2016 CERN
# @author Maciej Suminski <maciej.suminski@cern.ch>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you may find one here:
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# or you may search the http://www.gnu.org website for the version 2 license,
# or you may write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# Converts a bitmap font atlas description in XML format to data stored
# in a C structure.
import xml.etree.cElementTree as ET
import sys
import os
def convert(xml_file):
tree = ET.ElementTree(file=xml_file)
root = tree.getroot()
output = open(os.path.splitext(xml_file)[0] + '_desc.c', 'w')
# Header
output.write(
"""
/* generated with fnt2struct.py, do not modify by hand */
static const struct bitmap_glyph {
unsigned int x, y;
unsigned int width, height;
int x_off, y_off;
} bitmap_chars[] = {
""");
last_id = 0
fallback_line = '{ 0, 0, 0, 0, 0, 0 },\t\t/* %d (not defined) */\n'
for char in root.iter('char'):
cur_id = int(char.attrib['id'])
# Fill gaps for the missing characters
while(cur_id > last_id):
output.write(fallback_line % last_id)
last_id = last_id + 1
output.write('{ %d, %d, %d, %d, %d, %d },\t/* %d */\n' %
(int(char.attrib['x']), int(char.attrib['y']),
int(char.attrib['width']), int(char.attrib['height']),
int(char.attrib['xoffset']), int(char.attrib['yoffset']),
cur_id))
last_id = cur_id + 1
output.write('};\n')
output.write('static const int bitmap_chars_count = %d;\n' % last_id)
try:
lineHeight = int(root.find('common').get('lineHeight'))
except:
print('Could not determine the font height')
lineHeight = -1
output.write('static const int bitmap_chars_height = %d;\n' % (lineHeight))
output.close()
#----------------------------------------------------------------------
if __name__ == "__main__":
argc = len(sys.argv)
if(argc == 2):
convert(sys.argv[1])
else:
print("usage: %s <xml-file>" % sys.argv[0])

View File

@ -0,0 +1,59 @@
# AngelCode Bitmap Font Generator configuration file
fileVersion=1
# font settings
fontName=Ubuntu Mono
fontFile=
charSet=0
fontSize=55
aa=2
scaleH=100
useSmoothing=1
isBold=0
isItalic=0
useUnicode=1
disableBoxChars=1
outputInvalidCharGlyph=0
dontIncludeKerningPairs=0
useHinting=1
renderFromOutline=1
useClearType=1
# character alignment
paddingDown=0
paddingUp=0
paddingRight=0
paddingLeft=0
spacingHoriz=1
spacingVert=1
useFixedHeight=0
forceZero=0
# output file
outWidth=1024
outHeight=1024
outBitDepth=8
fontDescFormat=1
fourChnlPacked=0
textureFormat=png
textureCompression=0
alphaChnl=1
redChnl=0
greenChnl=0
blueChnl=0
invA=0
invR=0
invG=0
invB=0
# outline
outlineThickness=0
# selected chars
chars=0-0,8-9,13,29,32-126,160-591,658,900-902,904-906,908,910-929,931-974,1024-1119,1122-1123,1138-1141
chars=1162-1273,7808-7813,7922-7923,7936-7957,7960-7965,7968-8005,8008-8013,8016-8023,8025,8027,8029,8031
chars=8032-8061,8064-8116,8118-8132,8134-8147,8150-8155,8157-8175,8178-8180,8182-8190,8211-8213,8216-8218
chars=8220-8222,8224-8226,8230,8240,8249-8250,8260,8304,8308-8313,8320-8329,8364,8366,8372,8377,8531-8542
chars=8706,8710,8719,8721-8722,8725,8729-8730,8734,8747,8776,8800,8804-8805,9674
# imported icon images

View File

@ -0,0 +1,70 @@
#!/usr/bin/env python
# This program source code file is part of KiCad, a free EDA CAD application.
#
# Copyright (C) 2016 CERN
# @author Maciej Suminski <maciej.suminski@cern.ch>
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, you may find one here:
# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
# or you may search the http://www.gnu.org website for the version 2 license,
# or you may write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
# Converts a bitmap font atlas image in PNG format to raw pixel data stored
# in a C structure.
import os
import png
import sys
def convert(png_file):
r = png.Reader(file=open(png_file, 'rb'))
img = r.read()
output = open(os.path.splitext(png_file)[0] + '_img.c', 'w')
width = img[0]
height = img[1]
# Header
output.write(
"""
/* generated with png2struct.py, do not modify by hand */
static const struct {
unsigned int width, height;
unsigned char pixels[%d * %d];
} bitmap_font = {
""" % (width, height));
output.write('%d, %d,\n{' % (width, height))
for row in img[2]:
for p in row:
output.write('%d,' % p)
output.write('\n');
output.write('}\n};\n')
output.close()
#----------------------------------------------------------------------
if __name__ == "__main__":
argc = len(sys.argv)
if(argc == 2):
convert(sys.argv[1])
else:
print("usage: %s <xml-file>" % sys.argv[0])

View File

@ -288,6 +288,21 @@ public:
strokeFont.Draw( aText, aPosition, aRotationAngle );
}
/**
* @brief Draws a text using a bitmap font. It should be faster than StrokeText(),
* but can be used only for non-Gerber elements.
*
* @param aText is the text to be drawn.
* @param aPosition is the text position in world coordinates.
* @param aRotationAngle is the text rotation angle.
*/
virtual void BitmapText( const wxString& aText, const VECTOR2D& aPosition,
double aRotationAngle )
{
// Fallback: use stroke font
StrokeText( aText, aPosition, aRotationAngle );
}
/**
* @brief Compute the X and Y size of a given text. The text is expected to be
* a only one line text.

View File

@ -124,6 +124,10 @@ public:
virtual void DrawCurve( const VECTOR2D& startPoint, const VECTOR2D& controlPointA,
const VECTOR2D& controlPointB, const VECTOR2D& endPoint );
/// @copydoc GAL::BitmapText()
virtual void BitmapText( const wxString& aText, const VECTOR2D& aPosition,
double aRotationAngle );
// --------------
// Screen methods
// --------------
@ -263,6 +267,8 @@ private:
wxEvtHandler* paintListener;
static int instanceCounter;
GLuint fontTexture; ///< Bitmap font texture handle
// Vertex buffer objects related fields
typedef std::map< unsigned int, boost::shared_ptr<VERTEX_ITEM> > GROUPS_MAP;
GROUPS_MAP groups; ///< Stores informations about VBO objects (groups)
@ -283,6 +289,8 @@ private:
// Internal flags
bool isFramebufferInitialized; ///< Are the framebuffers initialized?
static bool isBitmapFontLoaded; ///< Is the bitmap font texture loaded?
bool isBitmapFontInitialized; ///< Is the shader set to use bitmap fonts?
bool isGrouping; ///< Was a group started?
// Polygon tesselation

View File

@ -43,6 +43,7 @@ enum SHADER_MODE
SHADER_LINE,
SHADER_FILLED_CIRCLE,
SHADER_STROKED_CIRCLE,
SHADER_FONT
};
typedef struct

View File

@ -382,18 +382,16 @@ void PCB_DRAW_PANEL_GAL::setDefaultLayerDeps()
LAYER_NUM layer = GAL_LAYER_ORDER[i];
wxASSERT( layer < KIGFX::VIEW::VIEW_MAX_LAYERS );
// Set layer display dependencies & targets
if( IsCopperLayer( layer ) )
{
// Copper layers are required for netname layers
m_view->SetRequired( GetNetnameLayer( layer ), layer );
m_view->SetLayerTarget( layer, KIGFX::TARGET_CACHED );
}
else if( IsNetnameLayer( layer ) )
{
// Netnames are drawn only when scale is sufficient (level of details)
// so there is no point in caching them
m_view->SetLayerTarget( layer, KIGFX::TARGET_NONCACHED );
m_view->SetLayerDisplayOnly( layer );
m_view->SetLayerTarget( layer, KIGFX::TARGET_CACHED );
}
}

View File

@ -313,7 +313,7 @@ void PCB_PAINTER::draw( const TRACK* aTrack, int aLayer )
m_gal->SetGlyphSize( VECTOR2D( textSize * 0.7, textSize * 0.7 ) );
m_gal->SetHorizontalJustify( GR_TEXT_HJUSTIFY_CENTER );
m_gal->SetVerticalJustify( GR_TEXT_VJUSTIFY_CENTER );
m_gal->StrokeText( netName, textPosition, textOrientation );
m_gal->BitmapText( netName, textPosition, textOrientation );
}
}
else if( IsCopperLayer( aLayer ) )
@ -518,9 +518,10 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
// Use a smaller text size to handle interline, pen size..
tsize *= 0.7;
VECTOR2D namesize( tsize, tsize );
m_gal->SetGlyphSize( namesize );
m_gal->SetLineWidth( namesize.x / 12.0 );
m_gal->StrokeText( aPad->GetShortNetname(), textpos, 0.0 );
m_gal->BitmapText( aPad->GetShortNetname(), textpos, 0.0 );
}
if( m_pcbSettings.m_padNumbers )
@ -537,7 +538,7 @@ void PCB_PAINTER::draw( const D_PAD* aPad, int aLayer )
m_gal->SetGlyphSize( numsize );
m_gal->SetLineWidth( numsize.x / 12.0 );
m_gal->StrokeText( aPad->GetPadName(), textpos, 0.0 );
m_gal->BitmapText( aPad->GetPadName(), textpos, 0.0 );
}
m_gal->Restore();