#include "stdafx.h"
#include "XUI_FontRenderer.h"
#include "XUI_Font.h"
#include "XUI_FontData.h"
#include "..\..\..\Minecraft.World\StringHelpers.h"

extern IDirect3DDevice9 *g_pD3DDevice;
extern void GetRenderAndSamplerStates(IDirect3DDevice9 *pDevice,DWORD *RenderStateA,DWORD *SamplerStateA);
extern void SetRenderAndSamplerStates(IDirect3DDevice9 *pDevice,DWORD *RenderStateA,DWORD *SamplerStateA);

XUI_FontRenderer::XUI_FontRenderer()
{
	ZeroMemory(m_loadedFontData, sizeof(XUI_FontData*) * eFontData_MAX);

	//XuiFontSetRenderer(this);
	
	//Minecraft *pMinecraft=Minecraft::GetInstance();

	//ScreenSizeCalculator ssc(pMinecraft->options, pMinecraft->width_phys, pMinecraft->height_phys);
	//m_fScreenWidth=(float)pMinecraft->width_phys;
	//m_fRawWidth=(float)ssc.rawWidth;
	//m_fScreenHeight=(float)pMinecraft->height_phys;
	//m_fRawHeight=(float)ssc.rawHeight;
}

HRESULT XUI_FontRenderer::Init( float fDpi )
{
	return( S_OK );

}

VOID XUI_FontRenderer::Term()
{
	return;
}

HRESULT XUI_FontRenderer::GetCaps( DWORD * pdwCaps )
{
    if( pdwCaps != NULL )
	{
        // setting this means XUI calls the DrawCharsToDevice method
        *pdwCaps = XUI_FONT_RENDERER_CAP_INTERNAL_GLYPH_CACHE | XUI_FONT_RENDERER_CAP_POINT_SIZE_RESPECTED | XUI_FONT_RENDERER_STYLE_DROPSHADOW;
	}
	return ( S_OK );
}

HRESULT XUI_FontRenderer::CreateFont( const TypefaceDescriptor * pTypefaceDescriptor, float fPointSize, DWORD dwStyle, DWORD dwReserved, HFONTOBJ * phFont )
{
	float fXuiSize = fPointSize * ( 16.0f / 14.0f );
	//float fXuiSize = fPointSize * ( 16.0f / 16.0f );
	fXuiSize /= 4.0f;
	fXuiSize = floor( fXuiSize );
	int xuiSize = (int)(fXuiSize * 4.0f);
	if( xuiSize < 1 ) xuiSize = 8;

	// 4J Stu - We have fonts based on multiples of 8 or 12
	// We don't want to make the text larger as then it may not fit in the box specified
	// so we decrease the size until we find one that will look ok
	while( xuiSize%8!=0 && xuiSize%12!=0 ) xuiSize -= 2;

	//app.DebugPrintf("point size is: %f, xuiSize is: %d\n", fPointSize, xuiSize);

	XUI_Font *font = NULL;
	XUI_FontData *fontData = NULL;
	FLOAT scale = 1;

	eFontData efontdata;
	if( xuiSize%12==0 )
	{
		scale = xuiSize/12;
		efontdata = eFontData_Mojangles_11;
	}
	else
	{
		scale = xuiSize/8;
		efontdata = eFontData_Mojangles_7;
	}

	font = m_loadedFonts[efontdata][scale];
	if (font == NULL)
	{
		fontData = m_loadedFontData[efontdata];
		if (fontData == NULL)
		{
			SFontData *sfontdata;
			switch (efontdata)
			{
			case eFontData_Mojangles_7:		sfontdata = &SFontData::Mojangles_7;	break;
			case eFontData_Mojangles_11:	sfontdata = &SFontData::Mojangles_11;	break;
			default:						sfontdata = NULL;						break;
			}

			fontData = new XUI_FontData();
			fontData->Create(*sfontdata);

			m_loadedFontData[efontdata] = fontData;
		}

		font = new XUI_Font( efontdata, scale, fontData );
		m_loadedFonts[efontdata][scale] = font;
	}
	font->IncRefCount();

	*phFont = (HFONTOBJ)font;
	return S_OK;
}

VOID XUI_FontRenderer::ReleaseFont( HFONTOBJ hFont )
{
	XUI_Font *xuiFont = (XUI_Font*) hFont;
	if (xuiFont != NULL)
	{
		xuiFont->DecRefCount();
		if (xuiFont->refCount <= 0)
		{
			AUTO_VAR(it, m_loadedFonts[xuiFont->m_iFontData].find(xuiFont->m_fScaleFactor) );
			if (it != m_loadedFonts[xuiFont->m_iFontData].end()) m_loadedFonts[xuiFont->m_iFontData].erase(it);
			delete hFont;
		}
	}
	return;
}

HRESULT XUI_FontRenderer::GetFontMetrics( HFONTOBJ hFont, XUIFontMetrics *pFontMetrics )
{
    if( hFont == 0 || pFontMetrics == 0 ) return E_INVALIDARG;

	XUI_Font *font = (XUI_Font *)hFont;

	pFontMetrics->fLineHeight =		(font->m_fontData->getFontYAdvance() + 1) * font->m_fYScaleFactor;
	pFontMetrics->fMaxAscent =		font->m_fontData->getMaxAscent() * font->m_fYScaleFactor;
	pFontMetrics->fMaxDescent =		font->m_fontData->getMaxDescent() * font->m_fYScaleFactor;
	pFontMetrics->fMaxHeight =		font->m_fontData->getFontHeight() * font->m_fYScaleFactor;
	pFontMetrics->fMaxWidth =		font->m_fontData->getFontMaxWidth() * font->m_fXScaleFactor;
	pFontMetrics->fMaxAdvance =		font->m_fontData->getFontMaxWidth() * font->m_fXScaleFactor;

	//*pFontMetrics = font->m_fontMetrics; // g_fontMetrics;
    return( S_OK );
}

HRESULT XUI_FontRenderer::GetCharMetrics( HFONTOBJ hFont, WCHAR wch, XUICharMetrics *pCharMetrics )
{
    if (hFont == 0 || pCharMetrics == 0) return E_INVALIDARG;

	XUI_Font *font = (XUI_Font *)hFont;
	XUI_FontData::SChar sChar = font->m_fontData->getChar(wch);

	pCharMetrics->fMinX = sChar.getMinX() * font->m_fYScaleFactor;
	pCharMetrics->fMinY = sChar.getMinY() * font->m_fYScaleFactor;
	pCharMetrics->fMaxX = sChar.getMaxX() * font->m_fYScaleFactor;
	pCharMetrics->fMaxY = sChar.getMaxY() * font->m_fYScaleFactor;
	pCharMetrics->fAdvance = sChar.getAdvance() * font->m_fYScaleFactor;

    return(S_OK);
}

HRESULT XUI_FontRenderer::DrawCharToTexture( HFONTOBJ hFont, WCHAR wch, HXUIDC hDC, IXuiTexture * pTexture, UINT x, UINT y, UINT width, UINT height, UINT insetX, UINT insetY )
{
    if( hFont==0 || pTexture==NULL ) return E_INVALIDARG;
    return( S_OK );
}

HRESULT XUI_FontRenderer::DrawCharsToDevice( HFONTOBJ hFont, CharData * pCharData, DWORD dwCount, RECT *pClipRect, HXUIDC hDC, D3DXMATRIX * pWorldViewProj )
{
    if( hFont == 0 ) return E_INVALIDARG;
    if( dwCount == 0 ) return( S_OK );

	DWORD RenderStateA[8];
	DWORD SamplerStateA[5];
	XMVECTOR vconsts[20];
	XMVECTOR pconsts[20];
	XUI_Font *font = (XUI_Font *)hFont;

	// 4J-PB - if we're in 480 Widescreen mode, we need to ensure that the font characters are aligned on an even boundary if they are a 2x multiple
	if(!RenderManager.IsHiDef())
	{
		if(RenderManager.IsWidescreen())
		{		
			float fScaleX, fScaleY;
			font->GetScaleFactors(&fScaleX,&fScaleY);
			int iScaleX=fScaleX;
			int iScaleY=fScaleY;

			if(iScaleX%2==0)
			{
				int iWorldX=pWorldViewProj->_41;
				pWorldViewProj->_41 = (float)(iWorldX & -2);
			}
			if(iScaleY%2==0)
			{
				int iWorldY=pWorldViewProj->_42;
				pWorldViewProj->_42 = (float)(iWorldY & -2);
			}
		}
		else
		{
			// make x an even number for 480 4:3
			int iWorldX=pWorldViewProj->_41;
			pWorldViewProj->_41 = (float)(iWorldX & -2);

			// 480 SD mode - y needs to be on a pixel boundary when multiplied by 1.5, so if it's an odd number, subtract 1/3 from it
			int iWorldY=pWorldViewProj->_42;
			if(iWorldY%2==1)
			{
				pWorldViewProj->_42-=1.0f/3.0f;
			}
		}
	}

	g_pD3DDevice->GetVertexShaderConstantF( 0, (float *)vconsts, 20 );
	g_pD3DDevice->GetPixelShaderConstantF( 0, (float *)pconsts, 20 );
	g_pD3DDevice->SetRenderState(D3DRS_HALFPIXELOFFSET, TRUE);
	GetRenderAndSamplerStates(g_pD3DDevice, RenderStateA, SamplerStateA );
	glDisable(GL_CULL_FACE);
	glDisable(GL_DEPTH_TEST);

	RenderManager.Set_matrixDirty();
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	glOrtho(0, 1280.0f, 720.0f, 0, 1000, 3000);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	glTranslatef(0, 0, -2000);
	glColor4f(1.0f,1.0f,1.0f,1.0f);
	float matrixCopy[16];
	memcpy(matrixCopy, pWorldViewProj, 64);
	matrixCopy[11] = 0.0f;
	matrixCopy[12] = floor(matrixCopy[12] + 0.5f);
	matrixCopy[13] = floor(matrixCopy[13] + 0.5f);
	matrixCopy[14] = floor(matrixCopy[14] + 0.5f);
	matrixCopy[15] = 1.0f;
	glMultMatrixf(matrixCopy);
	
	
	float lineXPos = 0.0f;
	float lineYPos = 0.0f;
	DWORD colour = 0;
	DWORD style = 0;
#if 1
	for( int i = 0; i < dwCount; i++ )
	{
		wstring string;
		string.push_back(pCharData[i].wch);
		lineYPos = pCharData[i].y;
		lineXPos = pCharData[i].x;
		colour = pCharData[i].dwColor;
		style = pCharData[i].dwStyle;

		//if(pCharData[i].wch > font->m_fontData->getMaxGlyph())
		if ( !font->m_fontData->getChar(pCharData[i].wch).hasChar() )
		{
			// Can't render this character, fallback to the default renderer
			app.OverrideFontRenderer(false,false);
			break;
		}
#else
	DWORD i = 0;
	while( i < dwCount )
	{
		wstring string;
		lineYPos = pCharData[i].y;
		lineXPos = pCharData[i].x;
		colour = pCharData[i].dwColor;
		style = pCharData[i].dwStyle;
		
		while(i < dwCount && pCharData[i].y == lineYPos)
		{
			string.push_back(pCharData[i].wch);
			++i;
		}
#endif

		bool dropShadow = false;
		if( (style & XUI_FONT_STYLE_DROPSHADOW) == XUI_FONT_STYLE_DROPSHADOW) dropShadow = true;

		//int yPos = (int)pCharData[i].y + (int)(font->m_fontMetrics.fLineHeight - font->m_fontMetrics.fMaxAscent)/2;
		//if( (pCharData[i].dwStyle & XUI_FONT_STYLE_VERTICAL_CENTER) == XUI_FONT_STYLE_VERTICAL_CENTER)
		//{
		//	yPos = (pClipRect->bottom - (int)font->m_fontMetrics.fLineHeight) / 2;
		//}

		if(dropShadow)
		{
			DWORD shadowColour;
			XuiGetTextDropShadowColor(hDC, &shadowColour);
			// 4J Stu - Shadow colour is currently ignored
			font->DrawShadowText( lineXPos,lineYPos,colour,shadowColour,string.c_str() );
			//drawShadow(thisChar, (int)pCharData[i].x, yPos, pCharData[i].dwColor );
		}
		else
		{
			font->DrawText( lineXPos,lineYPos,colour,string.c_str() );
			//draw(thisChar, (int)pCharData[i].x, yPos, pCharData[i].dwColor, false );
		}
	}

	g_pD3DDevice->SetVertexShaderConstantF( 0, (float *)vconsts, 20 );
	g_pD3DDevice->SetPixelShaderConstantF( 0, (float *)pconsts, 20 );
	SetRenderAndSamplerStates(g_pD3DDevice, RenderStateA, SamplerStateA );
	g_pD3DDevice->SetRenderState(D3DRS_HALFPIXELOFFSET, FALSE);
	glEnable(GL_CULL_FACE);
	glEnable(GL_DEPTH_TEST);
	
	XuiRenderRestoreState(hDC);

    return( S_OK );
}
