#include <windows.h>

#include <d3d8.h>
#include <d3dx8math.h>
#include <dshow.h>
#include <streams.h>

#include <stdio.h>

#pragma comment ( lib , "d3d8.lib" )
#pragma comment ( lib , "d3dx8.lib" )

#pragma warning( disable : 4305 )
#pragma warning( disable : 4018 )
#pragma warning( disable : 4067 )
#pragma warning( disable : 4244 )

#define __HOME__

#ifdef __HOME__
#include "d:\job\include\ParticleSystem.h"
#include "d:\job\include\D3DVertex.h"
#include "d:\job\include\ResourceManager.h"
#include "d:\job\include\Matrix4x4.h"
#include "d:\job\include\Cam.h"
#include "d:\job\include\SystemObjects.h"
#include "d:\job\include\D3DVertexBuffer.h"
#else
#include "include\ParticleSystem.h"
#include "include\D3DVertex.h"
#include "include\ResourceManager.h"
#include "include\Matrix4x4.h"
#include "include\Cam.h"
#include "include\SystemObjects.h"
#include "include\D3DVertexBuffer.h"
#endif

void Direct3DRelease( void ){
	if( D3DDevice )
		D3DDevice->Release();
	D3DDevice=NULL;

	if( D3DObject )
		D3DObject->Release();
	D3DObject=NULL;
}

cD3DFont		D3DFont;

bool Direct3DInit(HWND hWnd){
	D3DDISPLAYMODE			DisplayMode;
	D3DPRESENT_PARAMETERS	PresentParameters;

	//creating d3d object
	D3DObject = Direct3DCreate8(D3D_SDK_VERSION);if( FAILED( D3DObject ) ){MessageBox( NULL , "Error cretaing D3DObject!" , "Error" , MB_OK );return(false);}
	
	//setting display mode
	DisplayMode.Width		= D3D_SCREEN_WIDTH;
	DisplayMode.Height		= D3D_SCREEN_HEIGHT;
	DisplayMode.RefreshRate	= 0;
	DisplayMode.Format		= D3DFMT_X8R8G8B8;

	memset( &PresentParameters , 0 , sizeof( D3DPRESENT_PARAMETERS ) );
	PresentParameters.Windowed						= FALSE;
	PresentParameters.SwapEffect					= D3DSWAPEFFECT_DISCARD; 
	PresentParameters.BackBufferCount				= 1;
	PresentParameters.BackBufferFormat				= DisplayMode.Format;
	PresentParameters.BackBufferWidth				= DisplayMode.Width;
	PresentParameters.BackBufferHeight				= DisplayMode.Height;
	PresentParameters.FullScreen_RefreshRateInHz	= D3DPRESENT_RATE_DEFAULT;
	PresentParameters.EnableAutoDepthStencil		= TRUE;
	PresentParameters.AutoDepthStencilFormat		= D3DFMT_D24S8;

	HRESULT hr = D3DObject->CreateDevice( D3DADAPTER_DEFAULT , D3DDEVTYPE_HAL , hWnd , D3DCREATE_HARDWARE_VERTEXPROCESSING , &PresentParameters, &D3DDevice );

	if( FAILED( hr ) ){
		if( D3DERR_NOTAVAILABLE )MessageBox( NULL , "Error creating D3DDevice( Unavaiable Mode )" , "Error" , MB_OK );
		if( D3DERR_OUTOFVIDEOMEMORY )MessageBox( NULL , "Error creating D3DDevice( Out of memory )" , "Error" , MB_OK );
		return( false );
	}

	D3DDevice->SetRenderState( D3DRS_LIGHTING , FALSE );
	D3DDevice->SetRenderState( D3DRS_CULLMODE , D3DCULL_NONE );

	D3DXMATRIX projection_matrix;
	D3DXMatrixPerspectiveFovRH( &projection_matrix , D3DX_PI / 4 , ( float )D3D_SCREEN_WIDTH / ( float )D3D_SCREEN_HEIGHT , 0.1f , 1000000.0f );
	D3DDevice->SetTransform( D3DTS_PROJECTION, &( D3DMATRIX )projection_matrix );
	D3DXMatrixIdentity(&projection_matrix);

	Camera.D3DCameraInit( cPoint( 0 , 0 , 1 ) , cPoint( 0 , 0 , -1 ) , cPoint( 0 , 1 , 0 ) );

	return( true );
}

cParticleSystem				PS;

class		cKernel{
	int						ProcessState;
public:
	HWND					hWnd;
	cKernel( void );
	void					CreateViewPort( HINSTANCE , int );
	void					MainLoop( void );
	void					Display( void );
};

cKernel::cKernel( void ){
	ProcessState = 1;
	CoInitialize( NULL );
}

cKernel							Kernel;

void					cKernel::Display( void ){
	Camera.D3DCameraKeyboardInput( KBManager );
	Camera.D3DCameraMouseInput();

	PS.RunSystem( 1 );
	PS.Render( D3DDevice );

	D3DDevice->Present( NULL , NULL , NULL , NULL );
	D3DDevice->Clear( 0 , NULL , D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER , D3DCOLOR_XRGB( 0 , 0 , 0 ) , 1.0f , 0 );/**/
}

void					cKernel::MainLoop( void ){
	MSG						Msg;

	while( GetMessage( &Msg , NULL , NULL , NULL ) ){
		TranslateMessage( &Msg );
		DispatchMessage( &Msg );
		Display();
	}
}

void					cKernel::CreateViewPort( HINSTANCE hInstance , int nCmdShow ){
	WNDCLASSEX winClass;

	winClass.cbSize         = sizeof( WNDCLASSEX );
	winClass.style			= CS_OWNDC | CS_HREDRAW | CS_VREDRAW;
	winClass.lpfnWndProc	= WinProc;
	winClass.cbClsExtra		= 0;
	winClass.cbWndExtra		= 0;
	winClass.hInstance		= hInstance;
	winClass.hIcon			= LoadIcon( NULL , IDI_APPLICATION );
	winClass.hCursor		= LoadCursor( NULL , IDC_ARROW );
	winClass.hbrBackground	= ( HBRUSH )GetStockObject( BLACK_BRUSH );
	winClass.lpszMenuName	= NULL;
	winClass.lpszClassName	= "D3DProgram";
	winClass.hIconSm        = LoadIcon( NULL , IDI_APPLICATION );

	if ( !RegisterClassEx( &winClass ) ){
		MessageBox( 0 , "Невозможно зарегистрировать класс." , "Ошибка" , 0 );
		exit( 0 );
	}

	hWnd = CreateWindowEx( NULL , "D3DProgram" , "D3DEngine" , WS_POPUP | WS_VISIBLE , D3D_WINDOWPOSX, D3D_WINDOWPOSY ,
						   D3D_SCREEN_WIDTH , D3D_SCREEN_HEIGHT , NULL , NULL , hInstance , NULL );

	if( !hWnd ){ MessageBox( NULL , "Нет возможности создать окно." , "Ошибка" , MB_OK );exit( 0 );}

	if( !Direct3DInit( hWnd ) ){MessageBox( 0 , "Ошибка инициализации D3D." , "Ошибка" , 0 );exit( 0 );}

	ShowWindow( hWnd , nCmdShow );

	UpdateWindow( hWnd );
}

int WINAPI	WinMain( HINSTANCE hInstance , HINSTANCE hPrevInstance , LPSTR lpszCmdParam , int nCmdShow ){

	Kernel.CreateViewPort( hInstance , nCmdShow );

	ResourceManager.LoadResources( D3DDevice , Kernel.hWnd );

	PS.Create( NULL , cVector3( 0 , 0.02 , 0 ) , 0.002 , 300 , 0.2 , EFF_GRAVITY | EFF_AGING );
	PS.CreateMathPart( 300 , 270 );
	PS.CreateVisualPart( "particle2" );

	Kernel.MainLoop();

	return( NULL );
}

LRESULT	CALLBACK WinProc( HWND hWnd , UINT Message , UINT wParam , LONG lParam ){

	if( KBManager.GetKey( VK_ESCAPE ) )PostQuitMessage( 0 );

	switch( Message ){
		case( WM_DSNOTIFICATION ):
		break;
		case( WM_LBUTTONDOWN ):
		break;
		case( WM_KEYDOWN )	:KBManager.SetKey( wParam );return( 0 );
		case( WM_KEYUP )	:KBManager.ResetKey( wParam );return( 0 );
		case( WM_CREATE )   :return( 0 );
		case( WM_DESTROY )  :PostQuitMessage(NULL);return( 0 );
	}
	return( DefWindowProc( hWnd , Message , wParam , lParam ) );
}