/*
 * This source file is part of KEOS (Free 3D Engine)
 * For the latest info, see http://www.keosengine.org/
 * E-mails : thierry.vouriot@keosengine.org, yeri@keosengine.org
 * 
 * This program is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
 * Place - Suite 330, Boston, MA 02111-1307, USA, or go to
 * http://www.gnu.org/copyleft/lesser.txt.
 *
 */

#include "Keos.h"
using namespace Keos;

//-----------------------------------------------------------------------
/** Display cubes with alpha blending.
 */
class CTransparency : public IRenderApp
{
    //! Structure of the vertices
    struct TVertex
    {
        float X, Y, Z;
        unsigned long Color;
    };
    //! Indices type
    typedef ushort TIndex;

    //! Vertex buffer
    CBuffer<TVertex> m_VertexBuffer;
    //! Index buffer
    CBuffer<TIndex> m_IndexBuffer;
    //! Vertex declaration
    CDeclarationPtr m_Declaration;  

    //! View matrix 2D
    CMatrix4 m_MatView2D;
    //! View Matrix 3D
    CMatrix4 m_MatView3D;
    //! Projection matrix 2D
    CMatrix4 m_MatProj2D;
    //! Projection matrix 3D
    CMatrix4 m_MatProj3D;

    //! Rotation and scaling matrix
    CMatrix4 RotX, RotY, Scaling;
    //! Graphic string which display FPS informations
    CGraphicString*  m_pFPS;
        
    void Init(void) 
    {
        // Vertex buffer creation
        TVertex Vertices[] =
        {
            {-10,  10, -10, GetRenderSystem()->ConvertColor(0x6600FFFF)},
            { 10,  10, -10, GetRenderSystem()->ConvertColor(0x660000FF)},
            {-10, -10, -10, GetRenderSystem()->ConvertColor(0x66FF00FF)},
            { 10, -10, -10, GetRenderSystem()->ConvertColor(0x6600FFFF)},
            { 10,  10,  10, GetRenderSystem()->ConvertColor(0x660000FF)},
            {-10,  10,  10, GetRenderSystem()->ConvertColor(0x66FF00FF)},
            { 10, -10,  10, GetRenderSystem()->ConvertColor(0x6600FFFF)},
            {-10, -10,  10, GetRenderSystem()->ConvertColor(0x660000FF)}
            
        };
        m_VertexBuffer = GetRenderSystem()->CreateVertexBuffer(8, 0, Vertices);
        
        // Index buffer creation
        TIndex Indices[] =
        {   
            0, 1, 2, 2, 1, 3,
            4, 5, 6, 6, 5, 7,
            1, 4, 3, 3, 4, 6,
            5, 0, 7, 7, 0, 2,
            5, 4, 0, 0, 4, 1,
            2, 3, 7, 7, 3, 6
        };
        m_IndexBuffer = GetRenderSystem()->CreateIndexBuffer(36, 0, Indices);
        
        // Vertex declaration creation
        TDeclarationElement Decl[] =
        {
            {0, ELT_USAGE_POSITION, ELT_TYPE_FLOAT3},
            {0, ELT_USAGE_DIFFUSE,  ELT_TYPE_COLOR}
        };
        m_Declaration = GetRenderSystem()->CreateVertexDeclaration(Decl);

        // Init 3D transformation matrix
        m_MatView3D.LookAt(TVector3F(0, 0, -30), TVector3F(0, 0, 0));
        m_MatProj3D.PerspectiveFOV(3.14159f / 2, (Real)GetRenderTarget()->GetWidth()/(Real)GetRenderTarget()->GetHeight(), 1.0f, 300.0f);

        // Init 2D transformation matrix
        m_MatView2D.Identity();
        m_MatProj2D.OrthoOffCenter(0, 0, GetRenderTarget()->GetWidth(), GetRenderTarget()->GetHeight());

		CMediaManager::Instance().AddSearchPath("Textures");

        // Load font
        CMediaManager::Instance().AddSearchPath("Fonts");
        CFontManager::Instance().LoadFont("Atarian.ttf","Font",14);

        // Create graphic string
        String strFPS = "Current FPS: \nAverage FPS: \nBest FPS: \n Worst FPS:";
		strFPS += "\n\nF1 / F2 to show / hide the console, escape to exit";
        m_pFPS = new CGraphicString(TVector2I(0, 0), strFPS, CColor(255, 255, 255), "Font");
		
		m_pFPS->Align(ALIGN_LEFT | ALIGN_BOTTOM, CRectangle(10, 10, GetRenderTarget()->GetWidth()-20, GetRenderTarget()->GetHeight()-20)); 
		
        // Add a "look" to the console
        CConsole::Instance().ChangeLook(new Console::CLookDefault("Font", TVector2F(GetRenderTarget()->GetWidth(), (Real)GetRenderTarget()->GetHeight() / 3.0), "ConsoleBG.jpg"));	

        Scaling.SetScaling(0.5, 0.5, 0.5);
    }

    void Render(void)
    {
        // Switch to 3D mode
        GetRenderSystem()->LoadMatrix(MAT_MODELVIEW,  m_MatView3D);
        GetRenderSystem()->LoadMatrix(MAT_PROJECTION, m_MatProj3D);

        // Save current view matrix
        GetRenderSystem()->PushMatrix(MAT_MODELVIEW);

            // Save current view matrix
            GetRenderSystem()->PushMatrix(MAT_MODELVIEW);

                // Rotation
                GetRenderSystem()->LoadMatrixMult(MAT_MODELVIEW, RotX.Inverse()*RotY.Inverse());
                // Scaling /2
                GetRenderSystem()->LoadMatrixMult(MAT_MODELVIEW, Scaling);

                // Display cube
                GetRenderSystem()->SetDeclaration(m_Declaration);
                GetRenderSystem()->SetVertexBuffer(0, m_VertexBuffer);
                GetRenderSystem()->SetIndexBuffer(m_IndexBuffer);
                GetRenderSystem()->DrawIndexedPrimitives(PT_TRIANGLELIST, 0, m_IndexBuffer.GetCount() / 3);

            // Get the last view matrix
            GetRenderSystem()->PopMatrix(MAT_MODELVIEW);
            
            // Rotation
            GetRenderSystem()->LoadMatrixMult(MAT_MODELVIEW, RotX*RotY);
           
            // Alpha-blending function
            //Renderer->SetupAlphaBlending(BLEND_ONE, BLEND_ONE);
            Renderer->SetupAlphaBlending(BLEND_SRCALPHA, BLEND_INVSRCALPHA);

            // Enable alpha-blending
            Renderer->Enable(RENDER_ALPHABLEND, true);

            // Display cube
            GetRenderSystem()->DrawIndexedPrimitives(PT_TRIANGLELIST, 0, m_IndexBuffer.GetCount() / 3);
           
            // Disable alpha-blending
            Renderer->Enable(RENDER_ALPHABLEND, false);

        // Get the last view matrix
        GetRenderSystem()->PopMatrix(MAT_MODELVIEW);

         // Switch to 2D mode
        GetRenderSystem()->LoadMatrix(MAT_MODELVIEW,  m_MatView2D);
        GetRenderSystem()->LoadMatrix(MAT_PROJECTION, m_MatProj2D);
        
        // Draw text
        m_pFPS->Draw();

		// Draw console
        CConsole::Instance().Draw();
    }

    void Update(void)
    {
        uint nCurrentTime = GetTime();
		
        // Change the rotation matrix
        RotX.SetRotationX(nCurrentTime / 1500.f);
        RotY.SetRotationY(nCurrentTime / 1000.f);

        // Update the FPS text
        m_pFPS->Text = "Current FPS: " + CStringConverter::ToString(GetRenderTarget()->GetLastFPS()) + 
                     "\nAverage FPS: " + CStringConverter::ToString(GetRenderTarget()->GetAverageFPS()) +
                     "\nBest FPS: " + CStringConverter::ToString(GetRenderTarget()->GetBestFPS()) +
                     "\nWorst FPS: " + CStringConverter::ToString(GetRenderTarget()->GetWorstFPS()) +
					 "\n\nf1 / f2 to show / hide the console, escape to exit";
        
        // Console update
        CConsole::Instance().Update();
    }

    void Release(void)
    {
		delete m_pFPS;
    }
};

int main(int argc, char* argv[])
{ 
	KEOS_START();
    try
    { 
        CTransparency Transparency;
		// Show the configuration dialog and initialise the system
        // You can skip this and use KeosRoot.RestoreConfig() to load configuration
        // settings if you were sure there are valid ones saved in config.xml
        if (KeosRoot.ShowConfigDialog())
		{
			KeosRoot.Initialise(true, "KEOS Sample: Transparency");
			KeosRoot.GetRenderSystem()->SetRenderApp(&Transparency);
			KeosRoot.StartRendering();
		}
    }
    catch (const CException& E)
    {
        MessageBox(NULL, E.what(), "Keos Exception", MB_ICONWARNING);
    }

    KEOS_SHUTDOWN();
	return EXIT_SUCCESS;
}