// This is free and unencumbered software released into the public domain.
// Anyone is free to copy, modify, publish, use, compile, sell, or
// distribute this software, either in source code form or as a compiled
// binary, for any purpose, commercial or non-commercial, and by any
// means.
// In jurisdictions that recognize copyright laws, the author or authors
// of this software dedicate any and all copyright interest in the
// software to the public domain. We make this dedication for the benefit
// of the public at large and to the detriment of our heirs and
// successors. We intend this dedication to be an overt act of
// relinquishment in perpetuity of all present and future rights to this
// software under copyright law.
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
// OTHER DEALINGS IN THE SOFTWARE.
// For more information, please refer to <http://unlicense.org/>

#ifndef MICROPROFILE_ENABLED
#error "microprofile.h must be included before including microprofiledraw.h"
#endif

#ifndef MICROPROFILEDRAW_ENABLED
#define MICROPROFILEDRAW_ENABLED MICROPROFILE_ENABLED
#endif

#ifndef MICROPROFILEDRAW_API
#define MICROPROFILEDRAW_API
#endif

#if MICROPROFILEDRAW_ENABLED
MICROPROFILEDRAW_API void MicroProfileDrawInitGL();

MICROPROFILEDRAW_API void MicroProfileRender(uint32_t nWidth, uint32_t nHeight, float fScale);

MICROPROFILEDRAW_API void MicroProfileBeginDraw(uint32_t nWidth, uint32_t nHeight, float* pfProjection);
MICROPROFILEDRAW_API void MicroProfileBeginDraw(uint32_t nWidth, uint32_t nHeight, float fScale);
MICROPROFILEDRAW_API void MicroProfileEndDraw();

#ifdef MICROPROFILEDRAW_IMPL
struct MicroProfileDrawVertex
{
	float nX;
	float nY;
	uint32_t nColor;
	float fU;
	float fV;
};

struct MicroProfileDrawCommand
{
	uint32_t nCommand;
	uint32_t nNumVertices;
};

struct MicroProfileDrawContext
{
	enum
	{
		MAX_COMMANDS = 32,
		MAX_VERTICES = 16384,
	};

	bool bInitialized;

	GLuint nVAO;
	GLuint nVertexBuffer;
	GLuint nProgram;
	GLuint nTexture;

	int nAttributePosition;
	int nAttributeColor;
	int nAttributeTexture;
	int nUniformProjectionMatrix;

	uint32_t nVertexPos;
	uint32_t nCommandPos;

	MicroProfileDrawVertex nVertices[MAX_VERTICES];
	MicroProfileDrawCommand nCommands[MAX_COMMANDS];
};

MicroProfileDrawContext g_MicroProfileDraw;

#define Q0(d, member, v) d[0].member = v
#define Q1(d, member, v) d[1].member = v; d[3].member = v
#define Q2(d, member, v) d[4].member = v
#define Q3(d, member, v) d[2].member = v; d[5].member = v

#define FONT_TEX_X 1024
#define FONT_TEX_Y 9
#define FONT_SIZE (FONT_TEX_X*FONT_TEX_Y * 4)

namespace
{
	extern const uint8_t g_MicroProfileFont[];
	extern const uint16_t g_MicroProfileFontDescription[]; 

	extern const char g_MicroProfileVertexShader_110[];
	extern const char g_MicroProfileFragmentShader_110[];

	extern const char g_MicroProfileVertexShader_150[];
	extern const char g_MicroProfileFragmentShader_150[];
}

bool MicroProfileCompileShader(GLuint* pnHandle, int nType, const char* pShader)
{
	*pnHandle = glCreateShader(nType);
	glShaderSource(*pnHandle, 1, &pShader, 0);
	glCompileShader(*pnHandle);

	GLint compiled = 0;
	glGetShaderiv(*pnHandle, GL_COMPILE_STATUS, &compiled);

	if(!compiled)
	{
		char temp[4096];
		glGetShaderInfoLog(*pnHandle, 4096, NULL, temp);
		printf("SHADER FAILED TO COMPILE:\n%s\n", temp);
		return false;
	}

	return true;
}

bool MicroProfileLinkProgram(GLuint* pnHandle, GLuint nVertexShader, GLuint nFragmentShader)
{
	*pnHandle = glCreateProgram();
	glAttachShader(*pnHandle, nVertexShader);
	glAttachShader(*pnHandle, nFragmentShader);
	glLinkProgram(*pnHandle);

	GLint linked = 0;
	glGetProgramiv(*pnHandle, GL_LINK_STATUS, &linked);

	if(!linked)
	{
		char temp[4096];
		glGetProgramInfoLog(*pnHandle, 4096, NULL, temp);
		printf("PROGRAM FAILED TO LINK:\n%s\n", temp);
		return false;
	}

	return true;
}

void MicroProfileDrawInitGL()
{
	MicroProfileDrawContext& S = g_MicroProfileDraw;

	MP_ASSERT(!S.bInitialized);

	const GLubyte* pGLVersion = glGetString(GL_VERSION);
	const GLubyte* pGLSLVersion = glGetString(GL_SHADING_LANGUAGE_VERSION);

	int nGLVersion = (pGLVersion[0] - '0') * 10 + (pGLVersion[2] - '0');
	int nGLSLVersion = (pGLSLVersion[0] - '0') * 100 + (pGLSLVersion[2] - '0') * 10 + (pGLSLVersion[3] - '0');

	glGenBuffers(1, &S.nVertexBuffer);
	glBindBuffer(GL_ARRAY_BUFFER, S.nVertexBuffer);
	glBufferData(GL_ARRAY_BUFFER, sizeof(S.nVertices), 0, GL_STREAM_DRAW);
	glBindBuffer(GL_ARRAY_BUFFER, 0);

	if (nGLVersion >= 3)
		glGenVertexArrays(1, &S.nVAO);
	else
		S.nVAO = 0;

	GLuint nVertexShader;
	if(!MicroProfileCompileShader(&nVertexShader, GL_VERTEX_SHADER, nGLSLVersion >= 150 ? g_MicroProfileVertexShader_150 : g_MicroProfileVertexShader_110))
		return;

	GLuint nFragmentShader;
	if(!MicroProfileCompileShader(&nFragmentShader, GL_FRAGMENT_SHADER, nGLSLVersion >= 150 ? g_MicroProfileFragmentShader_150 : g_MicroProfileFragmentShader_110))
		return;

	if(!MicroProfileLinkProgram(&S.nProgram, nVertexShader, nFragmentShader))
		return;

	S.nAttributePosition = glGetAttribLocation(S.nProgram, "VertexIn");
	S.nAttributeColor = glGetAttribLocation(S.nProgram, "ColorIn");
	S.nAttributeTexture = glGetAttribLocation(S.nProgram, "TCIn");

	S.nUniformProjectionMatrix = glGetUniformLocation(S.nProgram, "ProjectionMatrix");

	glUseProgram(S.nProgram);
	glUniform1i(glGetUniformLocation(S.nProgram, "Texture"), 0);
	glUniform1f(glGetUniformLocation(S.nProgram, "RcpFontHeight"), 1.f / FONT_TEX_Y);
	glUseProgram(0);

	uint32_t* pUnpacked = (uint32_t*)alloca(FONT_SIZE);
	int idx = 0;
	int end = FONT_TEX_X * FONT_TEX_Y / 8;
	for(int i = 0; i < end; i++)
	{
		unsigned char pValue = g_MicroProfileFont[i];
		for(int j = 0; j < 8; ++j)
		{
			pUnpacked[idx++] = pValue & 0x80 ? (uint32_t)-1 : 0;
			pValue <<= 1;
		}
	}

	pUnpacked[idx-1] = 0xffffffff;

	uint32_t* p4 = &pUnpacked[0];
	glGenTextures(1, &S.nTexture);
	glBindTexture(GL_TEXTURE_2D, S.nTexture);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);     
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, FONT_TEX_X, FONT_TEX_Y, 0, GL_RGBA, GL_UNSIGNED_BYTE, &p4[0]);
	glBindTexture(GL_TEXTURE_2D, 0);

	S.bInitialized = true;
}

void MicroProfileBeginDraw(uint32_t nWidth, uint32_t nHeight, float* pfProjection)
{
	(void)nWidth;
	(void)nHeight;

	MicroProfileDrawContext& S = g_MicroProfileDraw;

	if (!S.bInitialized)
		return;

	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);

	if (S.nVAO)
		glBindVertexArray(S.nVAO);

	glUseProgram(S.nProgram);
	glUniformMatrix4fv(S.nUniformProjectionMatrix, 1, 0, pfProjection);

	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, S.nTexture);

	glBindBuffer(GL_ARRAY_BUFFER, S.nVertexBuffer);

	int nStride = sizeof(MicroProfileDrawVertex);

	glVertexAttribPointer(S.nAttributePosition, 2, GL_FLOAT, 0, nStride, (void*)(offsetof(MicroProfileDrawVertex, nX)));
	glVertexAttribPointer(S.nAttributeColor, 4, GL_UNSIGNED_BYTE, GL_TRUE, nStride, (void*)(offsetof(MicroProfileDrawVertex, nColor)));
	glVertexAttribPointer(S.nAttributeTexture, 2, GL_FLOAT, 0, nStride, (void*)(offsetof(MicroProfileDrawVertex, fU)));

	glEnableVertexAttribArray(S.nAttributePosition);
	glEnableVertexAttribArray(S.nAttributeColor);
	glEnableVertexAttribArray(S.nAttributeTexture);

	S.nVertexPos = 0;
	S.nCommandPos = 0;
}

void MicroProfileBeginDraw(uint32_t nWidth, uint32_t nHeight, float fScale)
{
	MicroProfileDrawContext& S = g_MicroProfileDraw;

	if (!S.bInitialized)
		return;

	float left = 0.f;
	float right = nWidth / fScale;
	float bottom = nHeight / fScale;
	float top = 0.f;
	float near_plane = -1.f;
	float far_plane = 1.f;

	float projection[16] = {};

	projection[0] = 2.0f / (right - left);
	projection[5] = 2.0f / (top - bottom);
	projection[10] = -2.0f / (far_plane - near_plane);
	projection[12] = - (right + left) / (right - left);
	projection[13] = - (top + bottom) / (top - bottom);
	projection[14] = - (far_plane + near_plane) / (far_plane - near_plane);
	projection[15] = 1.f;

	MicroProfileBeginDraw(nWidth, nHeight, projection);
}

void MicroProfileFlush()
{
	MicroProfileDrawContext& S = g_MicroProfileDraw;

	if(S.nVertexPos == 0)
		return;

	MICROPROFILE_SCOPEI("MicroProfile", "Flush", 0xffff3456);

	glBufferSubData(GL_ARRAY_BUFFER, 0, S.nVertexPos * sizeof(MicroProfileDrawVertex), S.nVertices);

	int nOffset = 0;

	for(int i = 0; i < int(S.nCommandPos); ++i)
	{
		int nCount = S.nCommands[i].nNumVertices;
		glDrawArrays(S.nCommands[i].nCommand, nOffset, nCount);
		nOffset += nCount;
	}

	S.nVertexPos = 0;
	S.nCommandPos = 0;
}

MicroProfileDrawVertex* MicroProfilePushVertices(uint32_t nCommand, int nCount)
{
	MP_ASSERT(nCount <= MicroProfileDrawContext::MAX_VERTICES);

	MicroProfileDrawContext& S = g_MicroProfileDraw;

	if(S.nVertexPos + nCount > MicroProfileDrawContext::MAX_VERTICES)
		MicroProfileFlush();

	if(S.nCommandPos && S.nCommands[S.nCommandPos-1].nCommand == nCommand)
	{
		S.nCommands[S.nCommandPos-1].nNumVertices += nCount;
	}
	else
	{
		if (S.nCommandPos == MicroProfileDrawContext::MAX_COMMANDS)
			MicroProfileFlush();

		S.nCommands[S.nCommandPos].nCommand = nCommand;
		S.nCommands[S.nCommandPos].nNumVertices = nCount;
		S.nCommandPos++;
	}

	uint32_t nOut = S.nVertexPos;
	S.nVertexPos += nCount;

	return &S.nVertices[nOut];
}

void MicroProfileEndDraw()
{
	MicroProfileDrawContext& S = g_MicroProfileDraw;

	if (!S.bInitialized)
		return;

	MicroProfileFlush();

	glDisableVertexAttribArray(S.nAttributePosition);
	glDisableVertexAttribArray(S.nAttributeColor);
	glDisableVertexAttribArray(S.nAttributeTexture);

	glBindBuffer(GL_ARRAY_BUFFER, 0);
	glUseProgram(0);

	if (S.nVAO)
		glBindVertexArray(0);

	glDisable(GL_BLEND);
}

void MicroProfileRender(uint32_t nWidth, uint32_t nHeight, float fScale)
{
	MicroProfileBeginDraw(nWidth, nHeight, fScale);
	MicroProfileDraw(nWidth, nHeight);
	MicroProfileEndDraw();
}

void MicroProfileDrawText(int nX, int nY, uint32_t nColor, const char* pText, uint32_t nLen)
{
	MICROPROFILE_SCOPEI("MicroProfile", "TextDraw", 0xff88ee);

	const float fOffsetU = 5.f / 1024.f;
	MP_ASSERT(nLen <= strlen(pText));
	float fX = (float)nX;
	float fY = (float)nY;
	float fY2 = fY + (MICROPROFILE_TEXT_HEIGHT+1);

	MicroProfileDrawVertex* pVertex = MicroProfilePushVertices(GL_TRIANGLES, 6 * nLen);
	if (!pVertex) return;

	const char* pStr = pText;
	nColor = 0xff000000|((nColor&0xff)<<16)|(nColor&0xff00)|((nColor>>16)&0xff);

	for(uint32_t j = 0; j < nLen; ++j)
	{
		int16_t nOffset = g_MicroProfileFontDescription[uint8_t(*pStr++)];
		float fOffset = nOffset / 1024.f;
		Q0(pVertex,nX, fX);
		Q0(pVertex,nY, fY);
		Q0(pVertex,nColor, nColor);
		Q0(pVertex,fU, fOffset);
		Q0(pVertex,fV, 0.f);
		
		Q1(pVertex, nX, fX+MICROPROFILE_TEXT_WIDTH);
		Q1(pVertex, nY, fY);
		Q1(pVertex, nColor, nColor);
		Q1(pVertex, fU, fOffset+fOffsetU);
		Q1(pVertex, fV, 0.f);

		Q2(pVertex, nX, fX+MICROPROFILE_TEXT_WIDTH);
		Q2(pVertex, nY, fY2);
		Q2(pVertex, nColor, nColor);
		Q2(pVertex, fU, fOffset+fOffsetU);
		Q2(pVertex, fV, 1.f);


		Q3(pVertex, nX, fX);
		Q3(pVertex, nY, fY2);
		Q3(pVertex, nColor, nColor);
		Q3(pVertex, fU, fOffset);
		Q3(pVertex, fV, 1.f);

		fX += MICROPROFILE_TEXT_WIDTH+1;
		pVertex += 6;
	}
}
void MicroProfileDrawBox(int nX0, int nY0, int nX1, int nY1, uint32_t nColor, MicroProfileBoxType Type)
{
	MicroProfileDrawVertex* pVertex = MicroProfilePushVertices(GL_TRIANGLES, 6);
	if (!pVertex) return;

	if(Type == MicroProfileBoxTypeFlat)
	{
		nColor = ((nColor&0xff)<<16)|((nColor>>16)&0xff)|(0xff00ff00&nColor);
		Q0(pVertex, nX, (float)nX0);
		Q0(pVertex, nY, (float)nY0);
		Q0(pVertex, nColor, nColor);
		Q0(pVertex, fU, 2.f);
		Q0(pVertex, fV, 2.f);
		Q1(pVertex, nX, (float)nX1);
		Q1(pVertex, nY, (float)nY0);
		Q1(pVertex, nColor, nColor);
		Q1(pVertex, fU, 2.f);
		Q1(pVertex, fV, 2.f);
		Q2(pVertex, nX, (float)nX1);
		Q2(pVertex, nY, (float)nY1);
		Q2(pVertex, nColor, nColor);
		Q2(pVertex, fU, 2.f);
		Q2(pVertex, fV, 2.f);
		Q3(pVertex, nX, (float)nX0);
		Q3(pVertex, nY, (float)nY1);
		Q3(pVertex, nColor, nColor);
		Q3(pVertex, fU, 2.f);
		Q3(pVertex, fV, 2.f);
	}
	else
	{
		uint32_t r = 0xff & (nColor>>16);
		uint32_t g = 0xff & (nColor>>8);
		uint32_t b = 0xff & nColor;
		uint32_t nMax = MicroProfileMax(MicroProfileMax(MicroProfileMax(r, g), b), 30u);
		uint32_t nMin = MicroProfileMin(MicroProfileMin(MicroProfileMin(r, g), b), 180u);

		uint32_t r0 = 0xff & ((r + nMax)/2);
		uint32_t g0 = 0xff & ((g + nMax)/2);
		uint32_t b0 = 0xff & ((b + nMax)/2);

		uint32_t r1 = 0xff & ((r+nMin)/2);
		uint32_t g1 = 0xff & ((g+nMin)/2);
		uint32_t b1 = 0xff & ((b+nMin)/2);
		uint32_t nColor0 = (r0<<0)|(g0<<8)|(b0<<16)|(0xff000000&nColor);
		uint32_t nColor1 = (r1<<0)|(g1<<8)|(b1<<16)|(0xff000000&nColor);
		Q0(pVertex, nX, (float)nX0);
		Q0(pVertex, nY, (float)nY0);
		Q0(pVertex, nColor, nColor0);
		Q0(pVertex, fU, 2.f);
		Q0(pVertex, fV, 2.f);
		Q1(pVertex, nX, (float)nX1);
		Q1(pVertex, nY, (float)nY0);
		Q1(pVertex, nColor, nColor0);
		Q1(pVertex, fU, 3.f);
		Q1(pVertex, fV, 2.f);
		Q2(pVertex, nX, (float)nX1);
		Q2(pVertex, nY, (float)nY1);
		Q2(pVertex, nColor, nColor1);
		Q2(pVertex, fU, 3.f);
		Q2(pVertex, fV, 3.f);
		Q3(pVertex, nX, (float)nX0);
		Q3(pVertex, nY, (float)nY1);
		Q3(pVertex, nColor, nColor1);
		Q3(pVertex, fU, 2.f);
		Q3(pVertex, fV, 3.f);
	}
}


void MicroProfileDrawLine2D(uint32_t nVertices, float* pVertices, uint32_t nColor)
{
	if(!nVertices) return;

	MicroProfileDrawVertex* pVertex = MicroProfilePushVertices(GL_LINES, 2*(nVertices-1));
	nColor = ((nColor&0xff)<<16)|(nColor&0xff00ff00)|((nColor>>16)&0xff);
	for(uint32_t i = 0; i < nVertices-1; ++i)
	{
		pVertex[0].nX = pVertices[i*2];
		pVertex[0].nY = pVertices[i*2+1] ;
		pVertex[0].nColor = nColor;
		pVertex[0].fU = 2.f;
		pVertex[0].fV = 2.f;
		pVertex[1].nX = pVertices[(i+1)*2];
		pVertex[1].nY = pVertices[(i+1)*2+1] ;
		pVertex[1].nColor = nColor;
		pVertex[1].fU = 2.f;
		pVertex[1].fV = 2.f;
		pVertex += 2;
	}
}

namespace
{
	const char g_MicroProfileVertexShader_110[] =
		"#version 110\n\
		uniform mat4 ProjectionMatrix; \
		attribute vec3 VertexIn; attribute vec4 ColorIn; attribute vec2 TCIn; \
		varying vec2 TC; varying vec4 Color; \
		void main() { Color = ColorIn; TC = TCIn; gl_Position = ProjectionMatrix * vec4(VertexIn, 1.0); }";

	const char g_MicroProfileVertexShader_150[] =
		"#version 150\n\
		uniform mat4 ProjectionMatrix; \
		in vec3 VertexIn; in vec4 ColorIn; in vec2 TCIn; \
		out vec2 TC; out vec4 Color; \
		void main() { Color = ColorIn; TC = TCIn; gl_Position = ProjectionMatrix * vec4(VertexIn, 1.0); }";

	const char g_MicroProfileFragmentShader_110[] =
		"#version 110\n\
		uniform sampler2D Texture; uniform float RcpFontHeight; \
		varying vec2 TC; varying vec4 Color; \
		void main() { \
			vec4 c0 = texture2D(Texture, TC.xy); \
			vec4 c1 = texture2D(Texture, TC.xy + vec2(0.0, RcpFontHeight)); \
			gl_FragColor = c0.w < 0.5 ? vec4(0, 0, 0, c1.w) : c0 * Color; \
		} \
	";

	const char g_MicroProfileFragmentShader_150[] =
		"#version 150\n\
		uniform sampler2D Texture; uniform float RcpFontHeight; \
		in vec2 TC; in vec4 Color; \
		out vec4 result; \
		void main() { \
			vec4 c0 = texture(Texture, TC.xy); \
			vec4 c1 = texture(Texture, TC.xy + vec2(0.0, RcpFontHeight)); \
			result = c0.w < 0.5 ? vec4(0, 0, 0, c1.w) : c0 * Color; \
		} \
	";

	const uint16_t g_MicroProfileFontDescription[] =
	{
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
		0x0ce,0x201,0x209,0x211,0x219,0x221,0x229,0x231,0x239,0x241,0x249,0x251,0x259,0x261,0x269,0x271,
		0x1b1,0x1b9,0x1c1,0x1c9,0x1d1,0x1d9,0x1e1,0x1e9,0x1f1,0x1f9,0x279,0x281,0x289,0x291,0x299,0x2a1,
		0x2a9,0x001,0x009,0x011,0x019,0x021,0x029,0x031,0x039,0x041,0x049,0x051,0x059,0x061,0x069,0x071,
		0x079,0x081,0x089,0x091,0x099,0x0a1,0x0a9,0x0b1,0x0b9,0x0c1,0x0c9,0x2b1,0x2b9,0x2c1,0x2c9,0x2d1,
		0x0ce,0x0d9,0x0e1,0x0e9,0x0f1,0x0f9,0x101,0x109,0x111,0x119,0x121,0x129,0x131,0x139,0x141,0x149,
		0x151,0x159,0x161,0x169,0x171,0x179,0x181,0x189,0x191,0x199,0x1a1,0x2d9,0x2e1,0x2e9,0x2f1,0x0ce,
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
		0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,0x0ce,
	};

	const uint8_t g_MicroProfileFont[] = 
	{
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x10,0x78,0x38,0x78,0x7c,0x7c,0x3c,0x44,0x38,0x04,0x44,0x40,0x44,0x44,0x38,0x78,
		0x38,0x78,0x38,0x7c,0x44,0x44,0x44,0x44,0x44,0x7c,0x00,0x00,0x40,0x00,0x04,0x00,
		0x18,0x00,0x40,0x10,0x08,0x40,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x38,0x10,0x38,0x7c,0x08,0x7c,0x1c,0x7c,0x38,0x38,
		0x10,0x28,0x28,0x10,0x00,0x20,0x10,0x08,0x10,0x10,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x04,0x00,0x20,0x38,0x38,0x70,0x00,0x1c,0x10,0x00,0x1c,0x10,0x70,0x30,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x28,0x44,0x44,0x44,0x40,0x40,0x40,0x44,0x10,0x04,0x48,0x40,0x6c,0x44,0x44,0x44,
		0x44,0x44,0x44,0x10,0x44,0x44,0x44,0x44,0x44,0x04,0x00,0x00,0x40,0x00,0x04,0x00,
		0x24,0x00,0x40,0x00,0x00,0x40,0x10,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x10,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x44,0x30,0x44,0x04,0x18,0x40,0x20,0x04,0x44,0x44,
		0x10,0x28,0x28,0x3c,0x44,0x50,0x10,0x10,0x08,0x54,0x10,0x00,0x00,0x00,0x04,0x00,
		0x00,0x08,0x00,0x10,0x44,0x44,0x40,0x40,0x04,0x28,0x00,0x30,0x10,0x18,0x58,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x44,0x44,0x40,0x44,0x40,0x40,0x40,0x44,0x10,0x04,0x50,0x40,0x54,0x64,0x44,0x44,
		0x44,0x44,0x40,0x10,0x44,0x44,0x44,0x28,0x28,0x08,0x00,0x38,0x78,0x3c,0x3c,0x38,
		0x20,0x38,0x78,0x30,0x18,0x44,0x10,0x6c,0x78,0x38,0x78,0x3c,0x5c,0x3c,0x3c,0x44,
		0x44,0x44,0x44,0x44,0x7c,0x00,0x4c,0x10,0x04,0x08,0x28,0x78,0x40,0x08,0x44,0x44,
		0x10,0x00,0x7c,0x50,0x08,0x50,0x00,0x20,0x04,0x38,0x10,0x00,0x00,0x00,0x08,0x10,
		0x10,0x10,0x7c,0x08,0x08,0x54,0x40,0x20,0x04,0x44,0x00,0x30,0x10,0x18,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x44,0x78,0x40,0x44,0x78,0x78,0x40,0x7c,0x10,0x04,0x60,0x40,0x54,0x54,0x44,0x78,
		0x44,0x78,0x38,0x10,0x44,0x44,0x54,0x10,0x10,0x10,0x00,0x04,0x44,0x40,0x44,0x44,
		0x78,0x44,0x44,0x10,0x08,0x48,0x10,0x54,0x44,0x44,0x44,0x44,0x60,0x40,0x10,0x44,
		0x44,0x44,0x28,0x44,0x08,0x00,0x54,0x10,0x18,0x18,0x48,0x04,0x78,0x10,0x38,0x3c,
		0x10,0x00,0x28,0x38,0x10,0x20,0x00,0x20,0x04,0x10,0x7c,0x00,0x7c,0x00,0x10,0x00,
		0x00,0x20,0x00,0x04,0x10,0x5c,0x40,0x10,0x04,0x00,0x00,0x60,0x10,0x0c,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x7c,0x44,0x40,0x44,0x40,0x40,0x4c,0x44,0x10,0x04,0x50,0x40,0x44,0x4c,0x44,0x40,
		0x54,0x50,0x04,0x10,0x44,0x44,0x54,0x28,0x10,0x20,0x00,0x3c,0x44,0x40,0x44,0x7c,
		0x20,0x44,0x44,0x10,0x08,0x70,0x10,0x54,0x44,0x44,0x44,0x44,0x40,0x38,0x10,0x44,
		0x44,0x54,0x10,0x44,0x10,0x00,0x64,0x10,0x20,0x04,0x7c,0x04,0x44,0x20,0x44,0x04,
		0x10,0x00,0x7c,0x14,0x20,0x54,0x00,0x20,0x04,0x38,0x10,0x10,0x00,0x00,0x20,0x10,
		0x10,0x10,0x7c,0x08,0x10,0x58,0x40,0x08,0x04,0x00,0x00,0x30,0x10,0x18,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x44,0x44,0x44,0x44,0x40,0x40,0x44,0x44,0x10,0x44,0x48,0x40,0x44,0x44,0x44,0x40,
		0x48,0x48,0x44,0x10,0x44,0x28,0x6c,0x44,0x10,0x40,0x00,0x44,0x44,0x40,0x44,0x40,
		0x20,0x3c,0x44,0x10,0x08,0x48,0x10,0x54,0x44,0x44,0x44,0x44,0x40,0x04,0x12,0x4c,
		0x28,0x54,0x28,0x3c,0x20,0x00,0x44,0x10,0x40,0x44,0x08,0x44,0x44,0x20,0x44,0x08,
		0x00,0x00,0x28,0x78,0x44,0x48,0x00,0x10,0x08,0x54,0x10,0x10,0x00,0x00,0x40,0x00,
		0x10,0x08,0x00,0x10,0x00,0x40,0x40,0x04,0x04,0x00,0x00,0x30,0x10,0x18,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x44,0x78,0x38,0x78,0x7c,0x40,0x3c,0x44,0x38,0x38,0x44,0x7c,0x44,0x44,0x38,0x40,
		0x34,0x44,0x38,0x10,0x38,0x10,0x44,0x44,0x10,0x7c,0x00,0x3c,0x78,0x3c,0x3c,0x3c,
		0x20,0x04,0x44,0x38,0x48,0x44,0x38,0x44,0x44,0x38,0x78,0x3c,0x40,0x78,0x0c,0x34,
		0x10,0x6c,0x44,0x04,0x7c,0x00,0x38,0x38,0x7c,0x38,0x08,0x38,0x38,0x20,0x38,0x70,
		0x10,0x00,0x28,0x10,0x00,0x34,0x00,0x08,0x10,0x10,0x00,0x20,0x00,0x10,0x00,0x00,
		0x20,0x04,0x00,0x20,0x10,0x3c,0x70,0x00,0x1c,0x00,0x7c,0x1c,0x10,0x70,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x38,0x00,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x40,0x04,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
		0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
	};
}
#endif
#endif
