text: /*
  * Copyright (c) 2006, Hybrid Graphics, Ltd.
  * All rights reserved.
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions are met:
  *
  *     * Redistributions of source code must retain the above copyright
  *       notice, this list of conditions and the following disclaimer.
  *     * Redistributions in binary form must reproduce the above copyright
  *       notice, this list of conditions and the following disclaimer in the
  *       documentation and/or other materials provided with the distribution.
  *     * The name of Hybrid Graphics may not be used to endorse or promote products
  *       derived from this software without specific prior written permission.
  *
  * THIS SOFTWARE IS PROVIDED BY HYBRID GRAPHICS ``AS IS'' AND ANY
  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  * DISCLAIMED. IN NO EVENT SHALL HYBRID GRAPHICS BE LIABLE FOR ANY
  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
  
  #include <iostream>
  #include <fstream>
  #include <vector>
  #include <float.h>
  
  #include "ft2build.h"
  #include FT_FREETYPE_H
  #include FT_OUTLINE_H
  
  #define OUTPUT_INTS
  #define NGLYPHS 500
  class Vector2
  {
  public:
  	Vector2()						{}
  	Vector2(float px, float py)		{ x = px; y = py; }
  	
  	float		x;
  	float		y;
  };
  
  Vector2	operator+(const Vector2& a, const Vector2& b)	{ return Vector2(a.x+b.x, a.y+b.y); }
  Vector2	operator*(const Vector2& a, float b)	{ return Vector2(a.x*b, a.y*b); }
  
  float convFTFixed( const FT_Pos &x )
  {
  	return (float)x / 4096.0f;
  }
  
  Vector2 convFTVector( const FT_Vector &v )
  {
  	return Vector2(convFTFixed(v.x),convFTFixed(v.y));
  }
  
  bool isOn( char b )
  {
  	return b & 1 ? true : false;
  }
  
  int main (int argc, char * const argv[])
  {
  	FT_Library library;
  	FT_Face face;
  
  	if(argc < 4)
  	{
  		printf("usage: font2openvg input_font_file output.c prefix\n");
  		exit(-1);
  	}
  
  	if( FT_Init_FreeType( &library ) )
  	{
  		printf("couldn't initialize freetype\n");
  		exit(-1);
  	}
  	int faceIndex = 0;
  	if( FT_New_Face( library, argv[1], faceIndex, &face ) )
  	{
  		printf("couldn't load new face\n");
  		exit(-1);
  	}
  
  	FT_Set_Char_Size(
                face,    /* handle to face object           */
                0,       /* char_width in 1/64th of points  */
                64*64,   /* char_height in 1/64th of points */
                96,     /* horizontal device resolution    */
                96 );   /* vertical device resolution      */
  
  	FILE* f = fopen(argv[2], "wt");
  	if(!f)
  	{
  		printf("couldn't open %s for writing\n", argv[2]);
  		exit(-1);
  	}
  
  	std::vector<int>		gpvecindices;
  	std::vector<int>		givecindices;
  	std::vector<int>		gpvecsizes;
  	std::vector<int>		givecsizes;
  	std::vector<Vector2>	gpvec;
  	std::vector<char>		givec;
  	std::vector<float>		gbbox;
  	std::vector<float>		advances;
  
          float                           global_miny = 1000000.0f;
          float                           global_maxy = -10000000.0f;
          
  	unsigned int characterMap[NGLYPHS];
  	int glyphs = 0;
  	for(int cc=0;cc<NGLYPHS;cc++)
  	{
  		characterMap[cc] = 0xffffffffu;	//initially nonexistent
  
  		if( cc < 32 )
  			continue;	//discard the first 32 characters
  
  		int glyphIndex = FT_Get_Char_Index( face, cc );
  
  		if( !FT_Load_Glyph( face, glyphIndex, FT_LOAD_NO_BITMAP | FT_LOAD_NO_HINTING | FT_LOAD_IGNORE_TRANSFORM ) )
  		{
  			float advance = convFTFixed( face->glyph->advance.x );
  			if( cc == ' ' )
  			{	//space doesn't contain any data
  				gpvecindices.push_back( gpvec.size() );
  				givecindices.push_back( givec.size() );
  
  				gpvecsizes.push_back( 0 );
  				givecsizes.push_back( 0 );
  
  				gbbox.push_back(0);
  				gbbox.push_back(0);
  				gbbox.push_back(0);
  				gbbox.push_back(0);
  
  				advances.push_back(advance);
  
  				//write glyph index to character map
  				characterMap[cc] = glyphs++;
  				continue;
  			}
  
  			FT_Outline &outline = face->glyph->outline;
  			std::vector<Vector2>		pvec;
  			std::vector<unsigned char>	ivec;
  			float minx = 10000000.0f,miny = 100000000.0f,maxx = -10000000.0f,maxy = -10000000.0f;
  			int s = 0,e;
  			bool on;
  			Vector2 last,v,nv;
  			for(int con=0;con<outline.n_contours;++con)
  			{
  				int pnts = 1;
  				e = outline.contours[con]+1;
  				last = convFTVector(outline.points[s]);
  
  				//read the contour start point
  				ivec.push_back(2);
  				pvec.push_back(last);
  
  				int i=s+1;
  				while(i<=e)
  				{
  					int c = (i == e) ? s : i;
  					int n = (i == e-1) ? s : (i+1);
  					v = convFTVector(outline.points[c]);
  					on = isOn( outline.tags[c] );
  					if( on )
  					{	//line
  						++i;
  						ivec.push_back(4);
  						pvec.push_back(v);
  						pnts += 1;
  					}
  					else
  					{	//spline
  						if( isOn( outline.tags[n] ) )
  						{	//next on
  							nv = convFTVector( outline.points[n] );
  							i += 2;
  						}
  						else
  						{	//next off, use middle point
  							nv = (v + convFTVector( outline.points[n] )) * 0.5f;
  							++i;
  						}
  						ivec.push_back(10);
  						pvec.push_back(v);
  						pvec.push_back(nv);
  						pnts += 2;
  					}
  					last = nv;
  				}
  				ivec.push_back(0);
  				s = e;
  			}
  
  			for(int i=0;i<pvec.size();++i)
  			{
  				if( pvec[i].x < minx ) minx = pvec[i].x;
  				if( pvec[i].x > maxx ) maxx = pvec[i].x;
  				if( pvec[i].y < miny ) miny = pvec[i].y;
  				if( pvec[i].y > maxy ) maxy = pvec[i].y;
  			}
  			if(!pvec.size())
  			{
  				minx = 0.0f;
  				miny = 0.0f;
  				maxx = 0.0f;
  				maxy = 0.0f;
  			}
  
  			gpvecindices.push_back( gpvec.size() );
  			givecindices.push_back( givec.size() );
  
  			gpvecsizes.push_back( pvec.size() );
  			givecsizes.push_back( ivec.size() );
  
  			gbbox.push_back( minx );
  			gbbox.push_back( miny );
  			gbbox.push_back( maxx );
  			gbbox.push_back( maxy );
  			advances.push_back(advance);
  
                          if (miny < global_miny) {
                              global_miny = miny;
                          }
                          if (maxy > global_maxy) {
                              global_maxy = maxy;
                          }
                          
  			int size;
  			size = gpvec.size();
  			gpvec.resize( size + pvec.size() );
  			memcpy( &(gpvec[size]), &(pvec[0]), pvec.size() * sizeof(Vector2) );
  
  			size = givec.size();
  			givec.resize( size + ivec.size() );
  			memcpy( &(givec[size]), &(ivec[0]), ivec.size() * sizeof(char) );
  
  			//write glyph index to character map
  			characterMap[cc] = glyphs++;
  		}
  	}
  	if(!glyphs)
  		printf("warning: no glyphs found\n");
  
  	static const char* legalese = {"/* Generated by font2openvg. See http://developer.hybrid.fi for more information. */\n\n"};
  
  	//print legalese
  	fprintf(f,"%s", legalese);
  
  
  	//print the name of the font file
  	fprintf (f,"/* converted from font file %s */\n", argv[1]);
  	fprintf (f,"/* font family name: %s */\n", face->family_name);
  	fprintf (f,"/* font style name: %s */\n\n", face->style_name);
  
  	//print instructions
  	fprintf (f,"static const unsigned char %s_glyphInstructions[%d] = {", argv[3],givec.size());
  	for(int i=0;i<givec.size();i++)
  	{
  		if ((i % 20)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%d%c",givec[i],(i==(givec.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n");
  
  	fprintf (f,"static const int %s_glyphInstructionIndices[%d] = {", argv[3],givecindices.size());
  	for(int i=0;i<givecindices.size();i++)
  	{
  		if ((i % 20)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%d%c",givecindices[i],(i==(givecindices.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n");
  
  	fprintf (f,"static const int %s_glyphInstructionCounts[%d] = {", argv[3],givecsizes.size());
  	for(int i=0;i<givecsizes.size();i++)
  	{
  		if ((i % 20)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%d%c",givecsizes[i],(i==(givecsizes.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n\n");
  
  	fprintf (f,"static const int %s_glyphPointIndices[%d] = {", argv[3],gpvecindices.size());
  	for(int i=0;i<gpvecindices.size();i++)
  	{
  		if ((i % 20)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%d%c",gpvecindices[i],(i==(gpvecindices.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n");
  
  #ifdef OUTPUT_INTS
  	//print points
  	fprintf (f,"static const int %s_glyphPoints[%d*2] = {", argv[3],gpvec.size());
  	for(int i=0;i<gpvec.size();i++)
  	{
  		if ((i % 10)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%d,%d%c",(int)(65536.0f*gpvec[i].x),(int)(65536.0f*gpvec[i].y),(i==(gpvec.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n");
  
  	//print the advances
  	fprintf (f,"static const int %s_glyphAdvances[%d] = {", argv[3],advances.size());
  	for(int i=0;i<advances.size();i++)
  	{
  		if ((i % 20)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%d%c",(int)(65536.0f*advances[i]),(i==(advances.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n\n");
  
  	//print the bounding boxes
  /*
  	fprintf (f,"static const int %s_glyphBBoxes[%d] = {", argv[3],gbbox.size());
  	for(int i=0;i<gbbox.size();i++)
  	{
  		if ((i % 20)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%d%c",(int)(65536.0f*gbbox[i]),(i==(gbbox.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n\n");
  */
          //print minimum and maximum y values over the whole font
          fprintf (f,"static const int %s_descender_height = %d;\n",argv[3],(int)(65536.0f*global_miny));
          fprintf (f,"static const int %s_font_height = %d;\n",argv[3],(int)(65536.0f*global_maxy));
  #else
  	//print points
  	fprintf (f,"static const float %s_glyphPoints[%d*2] = {", argv[3],gpvec.size());
  	for(int i=0;i<gpvec.size();i++)
  	{
  		if ((i % 10)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%f,%f%c",gpvec[i].x,gpvec[i].y,(i==(gpvec.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n");
  
  	//print the advances
  	fprintf (f,"static const float %s_glyphAdvances[%d] = {", argv[3],advances.size());
  	for(int i=0;i<advances.size();i++)
  	{
  		if ((i % 20)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%f%c",advances[i],(i==(advances.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n\n");
  
  	//print the bounding boxes
  /*
  	fprintf (f,"static const float %s_glyphBBoxes[%d] = {", argv[3],gbbox.size());
  	for(int i=0;i<gbbox.size();i++)
  	{
  		if ((i % 20)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%f%c",gbbox[i],(i==(gbbox.size()-1))?' ':',');
  	}
  	fprintf (f,"};\n\n");
  */
          fprintf (f,"static const float %s_descender_height = %d;\n",argv[3],global_miny));
          fprintf (f,"static const float %s_font_height = %d;\n",argv[3],global_maxy));
  #endif
  
  
  	//print the number of glyphs and the character map
  	fprintf (f,"static const int %s_glyphCount = %d;\n",argv[3],glyphs);
  	fprintf (f,"static const short %s_characterMap[500] = {", argv[3]);
  	for(int i=0;i<NGLYPHS;i++)
  	{
  		if ((i % 20)==0)
  			fprintf (f,"\n    ");
  		fprintf (f,"%d%c",characterMap[i],(i==(NGLYPHS-1))?' ':',');
  	}
  	fprintf (f,"};\n\n");
  	fclose(f);
  
  	if(glyphs)
  		printf("%d glyphs written\n", glyphs);
  
  	FT_Done_Face( face );
  	FT_Done_FreeType( library );
      return 0;
  }
  