示例#1
0
bool Selene::CFont::Load()
{
	if (m_Loaded || m_pFile == NULL || m_FontLibrary == NULL)
	{
		return false;
	}

	int dataSize = m_pFile->GetSize();
	unsigned char* pData = new unsigned char[dataSize];
	m_pFile->Read(pData, dataSize, 1);

	FT_Face face;

	FT_Error error = FT_New_Memory_Face(m_FontLibrary, pData, dataSize, 0, &face);
	if (error != 0)
	{
		//...
	}

	long fontSize = 60;
	unsigned int dpi = 96;
	error = FT_Set_Char_Size(face, 0, fontSize << 6, 0, dpi);
	if (error != 0)
	{
		//...
	}

	m_SymbolCount = 128;
	m_CharData = new SCharData[m_SymbolCount];
	int* sortedIndices = new int[m_SymbolCount];
	for (int i = 0; i < m_SymbolCount; i++)
	{
		//unsigned long charCode = 0x3043;
		//unsigned long charCode = 0x61; // a
		unsigned long charCode = i;
		if (i < 32)
		{
			charCode = i + 0x3042;
		}

		sortedIndices[i] = i;
		m_CharData[i].m_CharCode = charCode;
		if (!FillCharData(m_CharData[i], face))
		{
			//...
		}
	}

	// sort (bubble)
	for (int i = 0; i < m_SymbolCount; i++)
	{
		int maxGlyphIndex = i;
		for (int j = i; j < m_SymbolCount; j++)
		{
			//bool maxIsHorizontal = charData[maxGlyphIndex].m_Width > charData[maxGlyphIndex].m_Height;
			//bool currentIsHorizontal = charData[sortedIndices[j]].m_Width > charData[sortedIndices[j]].m_Height;
			//if (!maxIsHorizontal && currentIsHorizontal)
			//{
			//	maxGlyphIndex = j;
			//}
			//else if (maxIsHorizontal && currentIsHorizontal)
			//{
				if (m_CharData[maxGlyphIndex].m_Width < m_CharData[sortedIndices[j]].m_Width)
				{
					maxGlyphIndex = j;
				}
				//else if (m_CharData[maxGlyphIndex].m_Width == m_CharData[sortedIndices[j]].m_Width &&
				//		 m_CharData[maxGlyphIndex].m_Height < m_CharData[sortedIndices[j]].m_Height)
				//{
				//	maxGlyphIndex = j;
				//}
			//}
			//else if (!maxIsHorizontal && !currentIsHorizontal)
			//{
			//	if (charData[maxGlyphIndex].m_Height < charData[sortedIndices[j]].m_Height)
			//	{
			//		maxGlyphIndex = j;
			//	}
			//	else if (charData[maxGlyphIndex].m_Height == charData[sortedIndices[j]].m_Height &&
			//			 charData[maxGlyphIndex].m_Width < charData[sortedIndices[j]].m_Width)
			//	{
			//		maxGlyphIndex = j;
			//	}
			//}
		}
		int temp = sortedIndices[i];
		sortedIndices[i] = sortedIndices[maxGlyphIndex];
		sortedIndices[maxGlyphIndex] = temp;
	}

	// tree
	struct SNode
	{
		SNode* m_pChild[2];
		SRect m_Rect;
		int m_CharIndex;

		SNode()
		{
			m_pChild[0] = NULL;
			m_pChild[1] = NULL;
			m_CharIndex = -1;
		}

		void Clear()
		{
			if (m_pChild[0] != NULL)
			{
				m_pChild[0]->Clear();
				SAFE_DELETE(m_pChild[0]);
			}
			if (m_pChild[1] != NULL)
			{
				m_pChild[1]->Clear();
				SAFE_DELETE(m_pChild[1]);
			}
		}

		SNode* Insert(const SCharData& data)
		{
			if (m_pChild[0] != NULL && m_pChild[1] != NULL)
			{
				// try inserting into first child
				SNode* pNewNode = m_pChild[0]->Insert(data);
				if (pNewNode != NULL)
				{
					return pNewNode;
				}

				// no room, insert into second
				return m_pChild[1]->Insert(data);
			}
			else
			{
				// if there's already a glyph here, return
				if (m_CharIndex >= 0)
				{
					return NULL;
				}

				int width = m_Rect.m_Right - m_Rect.m_Left;
				int height = m_Rect.m_Bottom - m_Rect.m_Top;
				// if we're too small, return
				if (data.m_Width > width ||
					data.m_Height > height)
				{
					return NULL;
				}

				// if we're just right, accept
				if (data.m_Width == width &&
					data.m_Height == height)
				{
					return this;
				}

				// otherwise, gotta split this node and create some kids
				m_pChild[0] = new SNode();
				m_pChild[1] = new SNode();

				// decide which way to split
				int dw = width - data.m_Width;
				int dh = height - data.m_Height;

				if (dw > dh)
				{
					m_pChild[0]->m_Rect = SRect(m_Rect.m_Left, m_Rect.m_Left + data.m_Width,
												m_Rect.m_Top, m_Rect.m_Bottom);
					m_pChild[1]->m_Rect = SRect(m_Rect.m_Left + data.m_Width + 1, m_Rect.m_Right,
												m_Rect.m_Top, m_Rect.m_Bottom);
				}
				else
				{
					m_pChild[0]->m_Rect = SRect(m_Rect.m_Left, m_Rect.m_Right,
												m_Rect.m_Top, m_Rect.m_Top + data.m_Height);
					m_pChild[1]->m_Rect = SRect(m_Rect.m_Left, m_Rect.m_Right,
												m_Rect.m_Top + data.m_Height + 1, m_Rect.m_Bottom);
				}

				// insert into first child we created
				return m_pChild[0]->Insert(data);
			}
			return NULL;
		}
	};

	int atlasWidth = 1024;
	int atlasHeight = 1024;
	unsigned char* atlasData = new unsigned char[atlasWidth * atlasHeight * 2];
	memset(atlasData, 128, atlasWidth * atlasHeight * 2);

	SNode* pRoot = new SNode();
	pRoot->m_Rect.m_Left = 0;
	pRoot->m_Rect.m_Right = atlasWidth - 1;
	pRoot->m_Rect.m_Top = 0;
	pRoot->m_Rect.m_Bottom = atlasHeight - 1;

	for (int i = 0; i < m_SymbolCount; i++)
	{
		//int placeX = i % 16;
		//int placeY = i / 16;
		SCharData& data = m_CharData[sortedIndices[i]];
		SNode* pNode = pRoot->Insert(data);
		if (pNode != NULL)
		{
			data.m_StartX = pNode->m_Rect.m_Left;
			data.m_StartY = pNode->m_Rect.m_Top;
			//int placeIndex = placeY * 64 * atlasWidth * 2 + placeX * 64 * 2;
			int placeIndex = pNode->m_Rect.m_Top * atlasWidth * 2 + pNode->m_Rect.m_Left * 2;
			for (int k = 0; k < data.m_Height; k++)
			{
				for (int l = 0; l < data.m_Width; l++)
				{
					int atlasIndexL = placeIndex + k * atlasWidth * 2 + l * 2 + 0;
					int atlasIndexA = placeIndex + k * atlasWidth * 2 + l * 2 + 1;
					int charIndexL = k * data.m_Width * 2 + l * 2 + 0;
					int charIndexA = k * data.m_Width * 2 + l * 2 + 1;
					atlasData[atlasIndexL] = data.m_pData[charIndexL];
					atlasData[atlasIndexA] = data.m_pData[charIndexA];
				}
			}
			pNode->m_CharIndex = sortedIndices[i];
		}
	}

	pRoot->Clear();
	SAFE_DELETE(pRoot);

	glGenTextures(1, &m_TextureID);
	glBindTexture(GL_TEXTURE_2D, m_TextureID);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA,
				 atlasWidth, atlasHeight,
				 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE,
				 atlasData);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

	SAFE_DELETE_ARRAY(atlasData);

	SAFE_DELETE_ARRAY(sortedIndices);

	SAFE_DELETE(pData);

	error = FT_Done_Face(face);
	if (error != 0)
	{
		//...
	}

	SAFE_DELETE(pData);

	m_Loaded = true;

	return m_Loaded;
}