Bomberman-OverlordEngine-x64 / OverlordEngine / Content / SpriteFontLoader.cpp
SpriteFontLoader.cpp
Raw
#include "stdafx.h"
#include "SpriteFontLoader.h"

SpriteFont* SpriteFontLoader::LoadContent(const ContentLoadInfo& loadInfo)
{
	const auto pReader = new BinaryReader();
	pReader->Open(loadInfo.assetFullPath);

	if (!pReader->Exists())
	{
		Logger::LogError(L"Failed to read the assetFile!\nPath: \'{}\'", loadInfo.assetSubPath);
		return nullptr;
	}

	//See BMFont Documentation for Binary Layout

	//Parse the Identification bytes (B,M,F)
	if (pReader->Read<char>() != 'B' || pReader->Read<char>() != 'M' || pReader->Read<char>() != 'F')
	{
		Logger::LogError(L"SpriteFontLoader::LoadContent > Not a valid .fnt font");
		return nullptr;
	}

	//Check is version 3
	if (pReader->Read<char>() < 3)
	{
		Logger::LogError(L"SpriteFontLoader::LoadContent > Only .fnt version 3 is supported");
		return nullptr;
	}

	//Valid .fnt file >> Start Parsing!
	//use this SpriteFontDesc to store all relevant information (used to initialize a SpriteFont object)
	SpriteFontDesc fontDesc{};

	//**********
	// BLOCK 0 *
	//**********
	//Retrieve the blockId and blockSize
	int(pReader->Read<char>());
	pReader->Read<int>();
	//Retrieve the FontSize [fontDesc.fontSize]
	fontDesc.fontSize = pReader->Read<short>();
	//Move the binreader to the start of the FontName [BinaryReader::MoveBufferPosition(...) or you can set its position using BinaryReader::SetBufferPosition(...))
	pReader->MoveBufferPosition(12); // Move to FontName
	//Retrieve the FontName [fontDesc.fontName]
	fontDesc.fontName = pReader->ReadNullString();
	//...

	//**********
	// BLOCK 1 *
	//**********
	//Retrieve the blockId and blockSize
	int(pReader->Read<char>());
	pReader->Read<int>();
	//Retrieve Texture Width & Height [fontDesc.textureWidth/textureHeight]
	pReader->MoveBufferPosition(4);
	fontDesc.textureWidth = pReader->Read<short>();
	fontDesc.textureHeight = pReader->Read<short>();
	//Retrieve PageCount
	short pageCount = pReader->Read<short>();
	//> if pagecount > 1
	if (pageCount > 1)
	{
		//	> Log Error (Only one texture per font is allowed!)
		Logger::LogError(L"Only one texture per font is allowed!");
	}
	//Advance to Block2 (Move Reader)
	pReader->MoveBufferPosition(5);

	//**********
	// BLOCK 2 *
	//**********
	//Retrieve the blockId and blockSize
	int(pReader->Read<char>());
	pReader->Read<int>();
	//Retrieve the PageName (BinaryReader::ReadNullString)
	std::wstring pageName = pReader->ReadNullString();
	//Construct the full path to the page texture file
	//	>> page texture should be stored next to the .fnt file, pageName contains the name of the texture file
	//	>> full texture path = asset parent_path of .fnt file (see loadInfo.assetFullPath > get parent_path) + pageName (filesystem::path::append)
	std::filesystem::path fullPath = std::filesystem::path(loadInfo.assetFullPath).parent_path();
	fullPath.append(pageName.begin(), pageName.end());
	//	>> Load the texture (ContentManager::Load<TextureData>) & Store [fontDesc.pTexture]
	fontDesc.pTexture = ContentManager::Load<TextureData>(fullPath.wstring());
	
	//**********
	// BLOCK 3 *
	//**********
	//Retrieve the blockId and blockSize
	int(pReader->Read<char>());
	int blockSize = pReader->Read<int>();
	blockSize;
	//Retrieve Character Count (see documentation)
	int charCount = blockSize / 20;
	//Create loop for Character Count, and:
	for (int i = 0; i < charCount; ++i)
	{
		//	> Create instance of FontMetric (struct)
		FontMetric metric{};

		//	> Retrieve CharacterId (store Local) and cast to a 'wchar_t'
		wchar_t charId = wchar_t(pReader->Read<UINT>());
		//	> Set Character (CharacterId) [FontMetric::character]
		metric.character = charId;

		//	> Retrieve Xposition (store Local)
		//	> Retrieve Yposition (store Local)
		unsigned short xPos = pReader->Read<unsigned short>();
		unsigned short yPos = pReader->Read<unsigned short>();

		//	> Retrieve & Set Width [FontMetric::width]
		metric.width = pReader->Read<unsigned short>();

		//	> Retrieve & Set Height [FontMetric::height]
		metric.height = pReader->Read<unsigned short>();

		//	> Retrieve & Set OffsetX [FontMetric::offsetX]
		//	> Retrieve & Set OffsetY [FontMetric::offsetY]
		metric.offsetX = pReader->Read<short>();
		metric.offsetY = pReader->Read<short>();

		//	> Retrieve & Set AdvanceX [FontMetric::advanceX]
		metric.advanceX = pReader->Read<short>();

		//	> Retrieve & Set Page [FontMetric::page]
		metric.page = pReader->Read<unsigned char>();

		//	> Retrieve Channel (BITFIELD!!!) 
		//	> See documentation for BitField meaning [FontMetric::channel]
		unsigned char channel{ pReader->Read<unsigned char>() };
		switch (channel)
		{
		default:
			metric.channel = 0;
			break;
		case 0x1:
			metric.channel = 2;
			break;
		case 0x2:
			metric.channel = 1;
			break;
		case 0x4:
			metric.channel = 0;
			break;
		case 0x8:
			metric.channel = 4;
			break;
		case 0xF:
			metric.channel = 0;
		}

		//	> Calculate Texture Coordinates using Xposition, Yposition, fontDesc.TextureWidth & fontDesc.TextureHeight [FontMetric::texCoord]
		metric.texCoord = { (float)xPos / (float)fontDesc.textureWidth, (float)yPos / (float)fontDesc.textureHeight };

		//> Insert new FontMetric to the metrics [font.metrics] map
		//	> key = (wchar_t) charId
		//	> value = new FontMetric
		//(loop restarts till all metrics are parsed)
		fontDesc.metrics.insert(std::make_pair(charId, metric));
	}

	//Done!
	delete pReader;
	return new SpriteFont(fontDesc);
}

void SpriteFontLoader::Destroy(SpriteFont* objToDestroy)
{
	SafeDelete(objToDestroy);
}