示例#1
0
int CFontGen::SaveFont(const char *szFile)
{
	if( isWorking ) return -1;

	// The pages must be generated first
	if( !arePagesGenerated ) return -1;

	// Create a memory dc
	HDC dc = CreateCompatibleDC(0);

	HFONT font = CreateFont(0);
	HFONT oldFont = (HFONT)SelectObject(dc, font);

	// Determine the size needed for the char
	int height, base;

	TEXTMETRIC tm;
	GetTextMetrics(dc, &tm);

	// Round up to make sure fractional pixels are covered
	height = (int)ceil(float(tm.tmHeight)/aa);
	base = (int)ceil(float(tm.tmAscent)/aa);

	// Save the character attributes
	FILE *f;

	string filename = szFile;
	if( _stricmp(filename.substr(filename.length() - 4).c_str(), ".fnt") == 0 )
		filename = filename.substr(0, filename.length() - 4);

	errno_t e = fopen_s(&f, (filename + ".fnt").c_str(), "wb");
	if( e != 0 || f == 0 )
		return -1;

	// Get the filename without path
	int r = filename.rfind('\\');
	string filenameonly;
	if( r != -1 )
		filenameonly = filename.substr(r+1);
	else
		filenameonly = filename;
		
	if( outBitDepth != 32 ) fourChnlPacked = false;
	int numPages = pages.size();

	// Determine the number of digits needed for the page file id
	int numDigits = numPages > 1 ? int(log10(float(numPages-1))+1) : 1;

	if( fontDescFormat == 1 ) 
	{
		fprintf(f, "<?xml version=\"1.0\"?>\r\n");
		fprintf(f, "<font>\r\n");
		fprintf(f, "  <info face=\"%s\" size=\"%d\" bold=\"%d\" italic=\"%d\" charset=\"%s\" unicode=\"%d\" stretchH=\"%d\" smooth=\"%d\" aa=\"%d\" padding=\"%d,%d,%d,%d\" spacing=\"%d,%d\" outline=\"%d\"/>\r\n", fontName.c_str(), fontSize, isBold, isItalic, useUnicode ? "" : GetCharSetName(charSet).c_str(), useUnicode, scaleH, useSmoothing, aa, paddingUp, paddingRight, paddingDown, paddingLeft, spacingHoriz, spacingVert, outlineThickness);
		fprintf(f, "  <common lineHeight=\"%d\" base=\"%d\" scaleW=\"%d\" scaleH=\"%d\" pages=\"%d\" packed=\"%d\" alphaChnl=\"%d\" redChnl=\"%d\" greenChnl=\"%d\" blueChnl=\"%d\"/>\r\n", int(ceilf(height*float(scaleH)/100.0f)), int(ceilf(base*float(scaleH)/100.0f)), outWidth, outHeight, numPages, fourChnlPacked, alphaChnl, redChnl, greenChnl, blueChnl);

		fprintf(f, "  <pages>\r\n");
		for( int n = 0; n < numPages; n++ )
			fprintf(f, "    <page id=\"%d\" file=\"%s_%0*d.%s\" />\r\n", n, filenameonly.c_str(), numDigits, n, textureFormat.c_str());
		fprintf(f, "  </pages>\r\n");
	}
	else if( fontDescFormat == 0 )
	{
		fprintf(f, "info face=\"%s\" size=%d bold=%d italic=%d charset=\"%s\" unicode=%d stretchH=%d smooth=%d aa=%d padding=%d,%d,%d,%d spacing=%d,%d outline=%d\r\n", fontName.c_str(), fontSize, isBold, isItalic, useUnicode ? "" : GetCharSetName(charSet).c_str(), useUnicode, scaleH, useSmoothing, aa, paddingUp, paddingRight, paddingDown, paddingLeft, spacingHoriz, spacingVert, outlineThickness);
		fprintf(f, "common lineHeight=%d base=%d scaleW=%d scaleH=%d pages=%d packed=%d alphaChnl=%d redChnl=%d greenChnl=%d blueChnl=%d\r\n", int(ceilf(height*float(scaleH)/100.0f)), int(ceilf(base*float(scaleH)/100.0f)), outWidth, outHeight, numPages, fourChnlPacked, alphaChnl, redChnl, greenChnl, blueChnl);

		for( int n = 0; n < numPages; n++ )
			fprintf(f, "page id=%d file=\"%s_%0*d.%s\"\r\n", n, filenameonly.c_str(), numDigits, n, textureFormat.c_str());
	}
	else
	{
		// Write the magic word and file version
		fwrite("BMF", 3, 1, f);
		fputc(3, f); 

		// Write the info block
#pragma pack(push)
#pragma pack(1)
		struct infoBlock
		{
			int            blockSize;
			unsigned short fontSize;
			char           reserved    :4;
			char           bold        :1;
			char           italic      :1;
			char           unicode     :1;
			char           smooth      :1;
			unsigned char  charSet;
			unsigned short stretchH;
			char           aa;
			unsigned char  paddingUp;
			unsigned char  paddingRight;
			unsigned char  paddingDown;
			unsigned char  paddingLeft;
			unsigned char  spacingHoriz;
			unsigned char  spacingVert;
			unsigned char  outline;
			char           fontName[1];
		} info;
#pragma pack(pop)

		info.blockSize    = sizeof(info) + fontName.length() - 4;
		info.fontSize     = fontSize;
		info.reserved     = 0;
		info.bold         = isBold;
		info.italic       = isItalic;
		info.unicode      = useUnicode;
		info.smooth       = useSmoothing;
		info.charSet      = charSet;
		info.stretchH     = scaleH;
		info.aa           = aa;
		info.paddingUp    = paddingUp;
		info.paddingRight = paddingRight;
		info.paddingDown  = paddingDown;
		info.paddingLeft  = paddingLeft;
		info.spacingHoriz = spacingHoriz;
		info.spacingVert  = spacingVert;
		info.outline      = outlineThickness;

		fputc(1, f);
		fwrite(&info, sizeof(info)-1, 1, f);
		fwrite(fontName.c_str(), fontName.length()+1, 1, f);

		// Write the common block
#pragma pack(push)
#pragma pack(1)
		struct commonBlock
		{
			int blockSize;
			unsigned short lineHeight;
			unsigned short base;
			unsigned short scaleW;
			unsigned short scaleH;
			unsigned short pages;
			unsigned char  packed:1;
			unsigned char  reserved:7;
			unsigned char  alphaChnl;
			unsigned char  redChnl;
			unsigned char  greenChnl;
			unsigned char  blueChnl;
		} common; 
#pragma pack(pop)

		common.blockSize  = sizeof(common) - 4;
		common.lineHeight = int(ceilf(height*float(scaleH)/100.0f));
		common.base       = int(ceilf(base*float(scaleH)/100.0f));
		common.scaleW     = outWidth;
		common.scaleH     = outHeight;
		common.pages      = numPages;
		common.reserved   = 0;
		common.packed     = fourChnlPacked;
		common.alphaChnl  = alphaChnl;
		common.redChnl    = redChnl;
		common.greenChnl  = greenChnl;
		common.blueChnl   = blueChnl;

		fputc(2, f);
		fwrite(&common, sizeof(common), 1, f);

		// Write the page block
		fputc(3, f);
		int size = (filenameonly.length() + numDigits + 2 + textureFormat.length() + 1)*numPages;
		fwrite(&size, sizeof(size), 1, f);

		for( int n = 0; n < numPages; n++ )
		{
			fprintf(f, "%s_%0*d.%s", filenameonly.c_str(), numDigits, n, textureFormat.c_str());
			fputc(0, f);
		}
	}

	const int maxChars = useUnicode ? maxUnicodeChar+1 : 256;

	// Count the number of characters that will be written
	int numChars = 0;
	int n;
	for( n = 0; n < maxChars; n++ )
		if( chars[n] )
			numChars++;

	if( invalidCharGlyph )
		numChars++;

	if( fontDescFormat == 0 )
		fprintf(f, "chars count=%d\r\n", numChars);
	else if( fontDescFormat == 1 )
		fprintf(f, "  <chars count=\"%d\">\r\n", numChars);
	else if( fontDescFormat == 2 )
	{
		fputc(4, f);

		// Determine the size of this block
		int size = (4+2+2+2+2+2+2+2+1+1)*numChars;
		fwrite(&size, 4, 1, f);
	}

	if( invalidCharGlyph )
	{
		if( fontDescFormat == 1 )
			fprintf(f, "    <char id=\"%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xoffset=\"%d\" yoffset=\"%d\" xadvance=\"%d\" page=\"%d\" chnl=\"%d\" />\r\n", -1, invalidCharGlyph->m_x, invalidCharGlyph->m_y, invalidCharGlyph->m_width, invalidCharGlyph->m_height, invalidCharGlyph->m_xoffset, invalidCharGlyph->m_yoffset, invalidCharGlyph->m_advance, invalidCharGlyph->m_page, invalidCharGlyph->m_chnl);
		else if( fontDescFormat == 0 )
			fprintf(f, "char id=%-4d x=%-5d y=%-5d width=%-5d height=%-5d xoffset=%-5d yoffset=%-5d xadvance=%-5d page=%-2d chnl=%-2d\r\n", -1, invalidCharGlyph->m_x, invalidCharGlyph->m_y, invalidCharGlyph->m_width, invalidCharGlyph->m_height, invalidCharGlyph->m_xoffset, invalidCharGlyph->m_yoffset, invalidCharGlyph->m_advance, invalidCharGlyph->m_page, invalidCharGlyph->m_chnl);
		else
		{
#pragma pack(push)
#pragma pack(1)
			struct charBlock
			{
				DWORD id;
				WORD x;
				WORD y;
				WORD width;
				WORD height;
				short xoffset;
				short yoffset;
				short xadvance;
				char  page;
				char  channel;
			} charInfo;
#pragma pack(pop)

			charInfo.id = -1;
			charInfo.x  = invalidCharGlyph->m_x;
			charInfo.y  = invalidCharGlyph->m_y;
			charInfo.width = invalidCharGlyph->m_width;
			charInfo.height = invalidCharGlyph->m_height;
			charInfo.xoffset = invalidCharGlyph->m_xoffset;
			charInfo.yoffset = invalidCharGlyph->m_yoffset;
			charInfo.xadvance = invalidCharGlyph->m_advance;
			charInfo.page = invalidCharGlyph->m_page;
			charInfo.channel = invalidCharGlyph->m_chnl;

			fwrite(&charInfo, sizeof(charInfo), 1, f);
		}
	}

	for( n = 0; n < maxChars; n++ )
	{
        if( chars[n] )
		{
			int page, chnl;
			page = chars[n]->m_page;
			chnl = chars[n]->m_chnl;
			
			if( fontDescFormat == 1 )
				fprintf(f, "    <char id=\"%d\" x=\"%d\" y=\"%d\" width=\"%d\" height=\"%d\" xoffset=\"%d\" yoffset=\"%d\" xadvance=\"%d\" page=\"%d\" chnl=\"%d\" />\r\n", n, chars[n]->m_x, chars[n]->m_y, chars[n]->m_width, chars[n]->m_height, chars[n]->m_xoffset, chars[n]->m_yoffset, chars[n]->m_advance, page, chnl);
			else if( fontDescFormat == 0 )
				fprintf(f, "char id=%-4d x=%-5d y=%-5d width=%-5d height=%-5d xoffset=%-5d yoffset=%-5d xadvance=%-5d page=%-2d chnl=%-2d\r\n", n, chars[n]->m_x, chars[n]->m_y, chars[n]->m_width, chars[n]->m_height, chars[n]->m_xoffset, chars[n]->m_yoffset, chars[n]->m_advance, page, chnl);
			else
			{
#pragma pack(push)
#pragma pack(1)
				struct charBlock
				{
					DWORD id;
					WORD x;
					WORD y;
					WORD width;
					WORD height;
					short xoffset;
					short yoffset;
					short xadvance;
					char  page;
					char  channel;
				} charInfo;
#pragma pack(pop)

				charInfo.id = n;
				charInfo.x  = chars[n]->m_x;
				charInfo.y  = chars[n]->m_y;
				charInfo.width = chars[n]->m_width;
				charInfo.height = chars[n]->m_height;
				charInfo.xoffset = chars[n]->m_xoffset;
				charInfo.yoffset = chars[n]->m_yoffset;
				charInfo.xadvance = chars[n]->m_advance;
				charInfo.page = page;
				charInfo.channel = chnl;

				fwrite(&charInfo, sizeof(charInfo), 1, f);
			}
		}
	}

	if( fontDescFormat == 1 )
		fprintf(f, "  </chars>\r\n");


	// Save the kerning pairs as well
	vector<KERNINGPAIR> pairs;
	if( useUnicode )
	{
		// TODO: How do I obtain the kerning pairs for 
		// the characters in the higher planes?

		int num = GetKerningPairsW(dc, 0, 0);
		if( num > 0 )
		{
			pairs.resize(num);
			GetKerningPairsW(dc, num, &pairs[0]);
		}
	}
	else
	{
		int num = GetKerningPairs(dc, 0, 0);
		if( num > 0 )
		{
			pairs.resize(num);
			GetKerningPairs(dc, num, &pairs[0]);
		}
	}

	if( pairs.size() == 0 )
	{
		// Build a list of all selected chars
		vector<UINT> chars;
		chars.reserve(GetNumCharsSelected());
		for( UINT n = 0; n <= maxUnicodeChar; n++ )
		{
			if( selected[n] )
			{
				chars.push_back(n);
				if( chars.size() == GetNumCharsSelected() )
					break;
			}
		}

		GetKerningPairsFromGPOS(dc, pairs, chars);
	}

	if( pairs.size() > 0 )
	{
		// Count the number of kerning pairs
		int count = 0;
		for( unsigned int n = 0; n < pairs.size(); n++ )
		{
			if( pairs[n].wFirst < maxChars && pairs[n].wSecond < maxChars &&
				!disabled[pairs[n].wFirst] && !disabled[pairs[n].wSecond] &&
				selected[pairs[n].wFirst] && selected[pairs[n].wSecond] &&
				pairs[n].iKernAmount/aa )
			{
				count++;
			}
		}

		if( fontDescFormat == 0 )
			fprintf(f, "kernings count=%d\r\n", count);
		else if( fontDescFormat == 1 )
			fprintf(f, "  <kernings count=\"%d\">\r\n", count);
		else if( fontDescFormat == 2 )
		{
			fputc(5, f);

			// Determine the size of the block
			int size = count*10;
			fwrite(&size, 4, 1, f);
		}
	}

	// It's been reported that for Chinese WinXP the kerning pairs for 
	// non-unicode charsets may contain characters > 255, so we need to 
	// filter for this.
	for( unsigned int n = 0; n < pairs.size(); n++ )
	{
		if( pairs[n].wFirst < maxChars && pairs[n].wSecond < maxChars &&
			!disabled[pairs[n].wFirst] && !disabled[pairs[n].wSecond] &&
			selected[pairs[n].wFirst] && selected[pairs[n].wSecond] &&
			pairs[n].iKernAmount/aa )
		{
			if( fontDescFormat == 1 )
				fprintf(f, "    <kerning first=\"%d\" second=\"%d\" amount=\"%d\" />\r\n", pairs[n].wFirst, pairs[n].wSecond, pairs[n].iKernAmount/aa);
			else if( fontDescFormat == 0 )
				fprintf(f, "kerning first=%-3d second=%-3d amount=%-4d\r\n", pairs[n].wFirst, pairs[n].wSecond, pairs[n].iKernAmount/aa);
			else 
			{
#pragma pack(push)
#pragma pack(1)
				struct kerningBlock
				{
					DWORD first;
					DWORD second;
					short amount;
				} kerning;
#pragma pack(pop)
				kerning.first = pairs[n].wFirst;
				kerning.second = pairs[n].wSecond;
				kerning.amount = pairs[n].iKernAmount/aa;

				fwrite(&kerning, sizeof(kerning), 1, f);
			}
		}
	}

	if( pairs.size() > 0 && fontDescFormat == 1 )
		fprintf(f, "  </kernings>\r\n");

	if( fontDescFormat == 1 ) fprintf(f, "</font>\r\n");

	fclose(f);

	SelectObject(dc, oldFont);
	DeleteObject(font);

	DeleteDC(dc);


	// Save the image file
	for( n = 0; n < (signed)pages.size(); n++ )
	{
		string str = acStringFormat("%s_%0*d.%s", filename.c_str(), numDigits, n, textureFormat.c_str());

		acImage::Image image;
		image.width = outWidth;
		image.height = outHeight;
		if( outBitDepth == 32 )
		{
			image.pitch = image.width*4;
			image.format = acImage::PF_A8R8G8B8;
		}
		else
		{
			image.pitch = image.width;
			image.format = acImage::PF_A8;
		}

		image.data = new BYTE[image.pitch * image.height];

		// Generate the output texture for saving
		pages[n]->GenerateOutputTexture();

		cImage *page = pages[n]->GetPageImage();
		if( outBitDepth == 8 )
		{
			// Write image data
			for( int y = 0; y < outHeight; y++ )
			{
				for( int x = 0; x < outWidth; x++ )
				{
					DWORD pixel = page->pixels[y*outWidth + x];
					image.data[y*image.pitch + x] = (BYTE)(pixel>>24);
				}
			}
		}
		else
		{
			// Write image data
			for( int y = 0; y < outHeight; y++ )
			{
				for( int x = 0; x < outWidth; x++ )
				{
					DWORD pixel = page->pixels[y*outWidth + x];
					*(DWORD*)&image.data[y*image.pitch + x*4] = pixel;
				}
			}
		}

		if( textureFormat == "tga" )
			acImage::SaveTga(str.c_str(), image);
		else if( textureFormat == "png" )
			acImage::SavePng(str.c_str(), image);
		else if( textureFormat == "dds" )
			acImage::SaveDds(str.c_str(), image, textureCompression);
	}
void  nsLatin1Prober::DumpStatus()
{
    printf(" Latin1Prober: %1.3f [%s]\r\n", GetConfidence(), GetCharSetName());
}
void nsSingleByteCharSetProber::DumpStatus()
{
  printf("  SBCS: %1.3f [%s]\r\n", GetConfidence(), GetCharSetName());
}