#define STRICT
#define D3D_OVERLOADS
#include <math.h>
#include <d3d.h>
#include <malloc.h>
#include <stdio.h>
//#include "directx.hpp"
#include "dxrasterizer.hpp"
#define SAFE_RELEASE(p) 	 { if(p) { (p)->Release(); (p)=NULL; } }

#include "render.hpp"
static LPDIRECTDRAWSURFACE7 CreateATextureFromFile(LPDIRECTDRAW7 pDD, CHAR* strName );
static LPDIRECTDRAWSURFACE7 CreateRGBATextureFromFile(LPDIRECTDRAW7 pDD,CHAR* strName ,CHAR* strNamea,int bitcount=16);
static LPDIRECTDRAWSURFACE7 CreateSurfaceFromFile( LPDIRECTDRAW7 pdd,CHAR* strName );
static LPDIRECTDRAWSURFACE7 CreateTargetTexture(LPDIRECTDRAW7 pDD,DWORD tresx,DWORD tresy);
static LPDIRECTDRAWSURFACE7 CreateRGBATexture(LPDIRECTDRAW7 pDD,DWORD dwWidth,DWORD dwHeight,int bitcount=16);
static LPDIRECTDRAWSURFACE7 CreateRGBA16TextureFromBitmap(LPDIRECTDRAW7 pDD,HBITMAP hbm ,HBITMAP hbma);
static LPDIRECTDRAWSURFACE7 CreateRGBA32TextureFromBitmap(LPDIRECTDRAW7 pDD,HBITMAP hbm ,HBITMAP hbma);
static LPDIRECTDRAWSURFACE7 CreateATextureFromBitmap(LPDIRECTDRAW7 pDD,HBITMAP hbm );
static LPDIRECTDRAWSURFACE7 CreatePixelFormatTexture(LPDIRECTDRAW7 pDD,DWORD dwWidth,DWORD dwHeight,const DDPIXELFORMAT* pformat );

static bool DrawBitmapFileToTexture(LPDIRECTDRAWSURFACE7 pddsTexture,CHAR* strName );
bool __cdecl DrawBitmapToSurface(LPDIRECTDRAWSURFACE7 pddsTexture,int x,int y,const char* strName );

bool sh_isdeathmode;
extern HWND hWindow;
extern char AssetsDirectory1[MAX_PATH];

bool g_bCanSuicideAllways = false;
bool g_f3dtarget=false;
int g_nTypeOfMFDs = 1;
// 0 - no MFDs
// 1 - orginal(5+1=dual & single)
// 2 - B&W(3 + 1=1 dual)
// 3 - color(3 + 1=2 dual)

#include "ctcl_params.h"
//#define _ECTCL_Console              1 // CTCL_IsConsole()
//#define _ECTCL_Game                 2
//#define _ECTCL_CameraShip           3
//#define _ECTCL_None                 4
int (_stdcall* g_pfnCTCL_GetType)() = NULL;

// begin - for screen capture...
extern DWORD gCaptureDevice;
extern DWORD gCaptureScreen;
extern BYTE* _stdcall GrabScreenImage(IDirectDrawSurface7* pBBSurface, int nScrW, int nScrH);
extern bool _stdcall WriteImageAfterGrab(BYTE* Image, const char* pcszFilePrefix);
// end - for screen capture...

const	DWORD dwFullScreenFlags = DDSCL_SETFOCUSWINDOW | DDSCL_CREATEDEVICEWINDOW |
			  DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;

const DDPIXELFORMAT DDPF_R4G4B4A4=
{
	sizeof(DDPIXELFORMAT),
	DDPF_ALPHAPIXELS|DDPF_RGB,
	0,
	16,
	0x0F00,
	0x00F0,
	0x000F,
	0xF000
};

const DDPIXELFORMAT DDPF_R8G8B8A8=
{
	sizeof(DDPIXELFORMAT),
	DDPF_ALPHAPIXELS|DDPF_RGB,
	0,
	32,
	0x00FF0000,
	0x0000FF00,
	0x000000FF,
	0xFF000000
};

const DDPIXELFORMAT DDPF_R5G6B5=
{
	sizeof(DDPIXELFORMAT),
	DDPF_RGB,
	0,
	16,
	0xF800,
	0x07E0,
	0x001F,
};

//Utility Functions
LPVOID GetSurfacePointer(LPDIRECTDRAWSURFACE7 psurf)
{
	DDSURFACEDESC2 desc={0,};
	desc.dwSize=sizeof(desc);

	psurf->Lock(NULL,&desc,DDLOCK_WAIT ,NULL);
	return desc.lpSurface;
}

void ReleaseSurfacePointer(LPDIRECTDRAWSURFACE7 psurf)
{
	psurf->Unlock(NULL);
}

static bool IsTextureDimension(int n)
{
	for(int i=5;i<10;i++)
		if(n==(1<<i))return true;
	return false;
}

static LPDIRECTDRAWSURFACE7 CreateRGBATexture(LPDIRECTDRAW7 pDD,DWORD dwWidth,DWORD dwHeight,int bitcount)
{
	if(!(bitcount==16 || bitcount==32))return NULL;

	LPDIRECTDRAWSURFACE7 pddsTexture;
	HRESULT hr;

	DDSURFACEDESC2 ddsd;
	ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) );
	ddsd.dwSize 		 = sizeof(DDSURFACEDESC2);
	ddsd.dwFlags		 = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE;
	ddsd.ddsCaps.dwCaps  = DDSCAPS_TEXTURE;
	ddsd.dwWidth		 = dwWidth;
	ddsd.dwHeight		 = dwHeight;
	ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
	ddsd.ddpfPixelFormat = bitcount==16 ? DDPF_R4G4B4A4:DDPF_R8G8B8A8;


	if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTexture, NULL ) ) ){
		return NULL;
	}
	return pddsTexture;
}

static LPDIRECTDRAWSURFACE7 CreatePixelFormatTexture(LPDIRECTDRAW7 pDD,DWORD dwWidth,DWORD dwHeight,const DDPIXELFORMAT* pformat )
{
	LPDIRECTDRAWSURFACE7 pddsTexture;
	HRESULT hr;

	DDSURFACEDESC2 ddsd;
	ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) );
	ddsd.dwSize 		 = sizeof(DDSURFACEDESC2);
	ddsd.dwFlags		 = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_PIXELFORMAT|DDSD_TEXTURESTAGE;
	ddsd.ddsCaps.dwCaps  = DDSCAPS_TEXTURE;
	ddsd.dwWidth		 = dwWidth;
	ddsd.dwHeight		 = dwHeight;
	ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;
	ddsd.ddpfPixelFormat = *pformat;


	if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTexture, NULL ) ) ){
		return NULL;
	}
	return pddsTexture;
}

static bool IsValidAlphaPair(	DIBSECTION& dib,DIBSECTION& diba)
{
	BITMAP& bm=dib.dsBm;
	BITMAP& bma=diba.dsBm;
	int w=bm.bmWidth;
	int h=bm.bmHeight;

	if(dib.dsBmih.biHeight<0 || diba.dsBmih.biHeight<0)return false;

	//Does it satisfy the pixel format requirement?
	if(!(bm.bmBitsPixel==24 && bma.bmBitsPixel==8))return false;

	//Are the bitmap dimensions (X,Y) both powers of 2?
	if(!(IsTextureDimension(w) && IsTextureDimension(h)))return false;

	//Are RGB and Alpha bitmaps the same size?
	if(bma.bmWidth!=w || bma.bmHeight!=h)return NULL;

	return true;
}

//Main Functions
LPDIRECTDRAWSURFACE7 CreateRGBA16TextureFromBitmap(LPDIRECTDRAW7 pDD,HBITMAP hbm ,HBITMAP hbma)
{
	DIBSECTION dib,diba;
	if(GetObject(hbm,sizeof(DIBSECTION),&dib)!=sizeof(DIBSECTION))return NULL;
	if(GetObject(hbma,sizeof(DIBSECTION),&diba)!=sizeof(DIBSECTION))return NULL;
	BITMAP& bm=dib.dsBm;
	BITMAP& bma=diba.dsBm;
	int w=bm.bmWidth;
	int h=bm.bmHeight;

	if(!IsValidAlphaPair(dib,diba))return NULL;

	LPDIRECTDRAWSURFACE7 pddsTexture;
	pddsTexture=CreateRGBATexture(pDD,w,h,16);

	if(pddsTexture==NULL)return NULL;

	// Get a DC for the bitmap
	BYTE* bits	= (BYTE*)bm.bmBits;
	BYTE* bitsa = (BYTE*)bma.bmBits;
	
	WORD* bit=(WORD*)GetSurfacePointer(pddsTexture);
	DWORD wA,wR,wG,wB;

	bits+=bm.bmWidthBytes*(h-1);
	bitsa+=bma.bmWidthBytes*(h-1);
	for(int y=0; y < h; y++ ){
		BYTE* b=bits;
		for(int x=0; x < w; x++ ){
			wA= bitsa[x];
			wA= (wA<<8)&0xF000;

			wB=*b++;
			wG=*b++;
			wR=*b++;
			wR=(wR<<4)&0x0F00;
			wG=(wG)&0x00F0;
			wB=(wB>>4);
			*bit++=(WORD)(wA|wR|wG|wB);
		}
		bits-=bm.bmWidthBytes;
		bitsa-=bma.bmWidthBytes;
	}
	ReleaseSurfacePointer(pddsTexture);

	//delete data;
	return pddsTexture;
}

//Main Functions
LPDIRECTDRAWSURFACE7 CreateRGBA32TextureFromBitmap(LPDIRECTDRAW7 pDD,HBITMAP hbm ,HBITMAP hbma)
{
	DIBSECTION dib,diba;
	if(GetObject(hbm,sizeof(DIBSECTION),&dib)!=sizeof(DIBSECTION))return NULL;
	if(GetObject(hbma,sizeof(DIBSECTION),&diba)!=sizeof(DIBSECTION))return NULL;
	BITMAP& bm=dib.dsBm;
	BITMAP& bma=diba.dsBm;
	int w=bm.bmWidth;
	int h=bm.bmHeight;

	if(!IsValidAlphaPair(dib,diba))return NULL;

	LPDIRECTDRAWSURFACE7 pddsTexture;
	pddsTexture=CreateRGBATexture(pDD,w,h,32);

	if(pddsTexture)return NULL;

	// Get a DC for the bitmap
	BYTE* bits	= (BYTE*)bm.bmBits;
	BYTE* bitsa = (BYTE*)bma.bmBits;
	
	DWORD* bit=(DWORD*)GetSurfacePointer(pddsTexture);
	DWORD wA,wR,wG,wB;

	bits+=bm.bmWidthBytes*(h-1);
	bitsa+=bma.bmWidthBytes*(h-1);
	for(int y=0; y < h; y++ ){
		BYTE* b=bits;
		for(int x=0; x < w; x++ ){
			wA= bitsa[x];
			wB=*b++;
			wG=*b++;
			wR=*b++;
			*bit++ = (wA<<24)|(wR<<16)|(wG<<8)|wB;
		}
		bits-=bm.bmWidthBytes;
		bitsa-=bma.bmWidthBytes;
	}
	ReleaseSurfacePointer(pddsTexture);

	//delete data;
	return pddsTexture;
}

LPDIRECTDRAWSURFACE7 CreateRGBATextureFromFile(LPDIRECTDRAW7 pDD,CHAR* strName ,CHAR* strNamea,int bitcount)
{
	HBITMAP hbm,hbma;
	LPDIRECTDRAWSURFACE7 t=NULL;
	hbm = (HBITMAP)LoadImage( NULL, strName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION );
	if(hbm ){
		hbma = (HBITMAP)LoadImage( NULL, strNamea, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION );
		if(hbma){
			if(bitcount==16){
				t=CreateRGBA16TextureFromBitmap(pDD,hbm,hbma);
			}else{
				t=CreateRGBA32TextureFromBitmap(pDD,hbm,hbma);
			}//else t==NULL;
			DeleteObject(hbma);
		}
		DeleteObject(hbm);
	}

	return t;
}

static LPDIRECTDRAWSURFACE7 CreateTargetTexture(LPDIRECTDRAW7 pDD,DWORD tresx,DWORD tresy)
{
    LPDIRECTDRAWSURFACE7 pddsTexture;
    HRESULT hr;

    DDSURFACEDESC2 ddsd;
    ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) );
    ddsd.dwSize          = sizeof(DDSURFACEDESC2);
    ddsd.dwFlags         = DDSD_CAPS|DDSD_HEIGHT|DDSD_WIDTH|DDSD_TEXTURESTAGE;
    ddsd.ddsCaps.dwCaps  = DDSCAPS_VIDEOMEMORY |DDSCAPS_TEXTURE|DDSCAPS_3DDEVICE;
    ddsd.dwWidth         = tresx;
    ddsd.dwHeight        = tresy;
//    ddsd.ddsCaps.dwCaps2 = DDSCAPS2_TEXTUREMANAGE;


    if( FAILED( hr = pDD->CreateSurface( &ddsd, &pddsTexture, NULL ) ) )
        return NULL;

    return pddsTexture;
}


static LPDIRECTDRAWSURFACE7 CreateSurfaceFromFile( LPDIRECTDRAW7 pdd,CHAR* strName )
{

	HBITMAP hbm;
    BITMAP bm;
	DDSURFACEDESC2 ddsd;
    LPDIRECTDRAWSURFACE7 pddsTexture;

	hbm = (HBITMAP)LoadImage( NULL, strName, IMAGE_BITMAP, 0, 0,LR_LOADFROMFILE|LR_CREATEDIBSECTION );

    GetObject( hbm, sizeof(BITMAP), &bm );

	ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) );
	ddsd.dwSize          = sizeof(DDSURFACEDESC2);
	ddsd.dwFlags         = DDSD_HEIGHT|DDSD_WIDTH|DDSD_CAPS;
	ddsd.ddsCaps.dwCaps  = DDSCAPS_VIDEOMEMORY |DDSCAPS_OFFSCREENPLAIN;
	ddsd.dwWidth         = bm.bmWidth;
	ddsd.dwHeight        = bm.bmHeight;

    pdd->CreateSurface( &ddsd, &pddsTexture, NULL ) ;

    // Get a DC for the bitmap

    HDC hdcBitmap = CreateCompatibleDC( NULL );
    HBITMAP holdbitmap=(HBITMAP)SelectObject( hdcBitmap, hbm );

    HDC hdcTexture;
    pddsTexture->GetDC( &hdcTexture );
    BitBlt( hdcTexture, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap,0, 0, SRCCOPY );
    pddsTexture->ReleaseDC( hdcTexture );
	SelectObject(hdcBitmap,holdbitmap);
	DeleteObject(hbm);
    DeleteDC( hdcBitmap );

    return pddsTexture;
}

static bool DrawBitmapFileToTexture(LPDIRECTDRAWSURFACE7 pddsTexture,CHAR* strName )
{

	HBITMAP hbm;
    BITMAP bm;
	DDSURFACEDESC2 ddsd;

	hbm = (HBITMAP)LoadImage( NULL, strName, IMAGE_BITMAP, 0, 0,LR_LOADFROMFILE|LR_CREATEDIBSECTION );

    GetObject( hbm, sizeof(BITMAP), &bm );

	ZeroMemory( &ddsd, sizeof(DDSURFACEDESC2) );
	ddsd.dwSize          = sizeof(DDSURFACEDESC2);
	ddsd.dwFlags         = DDSD_HEIGHT|DDSD_WIDTH|DDSD_CAPS;
	ddsd.ddsCaps.dwCaps  = DDSCAPS_VIDEOMEMORY |DDSCAPS_OFFSCREENPLAIN;
	ddsd.dwWidth         = bm.bmWidth;
	ddsd.dwHeight        = bm.bmHeight;

    HDC hdcBitmap = CreateCompatibleDC( NULL );
    HBITMAP holdbitmap=(HBITMAP)SelectObject( hdcBitmap, hbm );

    HDC hdcTexture;
    pddsTexture->GetDC( &hdcTexture );
    BitBlt( hdcTexture, 0, 0, bm.bmWidth, bm.bmHeight, hdcBitmap,0, 0, SRCCOPY );
    pddsTexture->ReleaseDC( hdcTexture );
	SelectObject(hdcBitmap,holdbitmap);
	DeleteObject(hbm);
    DeleteDC( hdcBitmap );

	return true;
}

bool __cdecl DrawBitmapToSurface(LPDIRECTDRAWSURFACE7 pddsTexture,int x,int y,const char* strName )
{
	HBITMAP hbm;
	hbm = (HBITMAP)LoadImage( NULL, strName, IMAGE_BITMAP, 0, 0,LR_LOADFROMFILE|LR_CREATEDIBSECTION );

	BITMAP bm;
	GetObject( hbm, sizeof(BITMAP), &bm );

	HDC hdcBitmap = CreateCompatibleDC( NULL );
	HBITMAP holdbitmap=(HBITMAP)SelectObject( hdcBitmap, hbm );

	HDC hdcTexture;
	pddsTexture->GetDC( &hdcTexture );
	BitBlt( hdcTexture, x, y, bm.bmWidth, bm.bmHeight, hdcBitmap,0, 0, SRCCOPY );
	pddsTexture->ReleaseDC( hdcTexture );
	SelectObject(hdcBitmap,holdbitmap);
	DeleteObject(hbm);
	DeleteDC( hdcBitmap );

	return 0;
}





//Create texture with Alpha from 8-bit Bitmap..
static LPDIRECTDRAWSURFACE7 CreateATextureFromBitmap(LPDIRECTDRAW7 pDD,HBITMAP hbm )
{
	BITMAP bm={0,};
	GetObject(hbm,sizeof(bm),&bm);
	DWORD w=bm.bmWidth;
	DWORD h=bm.bmHeight;

	LPDIRECTDRAWSURFACE7 pddsTexture;
	pddsTexture=CreateRGBATexture(pDD,w,h,16);

	BYTE* data=(BYTE*)bm.bmBits;

	WORD* bits=(WORD*)GetSurfacePointer(pddsTexture);


	data+=bm.bmWidthBytes*(h-1);
	WORD wA;
	for(DWORD y=0; y < h; y++ ){
		for(DWORD x=0; x < w; x++ ){
			wA= data[x];
			WORD wBit=(WORD)((wA<<8)&0xF000|0x0FFF);
			*bits++=(WORD)((wA>0)?wBit:0);

		}
		data-=bm.bmWidthBytes;
	}
	ReleaseSurfacePointer(pddsTexture);

    return pddsTexture;
}

LPDIRECTDRAWSURFACE7 CreateATextureFromFile(LPDIRECTDRAW7 pDD, CHAR* strName )
{
	//Copy text content to Clipboard...
/*
	OpenClipboard(hWindow);
	HGLOBAL h=GlobalAlloc(GMEM_MOVEABLE,512);
	char * text=(char*)GlobalLock(h);
	lstrcpy(text,strName);
	GlobalUnlock(h);

	SetClipboardData(CF_TEXT,h);
	CloseClipboard();
*/
	/*

	FILE* fp=fopen("c:\\a.txt","w");
	fprintf(fp,"%s",strName);
	fclose(fp);
	*/

    HBITMAP hbm;
    hbm = (HBITMAP)LoadImage( NULL, strName, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE|LR_CREATEDIBSECTION );
    if( NULL == hbm ){
		//MessageBeep(0);
		return NULL;
	}

	LPDIRECTDRAWSURFACE7 t;
    t=CreateATextureFromBitmap( pDD, hbm );
	DeleteObject(hbm);
	return t;
}

//realize static member variable...
D3DTLVERTEX CHSHFont::m_pVB[300];

/////////////////////////////////// CHSH_Device ///////////////////////////////////
CHSH_Device::CHSH_Device()
{
	pDD=0;
	pDDSFront=0;
	pDDSBack=0;
	pDDSTarget=0;
	pDDSTexture=0;
	pD3DDevice=0;
	tw=512;
	th=512;
}

void CHSH_Device::SetRenderTargetBackbuffer()
{
	LPDIRECTDRAWSURFACE7 target;
	pD3DDevice->GetRenderTarget(&target);

	if(target!=pDDSBack){
		pD3DDevice->SetRenderTarget(pDDSBack,0);
	}
	D3DVIEWPORT7 vp = { 0, 0, size_back.cx, size_back.cy, 0.0f, 1.0f };
	pD3DDevice->SetViewport( &vp );
}


void CHSH_Device::SetRenderTargetTexture()
{
	LPDIRECTDRAWSURFACE7 target;
	pD3DDevice->GetRenderTarget(&target);

	if(target!=pDDSTarget){
		pD3DDevice->SetRenderTarget(pDDSTarget,0);
	}
	D3DVIEWPORT7 vp = { 0, 0, size_target.cx, size_target.cy, 0.0f, 1.0f };
	pD3DDevice->SetViewport( &vp );
}



#pragma warning(disable:4100)
#pragma warning(disable:4505)

const DWORD dwFlags = DDSCL_SETFOCUSWINDOW | DDSCL_CREATEDEVICEWINDOW |
              DDSCL_ALLOWREBOOT | DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN;

extern HRESULT wDirectDrawCreateEx( GUID* lpGUID, void** lplpDD, REFIID iid, IUnknown* pUnkOuter );

bool CHSH_Device::InitFirst(int devicenum,DWORD resx,DWORD resy, CHSH_Device* pOtherHSHD/* = NULL*/)
{
	m_pOtherHSHD = pOtherHSHD;
	if (pOtherHSHD) {
		pDD = pOtherHSHD->pDD;
	} else {
		HRESULT hr; 
		//1. Resolution change.
		wDirectDrawCreateEx( &DeviceArray[devicenum].DeviceGUID , (VOID**) &(pDD), IID_IDirectDraw7, NULL );
		pDD->SetCooperativeLevel(hWindow, dwFlags );
		hr=pDD->SetDisplayMode( resx, resy, 16, 60, 0 );
	}
	size_back.cx=resx;
	size_back.cy=resy;
	return true;
}

// MSL - Edit this list for the 2D artwork
// MSL ADD MECH
char *mechnames[]={
		"annihilator",
		"archer",
		"arcticwolf",
		"ares",
		"argus",
		"assassinii",
		"atlas",
		"avatar",
		"awesome",
		"battlemaster",
		"battlemasteriic",
		"behemoth",
		"behemothii",
		"blackhawk",
		"blackknight",
		"blacklanner",
		"brigand",
		"bushwacker",
		"catapult",
		"cauldronborn",
		"chimera",
		"commando",
		"cougar",
		"cyclops",
		"daishi",
//		"dasher",
		"deimos",
		"dragon",
		"fafnir",
		"flea",
		"gladiator",
		"grizzly",
		"hauptmann",
		"hellhound",
		"hellspawn",
		"highlander",
		"hollanderii",
		"hunchback",
		"kodiak",
		"loki",
		"longbow",
		"madcat",
		"madcat2",
		"masakari",
		"mauler",
		"novacat",
		"osiris",
		"owens",
		"puma",
		"raven",
		"rifleman",
		"ryoken",
		"shadowcat",
		"solitaire",
		"sunder",
		"templar",
		"thanatos",
		"thor",
		"uller",
		"urbanmech",
		"uziel",
		"victor",
		"vulture",
		"warhammer",
		"wolfhound",
		"zeus"
};
#define ARRAYSIZE(x)	(sizeof(x)/sizeof(x[0]))

bool CHSH_Device::InitSecond(DWORD tresx,DWORD tresy)
{	
  if (m_pOtherHSHD) {
	pDDSFront = m_pOtherHSHD->pDDSFront;
	pDDSBack = m_pOtherHSHD->pDDSBack;
	pD3DDevice = m_pOtherHSHD->pD3DDevice;
  } else {
	//2. Create Surfaces(Primary,Back,BackgroundImage,Texture)
	//////Front Buffer
	DDSURFACEDESC2		ddsd={0,};
	DDSCAPS2			ddsCaps;

	ddsd.dwSize 		   = sizeof(ddsd);
	ddsd.dwFlags		   = DDSD_BACKBUFFERCOUNT | DDSD_CAPS;
	ddsd.dwBackBufferCount = 1;
	ddsd.ddsCaps.dwCaps    = DDSCAPS_COMPLEX | DDSCAPS_FLIP | DDSCAPS_PRIMARYSURFACE| DDSCAPS_3DDEVICE;

	pDD->CreateSurface( &ddsd, &pDDSFront, NULL );


	//////BackBuffer
	ZeroMemory( &ddsCaps, sizeof(ddsCaps) );
	ddsCaps.dwCaps = DDSCAPS_BACKBUFFER;
	pDDSFront->GetAttachedSurface( &ddsCaps, &pDDSBack );

	//////3D Device
	LPDIRECT3D7 pD3D;
	pDD->QueryInterface( IID_IDirect3D7, (VOID**)&(pD3D) );
	pD3D->CreateDevice(IID_IDirect3DHALDevice,pDDSBack,&pD3DDevice);
	pD3D->Release();

	D3DVIEWPORT7 vp = { 0, 0, size_back.cx, size_back.cy, 0.0f, 1.0f };
	pD3DDevice->SetViewport( &vp );
  }

	//3. Create Target Buffer(Texture)
	pDDSTarget=0;
	if(tresx >0 && tresy>0)
		pDDSTarget=CreateTargetTexture(pDD,tresx,tresy);


	//4. Create Font Objects

	pFont[0].Init(pDD,pD3DDevice,"Arial",30,false,false);
	pFont[1].Init(pDD,pD3DDevice,"Arial",15,false,false);
	pFont[2].Init(pDD,pD3DDevice,"Arial",20,true,false);
	pFont[3].Init(pDD,pD3DDevice,"Arial",16,true,false);

	//5. Etc
	size_target.cx=tresx;
	size_target.cy=tresy;

	return true;//success
}

bool CHSH_Device::Release()
{
	if(pDD){
		for(int i=0;i<4;i++)pFont[i].Cleanup();

		SAFE_RELEASE(pDDSTexture);
		if(pD3DDevice)pD3DDevice->EndScene();
	  if (m_pOtherHSHD)
		pD3DDevice = NULL;
	  else
		SAFE_RELEASE(pD3DDevice);

		SAFE_RELEASE(pDDSTarget);
	  if (m_pOtherHSHD) {
		pDDSBack = NULL;
		pDDSFront = NULL;
	  } else {
		SAFE_RELEASE(pDDSBack);
		SAFE_RELEASE(pDDSFront);

		pDD->RestoreDisplayMode();
		pDD->SetCooperativeLevel(hWindow, DDSCL_NORMAL);
		pDD->Release();
	  }
		pDD=0;
		m_pOtherHSHD = NULL;
	}
	return true;
}

void CHSH_Device::DrawQuad(int x1,int y1,int x2,int y2,DWORD dwColor)
{
	D3DTLVERTEX Vertices[4]; // Vertices for the cube

	Vertices[0] = D3DTLVERTEX(D3DVECTOR(  (float)x1-0.5f, (float)y2-0.5f,0.9f),1.0f,dwColor,0, 0.0f, 1.0f );
	Vertices[1] = D3DTLVERTEX(D3DVECTOR(  (float)x1-0.5f, (float)y1-0.5f,0.9f),1.0f,dwColor,0, 0.0f, 0.0f );
	Vertices[2] = D3DTLVERTEX(D3DVECTOR(  (float)x2-0.5f, (float)y2-0.5f,0.9f),1.0f,dwColor,0, 1.0f, 1.0f );
	Vertices[3] = D3DTLVERTEX(D3DVECTOR(  (float)x2-0.5f, (float)y1-0.5f,0.9f),1.0f,dwColor,0, 1.0f, 0.0f );

	pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices, 4, NULL );
}

void CHSH_Device::DrawQuadList(int quadcount,RECT * prc,DWORD dwColor)
{
	int cvertex=quadcount*6;
	D3DTLVERTEX *Vertices=(D3DTLVERTEX*)malloc(cvertex*sizeof(D3DTLVERTEX));

	//012 213
	for(int i=0,n=0;i<quadcount;i++,prc++){
		int x1=prc->left;
		int y1=prc->top;
		int x2=prc->right;
		int y2=prc->bottom;
		Vertices[n++] = D3DTLVERTEX(D3DVECTOR(	(float)x1-0.5f, (float)y2-0.5f,0.9f),1.0f,dwColor,0, 0.0f, 1.0f );//0
		Vertices[n++] = D3DTLVERTEX(D3DVECTOR(	(float)x1-0.5f, (float)y1-0.5f,0.9f),1.0f,dwColor,0, 0.0f, 0.0f );//1
		Vertices[n++] = D3DTLVERTEX(D3DVECTOR(	(float)x2-0.5f, (float)y2-0.5f,0.9f),1.0f,dwColor,0, 1.0f, 1.0f );//2
		Vertices[n++] = D3DTLVERTEX(D3DVECTOR(	(float)x2-0.5f, (float)y2-0.5f,0.9f),1.0f,dwColor,0, 1.0f, 1.0f );//2
		Vertices[n++] = D3DTLVERTEX(D3DVECTOR(	(float)x1-0.5f, (float)y1-0.5f,0.9f),1.0f,dwColor,0, 0.0f, 0.0f );//1
		Vertices[n++] = D3DTLVERTEX(D3DVECTOR(	(float)x2-0.5f, (float)y1-0.5f,0.9f),1.0f,dwColor,0, 1.0f, 0.0f );//3
	}
	pD3DDevice->DrawPrimitive( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX , Vertices, cvertex, NULL );
	free(Vertices);
}

void CHSH_Device::DrawLine(int x1,int y1,int x2,int y2,DWORD dwColor)
{
	D3DTLVERTEX Vertices[2]; // Vertices for the cube

	Vertices[0] = D3DTLVERTEX(D3DVECTOR(  (float)x1, (float)y1,0.9f),1.0f,dwColor,0, 0.0f, 0.0f );
	Vertices[1] = D3DTLVERTEX(D3DVECTOR(  (float)x2, (float)y2,0.9f),1.0f,dwColor,0, 0.0f, 0.0f );

	pD3DDevice->DrawPrimitive( D3DPT_LINESTRIP , D3DFVF_TLVERTEX , Vertices, 2, NULL );
}

void CHSH_Device::DrawLineStrip(int point_count,POINT* pts,DWORD dwColor)
{
	D3DTLVERTEX *Vertices=(D3DTLVERTEX*)malloc(point_count*sizeof(D3DTLVERTEX));

	for(int i=0;i<point_count;i++){
		Vertices[i] = 
			D3DTLVERTEX(D3DVECTOR(	(float)pts[i].x, (float)pts[i].y,0.9f),1.0f,dwColor,0, 0.0f, 0.0f );
	}

	pD3DDevice->DrawPrimitive( D3DPT_LINESTRIP , D3DFVF_TLVERTEX , Vertices, point_count, NULL );
	free(Vertices);
}

void CHSH_Device::DrawLineList(int line_count,POINT* pts,DWORD dwColor)
{
	int point_count=line_count*2;
	D3DTLVERTEX *Vertices=(D3DTLVERTEX*)malloc(point_count*sizeof(D3DTLVERTEX));

	for(int i=0;i<point_count;i++){
		Vertices[i] = 
			D3DTLVERTEX(D3DVECTOR(	(float)pts[i].x, (float)pts[i].y,0.9f),1.0f,dwColor,0, 0.0f, 0.0f );
	}

	pD3DDevice->DrawPrimitive( D3DPT_LINELIST , D3DFVF_TLVERTEX , Vertices, point_count, NULL );
	free(Vertices);
}

void CHSH_Device::DrawFrame(int x1,int y1,int x2,int y2,DWORD dwColor)
{
	D3DTLVERTEX Vertices[5]; // Vertices for the cube

	Vertices[0] = D3DTLVERTEX(D3DVECTOR(  (float)x1, (float)y1,0.9f),1.0f,dwColor,0, 0.0f, 1.0f );
	Vertices[1] = D3DTLVERTEX(D3DVECTOR(  (float)x2, (float)y1,0.9f),1.0f,dwColor,0, 0.0f, 0.0f );
	Vertices[2] = D3DTLVERTEX(D3DVECTOR(  (float)x2, (float)y2,0.9f),1.0f,dwColor,0, 1.0f, 1.0f );
	Vertices[3] = D3DTLVERTEX(D3DVECTOR(  (float)x1, (float)y2,0.9f),1.0f,dwColor,0, 1.0f, 0.0f );
	Vertices[4] = D3DTLVERTEX(D3DVECTOR(  (float)x1, (float)y1,0.9f),1.0f,dwColor,0, 1.0f, 0.0f );

	pD3DDevice->DrawPrimitive( D3DPT_LINESTRIP, D3DFVF_TLVERTEX , Vertices, 5, NULL );
}

void CHSH_Device::DrawFrameList(int framecount,RECT * prc,DWORD dwColor)
{
	int point_count=framecount*8;
	D3DTLVERTEX *Vertices=(D3DTLVERTEX*)malloc(point_count*sizeof(D3DTLVERTEX));

	//0=7 / 1=2 / 3=4 / 5=6

	D3DTLVERTEX *v=Vertices;
	for(int i=0;i<framecount;i++,prc++,v+=8){
		int x1=prc->left;
		int y1=prc->top;
		int x2=prc->right;
		int y2=prc->bottom;
		v[0]=v[7] = D3DTLVERTEX(D3DVECTOR(	(float)x1, (float)y2,0.9f),1.0f,dwColor,0, 0.0f, 1.0f );//0
		v[1]=v[2] = D3DTLVERTEX(D3DVECTOR(	(float)x1, (float)y1,0.9f),1.0f,dwColor,0, 0.0f, 0.0f );//1
		v[3]=v[4] = D3DTLVERTEX(D3DVECTOR(	(float)x2, (float)y2,0.9f),1.0f,dwColor,0, 1.0f, 1.0f );//2
		v[5]=v[6] = D3DTLVERTEX(D3DVECTOR(	(float)x2, (float)y1,0.9f),1.0f,dwColor,0, 1.0f, 0.0f );//3
	}


	pD3DDevice->DrawPrimitive( D3DPT_LINELIST, D3DFVF_TLVERTEX , Vertices, point_count, NULL );

	free(Vertices);
}

void CHSH_Device::DrawThickFrame(int x1,int y1,int x2,int y2,int t,DWORD dwColor)
{
	if(t>1){
		RECT rc[4]={
			{x1  ,y1  ,x2  ,y1+t},
			{x1  ,y2-t,x2  ,y2	},
			{x1  ,y1  ,x1+t,y2	},
			{x2-t,y1  ,x2  ,y2	}
		};
		DrawQuadList(4,rc,dwColor);
	}
}

void CHSH_Device::DrawThickFrameList(int framecount,RECT* prc,int t,DWORD dwColor)
{
	if(t>0){
		int quadcount=framecount*4;
		RECT* rc=(RECT*)malloc(sizeof(RECT)*quadcount);
		RECT* rcorg=rc;

		for(int i=0;i<framecount;i++,prc++,rc+=4){
			int x1=prc->left;
			int y1=prc->top;
			int x2=prc->right;
			int y2=prc->bottom;
			RECT r[4]={
				{x1  ,y1  ,x2  ,y1+t},
				{x1  ,y2-t,x2  ,y2	},
				{x1  ,y1  ,x1+t,y2	},
				{x2-t,y1  ,x2  ,y2	}
			};
			CopyMemory(rc,r,sizeof(r));
		}
		DrawQuadList(quadcount,rcorg,dwColor);
		free(rcorg);
	}
}


//Texture coordinates..	u1,v1,u2,v2
//Texture rotation axis	tx,ty
//Screen rotation axis 	x,y
//Rotation angle			e

void CHSH_Device::DrawTextureRotate(float u1,float v1,float u2,float v2,float tx,float ty,float x,float y,float e,DWORD color)
{
	float U1=u1-tx;
	float V1=v1-ty;
	float U2=u2-tx;
	float V2=v2-ty;

	//(U1,V1),(U2,V1),(U1,V2),(U2,V2) four pairs are rotation-transformed.
	//pt[0][0]....
	//Add x,y to each axis.
	float cose=cosf(e);
	float cos_u1=cose*U1;
	float cos_u2=cose*U2;
	float cos_v1=cose*V1;
	float cos_v2=cose*V2;
	float sine=sinf(e);
	float sin_u1=sine*U1;
	float sin_u2=sine*U2;
	float sin_v1=sine*V1;
	float sin_v2=sine*V2;

	float pt[4][2];
	pt[0][0] = cos_u1-sin_v1+x;
	pt[0][1] = sin_u1+cos_v1+y;
	pt[1][0] = cos_u2-sin_v1+x;
	pt[1][1] = sin_u2+cos_v1+y;
	pt[2][0] = cos_u1-sin_v2+x;
	pt[2][1] = sin_u1+cos_v2+y;
	pt[3][0] = cos_u2-sin_v2+x;
	pt[3][1] = sin_u2+cos_v2+y;

	//HSH_Draw3DTexture2(0,pt,0xFF00FF00,u1, v1/256.0f, u2/256.0f,	v2/256.0f);
	//Then translate all by x,y again.
	DrawTexture(pt,color,u1,v1,u2,v2);
}

//Scaled arbitrarily. x1,y1,x2,y2
void CHSH_Device::DrawTexture(float x1,float y1,float x2,float y2,DWORD dwColor, float u1,float v1,float u2,float v2)
{

	D3DTLVERTEX v[4];
	v[0] = D3DTLVERTEX(D3DVECTOR(x1-0.5f,y2-0.5f,0.9f),1.0f, dwColor,0, u1/tw, v2/th );
	v[1] = D3DTLVERTEX(D3DVECTOR(x1-0.5f,y1-0.5f,0.9f),1.0f, dwColor,0, u1/tw, v1/th );
	v[2] = D3DTLVERTEX(D3DVECTOR(x2-0.5f,y2-0.5f,0.9f),1.0f, dwColor,0, u2/tw, v2/th );
	v[3] = D3DTLVERTEX(D3DVECTOR(x2-0.5f,y1-0.5f,0.9f),1.0f, dwColor,0, u2/tw, v1/th );
	
	pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX ,v,4,0 );
}

//Scaled arbitrarily. x,y,width,height
void CHSH_Device::DrawTexture2(float x,float y,float w,float h,DWORD dwColor, float u1,float v1,float u2,float v2)
{

	D3DTLVERTEX v[4];
	v[0] = D3DTLVERTEX(D3DVECTOR(x+0-0.5f,y+h-0.5f,0.9f),1.0f, dwColor,0, u1/tw, v2/th );
	v[1] = D3DTLVERTEX(D3DVECTOR(x+0-0.5f,y+0-0.5f,0.9f),1.0f, dwColor,0, u1/tw, v1/th );
	v[2] = D3DTLVERTEX(D3DVECTOR(x+w-0.5f,y+h-0.5f,0.9f),1.0f, dwColor,0, u2/tw, v2/th );
	v[3] = D3DTLVERTEX(D3DVECTOR(x+w-0.5f,y+0-0.5f,0.9f),1.0f, dwColor,0, u2/tw, v1/th );
	
	pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX ,v,4,0 );
}


//Not scaled....
void CHSH_Device::DrawTexture(float x,float y,DWORD dwColor, float u1,float v1,float u2,float v2)
{
	D3DTLVERTEX v[4];
	float w=u2-u1;
	float h=v2-v1;
	v[0] = D3DTLVERTEX(D3DVECTOR(x+0-0.5f,y+h-0.5f,0.9f),1.0f, dwColor,0, u1/tw, v2/th );
	v[1] = D3DTLVERTEX(D3DVECTOR(x+0-0.5f,y+0-0.5f,0.9f),1.0f, dwColor,0, u1/tw, v1/th );
	v[2] = D3DTLVERTEX(D3DVECTOR(x+w-0.5f,y+h-0.5f,0.9f),1.0f, dwColor,0, u2/tw, v2/th );
	v[3] = D3DTLVERTEX(D3DVECTOR(x+w-0.5f,y+0-0.5f,0.9f),1.0f, dwColor,0, u2/tw, v1/th );
	
	pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX ,v,4,0 );
}


void CHSH_Device::DrawTexture(float pt[4][2],DWORD dwColor,float tx1,float ty1,float tx2,float ty2)
{
	D3DTLVERTEX v[4];
	v[0] = D3DTLVERTEX(D3DVECTOR(pt[2][0]-0.5f, pt[2][1]-0.5f,0.9f),1.0f, dwColor,0, tx1/tw, ty2/th );
	v[1] = D3DTLVERTEX(D3DVECTOR(pt[0][0]-0.5f, pt[0][1]-0.5f,0.9f),1.0f, dwColor,0, tx1/tw, ty1/th );
	v[2] = D3DTLVERTEX(D3DVECTOR(pt[3][0]-0.5f, pt[3][1]-0.5f,0.9f),1.0f, dwColor,0, tx2/tw, ty2/th );
	v[3] = D3DTLVERTEX(D3DVECTOR(pt[1][0]-0.5f, pt[1][1]-0.5f,0.9f),1.0f, dwColor,0, tx2/tw, ty1/th );
	
	pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX ,v,4,0 );
}

//Mission Review Device
/////////////////////////////////// CMR_Device ///////////////////////////////////

extern int g_nDualHead;
extern int g_nNonDualHead;
extern int g_nMFD1;  // mode 4: left 640x480 MFD monitor
extern int g_nMFD2;  // mode 4: right 640x480 MFD monitor
// MSL 5.03 Mechview
extern int g_nMechViewType; // jcem : 0 - no mechview, 1 - on radar screen, 2 - on main screen

bool sh_game_started = false;
int (_stdcall *g_pfnVehGetShutdownState)() = NULL;

bool IsMechShutdown()
{
    return g_pfnVehGetShutdownState && ((*g_pfnVehGetShutdownState)() == 1);
}

CMR_Device::CMR_Device()
{
}

CMR_Device::~CMR_Device()
{
}

bool CMR_Device::InitFirst()
{
    if (g_nNonDualHead != -1)
	    return CHSH_Device::InitFirst(g_nNonDualHead,640,480);
    if (g_nDualHead != -1)
        return CHSH_Device::InitFirst(g_nDualHead,640,480);
    return false;
}

bool CMR_Device::InitSecond()
{
	map_loaded=false;
	CHSH_Device::InitSecond(0,0); // no off screen - do not create Target Texture.

	char temppath[MAX_PATH],temppatha[MAX_PATH];

	//1. Surface for background image
	sprintf(temppath,"%s\\hsh\\%s",AssetsDirectory1,"mr_background.bmp");
	pDDSBackground=CreateSurfaceFromFile(pDD,temppath);

	if(pDDSBackground==NULL){
		MessageBeep(0);
	}
	
	//2. General-purpose texture
	sprintf(temppath,"%s\\hsh\\%s",AssetsDirectory1,"mr_texture.bmp");
	sprintf(temppatha,"%s\\hsh\\%s",AssetsDirectory1,"mr_texturea.bmp");
	pDDSTexture=CreateRGBATextureFromFile(pDD, temppath,temppatha,16);

	//3. Texture for map..
	pDDSMapTexture=CreatePixelFormatTexture(pDD,256,256,&DDPF_R5G6B5);

	tw=256;
	th=256;

	pDDSMRTargetTexture=0;

	return true;
}

bool CMR_Device::BeginScene()
{
	//Set the Render Target.
	//SetRenderTargetTexture();


	//Draw background image to Texture. Used as a substitute for Clear..
	if(sh_game_started){
		//Draw background only when game has started.
		RECT rc={0,0,640,480};
		pDDSBack->BltFast(0,0,pDDSBackground,&rc,0);
	}else{
		//If game has not started.. show blank.
		pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET ,0,1.0f,0);
	}

	pD3DDevice->BeginScene();

	pD3DDevice->SetTexture(0,pDDSTexture);
	return true;
}

bool CMR_Device::EndScene()
{
	pD3DDevice->EndScene();
	if( gCaptureScreen && (gCaptureDevice == 2))
	{
	    if(pDD && pD3DDevice && pDDSBack){
		    BYTE* Image=GrabScreenImage(pDDSBack, 0, 0);
            WriteImageAfterGrab(Image, "mr-scr%04d.%s");
        }
        gCaptureScreen = 0;
	}
	return true;
}

	
bool CMR_Device::Release()
{
	map_loaded=false;
	if(pDD){
		SAFE_RELEASE(pDDSBackground);
		SAFE_RELEASE(pDDSMapTexture);
		SAFE_RELEASE(pDDSMRTargetTexture);
		CHSH_Device::Release();
	}
	return true;
}

// MSL 5.03 Target Damage Display
bool CMR_Device::LoadMRTargetTexture(const char *mechtexturename)
{
	SAFE_RELEASE(pDDSMRTargetTexture);

	char temppath[MAX_PATH];
	sprintf(temppath,"%s\\hsh\\%s.bmp",AssetsDirectory1,mechtexturename);
	pDDSMRTargetTexture=CreateATextureFromFile(pDD, temppath);
	return true;
}

CMR_Device mr_device;

// Mode 4: the right-hand 640x480 MFD device.  Shares VRAM with mfd_device
// (same GPU), so mfd_device's pDDSTarget texture can be passed to this
// device's pD3DDevice->SetTexture without a copy.
CMFDRight_Device mfd_device_right;

bool CMFDRight_Device::InitFirst()
{
	// Take over g_nMFD2 monitor at 640x480 fullscreen.
	return CHSH_Device::InitFirst(g_nMFD2, 640, 480);
}

bool CMFDRight_Device::InitSecond()
{
	// Create flip chain, D3D device and a render-target slot (1024x512).
	return CHSH_Device::InitSecond(1024, 512);
}

/////////////////////////////////// CRadar_Device ///////////////////////////////////
const char g_szRadarShutdown[] = "SHUT\nDOWN";
const char g_szRadarStartup[] = "START\nUP";
const char g_szRadarJumpjet[] = "JUMP\nJET";
const char g_szRadarZoom[] = "ZOOM";
// MSL 5.03
char g_aaRadarText[12][32] = {
	"","","AUXIL\nMODE","FLUSH","CROUCH","PRGM\nMODE",
	"RANGE","RADAR\nMODE","LIGHT\nAMP","SEARCH\nLIGHT","AUTO\nCENTER","PILOT\nMODE"
};

CRadar_Device::CRadar_Device()
{
// MSL 5.03 Mechview
    // MechView Param - m_ptMechViewDim
    // if m_ptMechViewDim is 2048,1024 && m_ptMechViewSize is 320/200 then
    //   (2048/320) * (1024/200) = 6 * 5 = 30 frames....
    // m_ptMechViewDim should be power of 2, (256/512/1024/2048...)
    // m_ptMechViewSize should be multiple of 4... (.../320/324/326/...)
    m_ptMechViewDim.x = 2048;
    m_ptMechViewDim.y = 2048;
    m_ptMechViewSize.x = 360;
    m_ptMechViewSize.y = 360;
    // 2048 / 360 = 5.xxx so 5 * 5 = 25 frames
    m_nMechViewCurs = -1;
    m_nMechViewMax = 0;
}

CRadar_Device::~CRadar_Device()
{
}

bool CRadar_Device::InitFirst()
{
	if (g_nTypeOfMFDs == 2)
		return CHSH_Device::InitFirst(g_nNonDualHead,640,480, &mfd_device);
	else
		return CHSH_Device::InitFirst(g_nNonDualHead,640,480);
}

bool CRadar_Device::InitSecond()
{
	ZeroMemory(recent_state,sizeof(recent_state));
	CHSH_Device::InitSecond(512,1024); // 480 x 640
	MapDrawn=false;
	char temppath[MAX_PATH],temppatha[MAX_PATH];

	sprintf(temppath,"%s\\hsh\\radar\\%s",AssetsDirectory1,"radar_background.bmp");
	pDDSBackground=CreateSurfaceFromFile(pDD,temppath);

// MSL 5.03 Mechview
    if (g_nMechViewType == 1)
	{
	    sprintf(temppath,"%s\\hsh\\%s",AssetsDirectory1,"mechview_background.bmp");
        pDDSMechViewBkgnd=CreateSurfaceFromFile(pDD,temppath);
    }
	else
	{
        pDDSMechViewBkgnd=NULL;
    }

// MSL 5.03 Secondary Damage Display
	pDDSRadarDamageTexture=0;
	
	//////Texture
	sprintf(temppath,"%s\\hsh\\radar\\%s",AssetsDirectory1,"radar_texture.bmp");
	sprintf(temppatha,"%s\\hsh\\radar\\%s",AssetsDirectory1,"radar_texturea.bmp");
	pDDSTexture=CreateRGBATextureFromFile(pDD, temppath,temppatha,16);
	tw=512;
	th=512;

// MSL 5.03 Mechview
    if (g_nMechViewType == 1)
	{
	    m_pDDSMechView=CreatePixelFormatTexture(pDD,m_ptMechViewDim.x,m_ptMechViewDim.y,&DDPF_R5G6B5);
	}
    else
	{
        m_pDDSMechView=NULL;
	}

	return true;
}

bool CRadar_Device::BeginScene()
{
	//Set the Render Target.
	SetRenderTargetTexture();


	//Draw background image to Texture. Used as a substitute for Clear..
	if(sh_game_started){
		//Draw background only when game has started.
		RECT rc={0,0,480,640};
		pDDSTarget->BltFast(0,0,pDDSBackground,&rc,0);
		if(IsMechShutdown())
		{
			//Clear map area.
			RECT rc={140,407,340,607};

			DDBLTFX fx={0,};
			fx.dwSize=sizeof(fx);
			fx.dwFillColor=0; 
			
			pDDSTarget->Blt(&rc,NULL,NULL,DDBLT_COLORFILL ,&fx);
		}
	}else{
		//If game has not started.. show blank.
		pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET ,0,1.0f,0);
	}
	pD3DDevice->BeginScene();
	if(sh_game_started && IsMechShutdown()){
		//Draw shutdown button.
		int state[12]={0,2,0,};
		state[3]=recent_state[3];//flush state: use the most recent value.
		state[11]=recent_state[11];//flush state: use the most recent value.
        if (!g_aaRadarText[0][0])
            strcpy(&g_aaRadarText[0][0], g_szRadarJumpjet);
        strcpy(&g_aaRadarText[1][0], g_szRadarStartup);

		pD3DDevice->SetTexture(0,0);
		pD3DDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
		pD3DDevice->SetRenderState( D3DRENDERSTATE_SRCBLEND,	D3DBLEND_SRCALPHA );
		pD3DDevice->SetRenderState( D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );

		DrawBackText(state);
	}
	pD3DDevice->SetTexture(0,pDDSTexture);
	return true;
}

bool CRadar_Device::EndScene()
{
	pD3DDevice->EndScene();

	if( gCaptureScreen && (gCaptureDevice == 1))
	{
	    if(pDD && pD3DDevice && pDDSTarget){
		    BYTE* Image=GrabScreenImage(pDDSTarget, 480, 640);
            WriteImageAfterGrab(Image, "radar-scr%04d.%s");
        }
        gCaptureScreen = 0;
	}

	SetRenderTargetBackbuffer();
	pD3DDevice->BeginScene();

		pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,FALSE);
		pD3DDevice->SetTexture( 0, pDDSTarget );

		DWORD color=0xFFFFFFFF;
		D3DTLVERTEX Vertices[4]; // Vertices for the cube
		
		float w=(float)size_back.cx;
		float h=(float)size_back.cy;
		float w2=(float)size_target.cx;
		float h2=(float)size_target.cy;

		Vertices[0] = D3DTLVERTEX(D3DVECTOR(w-0.5f,h-0.5f,0.9f),1.0f,color,0, 0/w2, w/h2);
		Vertices[1] = D3DTLVERTEX(D3DVECTOR(0-0.5f,h-0.5f,0.9f),1.0f,color,0, 0/w2, 0/h2);
		Vertices[2] = D3DTLVERTEX(D3DVECTOR(w-0.5f,0-0.5f,0.9f),1.0f,color,0, h/w2, w/h2);
		Vertices[3] = D3DTLVERTEX(D3DVECTOR(0-0.5f,0-0.5f,0.9f),1.0f,color,0, h/w2, 0/h2);

		pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices, 4, NULL );

	pD3DDevice->EndScene();
	return true;
}

	
bool CRadar_Device::Release()
{
	if(pDD){
// MSL 5.03 Mechview
        SAFE_RELEASE(m_pDDSMechView);
        SAFE_RELEASE(pDDSMechViewBkgnd);
		SAFE_RELEASE(pDDSBackground);
// MSL 5.03 Secondary Damage Display
		SAFE_RELEASE(pDDSRadarDamageTexture);
		CHSH_Device::Release();
	}
	return true;
}

// MSL 5.03 Secondary Damage Display
bool CRadar_Device::LoadRadarDamageTexture(const char *mechtexturename)
{
	SAFE_RELEASE(pDDSRadarDamageTexture);

	char temppath[MAX_PATH];
	sprintf(temppath,"%s\\hsh\\radar\\%s.bmp",AssetsDirectory1,mechtexturename);
	pDDSRadarDamageTexture=CreateATextureFromFile(pDD, temppath);
	return true;

}

struct POINTF
{
	float x,y;
};

POINTF radar_text_pos[12]={
	{ 20,56+105*0},{ 20,56+105*1},{ 20,56+105*2},{ 20,56+105*3},{ 20,56+105*4},{ 20,56+105*5},
	{460,56+105*0},{460,56+105*1},{460,56+105*2},{460,56+105*3},{460,56+105*4},{460,56+105*5},
};
//state 0:grayed
//state 1:ready
//state 2:activated

//Has a different meaning in pilot mode.

bool CRadar_Device::DrawBackText(int state[12])
{
	//Other Buttons - see VehicleInterface::GetGUIRadarStates(...)
	for(int i=0;i<12;i++)
	{
		switch(i)
		{
		case 2:
			break;
		case 11:
			break;
		default:
			const char* pcszRT = &g_aaRadarText[i][0];
			POINTF &pt=radar_text_pos[i];
			if(state[i]==0){
				pFont[3].DrawTextVerticalOrg(pt.x,pt.y,0xFF808080,pcszRT);
			}else if(state[i]==1){
				pFont[3].DrawTextVerticalOrg(pt.x,pt.y,0xFFFFFFFF,pcszRT);
			}else if(state[i]==2){
				DrawQuad((int)pt.x-21,(int)pt.y-51,(int)pt.x+20,(int)pt.y+50,0xFFFFFFFF);
				pFont[3].DrawTextVerticalOrg(pt.x,pt.y,0xFF000000,pcszRT);
			}
			break;
		}
	}
// MSL 5.03 Auxil Mode
	DWORD color2[3]={0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
	color2[state[2]]=0xFF000000;
	//Hilight
	DrawQuad(0-1,255+1+state[2]*20,40-2,275-1+state[2]*20,0xFFFFFFFF);
	//Texts
	pFont[3].DrawTextMultiLine(19,215+40/2,0xFFFFFFFF,&g_aaRadarText[2][0],TEXTALIGN_ORG);
	pFont[3].DrawText(20,255+20/2,color2[0],"MAP",TEXTALIGN_ORG);
	pFont[3].DrawText(20,275+20/2,color2[1],"DMG",TEXTALIGN_ORG);
	pFont[3].DrawText(20,295+20/2,color2[2],"TGT",TEXTALIGN_ORG);
	//Frames
	DrawFrame(0-1,215+1,40-2,255-1,0xFFFFFFFF);
	DrawFrame(0-1,255+1,40-2,275-1,0xFFFFFFFF);
	DrawFrame(0-1,275+1,40-2,295-1,0xFFFFFFFF);
	DrawFrame(0-1,295+1,40-2,315-1,0xFFFFFFFF);

	//Pilot Mode...
	DWORD color11[3]={0xFFFFFFFF,0xFFFFFFFF,0xFFFFFFFF};
	color11[state[11]]=0xFF000000;
	//Hilight
	DrawQuad(440,570+1+state[11]*20,480,590-1+state[11]*20,0xFFFFFFFF);
	//Texts
	pFont[3].DrawTextMultiLine(460,530+40/2,0xFFFFFFFF,&g_aaRadarText[11][0],TEXTALIGN_ORG);
	pFont[3].DrawText(460,570+20/2,color11[0],"BAS",TEXTALIGN_ORG);
	pFont[3].DrawText(460,590+20/2,color11[1],"MID",TEXTALIGN_ORG);
	pFont[3].DrawText(460,610+20/2,color11[2],"ADV",TEXTALIGN_ORG);
	//Frames
	DrawFrame(440,530+1,480,570-1,0xFFFFFFFF);
	DrawFrame(440,570+1,480,590-1,0xFFFFFFFF);
	DrawFrame(440,590+1,480,610-1,0xFFFFFFFF);
	DrawFrame(440,610+1,480,630-1,0xFFFFFFFF);
	return true;
}
	
/////////////////////////////////// CMFD_Device ///////////////////////////////////

static DWORD channel_color[6]={
	0xFFFF0000,
	0xFF00FF00,
	0xFF0000FF,
	0xFFFF0000,
	0xFF00FF00,
	0xFF0000FF,
};


CMFD_Device::CMFD_Device()
	: ch((DWORD)-1), m_pRightDevice(NULL)
{
}

CMFD_Device::~CMFD_Device()
{
}

bool CMFD_Device::InitFirst()
{
	// Mode 4: use g_nMFD1 (640x480) for left panel; also start up the right
	// device here so both displays are ready before InitSecond runs.
	if (g_nTypeOfMFDs == 4) {
		m_pRightDevice = &mfd_device_right;
		CHSH_Device::InitFirst(g_nMFD1, 640, 480);  // left device
		mfd_device_right.InitFirst();                // right device display mode
		return true;
	}
	m_pRightDevice = NULL;
	return CHSH_Device::InitFirst(g_nDualHead,1280,480);
}

bool CMFD_Device::InitSecond()
{
	CHSH_Device::InitSecond(1024,512); // 640 x 480
	if(g_f3dtarget){
		pDDSMechTexture=CreatePixelFormatTexture(pDD,128,128,&DDPF_R5G6B5);//Texture for storing 3D mech image...
	}else{
// MSL 5.02 Target MFD Image
		//		pDDSMechTexture=CreatePixelFormatTexture(pDD,512,512,&DDPF_R5G6B5);//texture for storing 2D mech image...
		pDDSMechTexture=CreatePixelFormatTexture(pDD,1024,1024,&DDPF_R5G6B5);//Texture for storing 2D mech image...
		//Store images for all mechs.
		for(int mech=0;mech<ARRAYSIZE(mechnames);mech++){
// MSL 5.02 Target MFD Image
//			int x=(mech%4)*128;
//			int y=(mech/4)*128;
			int x=(mech%8)*128;
			int y=(mech/8)*128;

			char temppath[MAX_PATH];
			sprintf(temppath,"%s\\hsh\\mfd\\%s.bmp",AssetsDirectory1,mechnames[mech]);

			DrawBitmapToSurface(pDDSMechTexture,x,y,temppath);
		}
	}
	//if(pDDSMechTexture==NULL)MessageBeep(0);
	//pDDSMechTexture=0;
	//pDDSDamageTexture=CreatePixelFormatTexture(pDD,512,512,&DDPF_R4G4B4A4);//damage image..
	pDDSDamageTexture=0;//On Reset: recreated... no need to create now.
// MSL 5.03 Target Damage Display
	pDDSTargetTexture=0;

	//////Texture
	char temppath[MAX_PATH];
	sprintf(temppath,"%s\\hsh\\%s",AssetsDirectory1,"mfd_texture.bmp");
	pDDSTexture=CreateATextureFromFile(pDD, temppath);
	//pDDSTexture=0;
	tw=512;
	th=512;

	//SmallFont.Init(pDD,pD3DDevice,"Arial",14,false,false);

	D3DMATERIAL7 mtrl;
	ZeroMemory( &mtrl, sizeof(mtrl) );
	mtrl.diffuse.r = mtrl.diffuse.g = mtrl.diffuse.b = 1.0f;
	mtrl.ambient.r = mtrl.ambient.g = mtrl.ambient.b = 1.0f;
	pD3DDevice->SetMaterial( &mtrl );
	pD3DDevice->SetRenderState( D3DRENDERSTATE_AMBIENT, 0xffffffff );

	// Mode 4: create flip chain + D3D device for the right 640x480 monitor.
	if (g_nTypeOfMFDs == 4 && m_pRightDevice) {
		mfd_device_right.InitSecond();
	}

	return true;
}

bool CMFD_Device::BeginChannel(DWORD channel)
{
	if (!sh_game_started)
		return false;
	if (ch != (DWORD)-1) {
		EndChannel();
	}
	// 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual)
	switch(g_nTypeOfMFDs)
	{
	default: // case 0:
		return false;
	case 1:
		if (sh_step != channel + 2)
			return false;
		break;
	case 2:
		switch(channel)
		{
		case 1:
			if (sh_step != 2)
				return false;
			channel = 4;
			break;
		case 3:
			if (sh_step != 3)
				return false;
			channel = 3;
			break;
		case 4:
			if (sh_step != 4)
				return false;
			channel = 5;
			break;
		default:
			return false;
		}
		break;
	case 4:
		// Same 7-step timing as mode 1: channels 0-4 map to sh_step 2-6.
		if (sh_step != (int)(channel + 2))
			return false;
		break;
	}
	ch=channel;

	//Set the Render Target.
	SetRenderTargetTexture();
	pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET ,0,0,0);
	pD3DDevice->BeginScene();
	pD3DDevice->SetTexture(0,pDDSTexture);
	return true;
}

bool CMFD_Device::EndChannel()
{
  if (ch != (DWORD)-1) {
	pD3DDevice->EndScene();

	if( gCaptureScreen && (gCaptureDevice == ((ch >> 16) + 3)))
	{
	    if(pDD && pD3DDevice && pDDSTarget){
		    BYTE* Image=GrabScreenImage(pDDSTarget, 0, 0);
            WriteImageAfterGrab(Image, "mfd-scr%04d.%s");
        }
        gCaptureScreen = 0;
	}

	// Mode 4: route this channel's blit to the correct physical monitor.
	// Handled here, before the modes 1-3 SetRenderTargetBackbuffer/BeginScene
	// block, so each path has exactly one matched Begin/EndScene pair.
	// Channels 0-2 go to the LEFT device (this, g_nMFD1).
	// Channels 3-4 go to the RIGHT device (m_pRightDevice, g_nMFD2).
	// pDDSTarget was created by this device's pDD; both devices are on the
	// same GPU so VRAM textures are mutually accessible.
	if (g_nTypeOfMFDs == 4 && m_pRightDevice) {
		CHSH_Device* target = (ch >= 3) ? m_pRightDevice : static_cast<CHSH_Device*>(this);
		target->SetRenderTargetBackbuffer();
		target->pD3DDevice->BeginScene();

		target->pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE);
		target->pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE);
		target->pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE);

		target->pD3DDevice->SetTexture(0, pDDSTarget);

		DWORD color4 = channel_color[ch];
		float w4   = (float)target->size_back.cx;  // 640
		float h4   = (float)target->size_back.cy;  // 480
		float w2_4 = (float)size_target.cx;        // 1024
		float h2_4 = (float)size_target.cy;        // 512
		D3DTLVERTEX V4[4];
		V4[0]=D3DTLVERTEX(D3DVECTOR(   -0.5f,h4-0.5f,0.9f),1.0f,color4,0,    0/w2_4,h4/h2_4);
		V4[1]=D3DTLVERTEX(D3DVECTOR(   -0.5f,  -0.5f,0.9f),1.0f,color4,0,    0/w2_4,   0/h2_4);
		V4[2]=D3DTLVERTEX(D3DVECTOR(w4-0.5f,h4-0.5f,0.9f),1.0f,color4,0,w4/w2_4,h4/h2_4);
		V4[3]=D3DTLVERTEX(D3DVECTOR(w4-0.5f,  -0.5f,0.9f),1.0f,color4,0,w4/w2_4,   0/h2_4);
		target->pD3DDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP,D3DFVF_TLVERTEX,V4,4,NULL);

		target->pD3DDevice->EndScene();
		ch = (DWORD)-1;
	} else {
		// Modes 1-3: blit to half of the single 1280-wide (or 640-wide) backbuffer.
		SetRenderTargetBackbuffer();
		pD3DDevice->BeginScene();

		pD3DDevice->SetRenderState(D3DRENDERSTATE_ALPHABLENDENABLE,TRUE);
		pD3DDevice->SetRenderState(D3DRENDERSTATE_SRCBLEND,D3DBLEND_ONE);
		pD3DDevice->SetRenderState(D3DRENDERSTATE_DESTBLEND,D3DBLEND_ONE);

		pD3DDevice->SetTexture( 0, pDDSTarget );

		DWORD color;
		
		color = channel_color[ch];
		//color = 0xFFFFFFFF;
		D3DTLVERTEX Vertices[4]; // Vertices for the cube
		
		float w=(float)size_back.cx/2;//<==NOTE: this differs from radar.
		float x1=(ch/3)*w;
		float x2=x1+w;
		float h=(float)size_back.cy;
		float w2=(float)size_target.cx;
		float h2=(float)size_target.cy;

		Vertices[0] = D3DTLVERTEX(D3DVECTOR(x1-0.5f,h-0.5f,0.9f),1.0f,color,0, 0/w2, h/h2);
		Vertices[1] = D3DTLVERTEX(D3DVECTOR(x1-0.5f,0-0.5f,0.9f),1.0f,color,0, 0/w2, 0/h2);
		Vertices[2] = D3DTLVERTEX(D3DVECTOR(x2-0.5f,h-0.5f,0.9f),1.0f,color,0, w/w2, h/h2);
		Vertices[3] = D3DTLVERTEX(D3DVECTOR(x2-0.5f,0-0.5f,0.9f),1.0f,color,0, w/w2, 0/h2);

		pD3DDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices, 4, NULL );

		pD3DDevice->EndScene();
		ch = (DWORD)-1;
	}
  }
	return true;
}


// Mode 4: same grid pattern as rcs640 but offset to x=0 for a standalone
// 640x480 surface (left half of rcs1280).
static RECT rcs640_solo[8]={
	{0,40,640,42},
	{ 160-1,0, 160+1,40},
	{ 320-1,0, 320+1,40},
	{ 480-1,0, 480+1,40},
	{0,480-42,640,480-40},
	{ 160-1,440, 160+1,480},
	{ 320-1,440, 320+1,480},
	{ 480-1,440, 480+1,480},
};

bool CMFD_Device::BeginScene()
{
/*
	DDBLTFX fx={0,};
	fx.dwSize=sizeof(fx);
	fx.dwFillColor=0xFFFF; 

	pDDSBack->Blt(NULL,NULL,NULL,DDBLT_COLORFILL |DDBLT_WAIT ,&fx);
*/
	// 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual)
	switch(g_nTypeOfMFDs)
	{
	case 1:
		SetRenderTargetBackbuffer();
		pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET ,0,1.0f,0);
		break;
	case 2:
		{static D3DRECT s_rc2 = { 640, 0, 1280, 480 };
		SetRenderTargetBackbuffer();
		pD3DDevice->Clear(1,&s_rc2,D3DCLEAR_TARGET ,0,1.0f,0);
		//pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET ,0,1.0f,0);
		}break;
	case 4:
		// Clear and draw background grid on the LEFT device only.
		// The right device is cleared/gridded in BeginSceneRight(),
		// called from WinMain at old sh_step==1 (one frame after the
		// right MFD flip) so its back buffer has fresh content when flipped.
		SetRenderTargetBackbuffer();
		pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0);
		pD3DDevice->BeginScene();
		if(sh_game_started) DrawMFDBackGrid();
		pD3DDevice->EndScene();
		return true;  // skip the common BeginScene/DrawGrid/EndScene below
	}
	pD3DDevice->BeginScene();
	if(sh_game_started) {
		//Draw background only when game has started..
		DrawMFDBackGrid();
	}
	pD3DDevice->EndScene();

	return true;
}


bool CMFD_Device::EndScene()
{
	return true;
}

// Mode 4: clear and draw the background grid on the right device.
// Called from WinMain at old sh_step==1, one frame after the right MFD
// flip, so channels 3-4 can render into a fresh back buffer before the
// next flip at new sh_step==1 (= old sh_step==0).
bool CMFD_Device::BeginSceneRight()
{
	if (g_nTypeOfMFDs != 4 || !m_pRightDevice)
		return false;
	m_pRightDevice->SetRenderTargetBackbuffer();
	m_pRightDevice->pD3DDevice->Clear(0,NULL,D3DCLEAR_TARGET,0,1.0f,0);
	m_pRightDevice->pD3DDevice->BeginScene();
	if(sh_game_started) {
		m_pRightDevice->pD3DDevice->SetTexture(0,0);
		m_pRightDevice->DrawQuadList(8,rcs640_solo,0xFFFFFFFF);
	}
	m_pRightDevice->pD3DDevice->EndScene();
	return true;
}


bool CMFD_Device::Release()
{
	if(pDD){
		//SmallFont.Cleanup();
		SAFE_RELEASE(pDDSMechTexture);
		SAFE_RELEASE(pDDSDamageTexture);
// MSL 5.03 Target Damage Display
		SAFE_RELEASE(pDDSTargetTexture);
		// Mode 4: release the right device before releasing this (left) device.
		if (g_nTypeOfMFDs == 4 && m_pRightDevice) {
			m_pRightDevice->Release();
			m_pRightDevice = NULL;
		}
		CHSH_Device::Release();
	}
	return true;
}

bool CMFD_Device::LoadDamageTexture(const char *mechtexturename)
{
	SAFE_RELEASE(pDDSDamageTexture);

	char temppath[MAX_PATH];
	sprintf(temppath,"%s\\hsh\\%s.bmp",AssetsDirectory1,mechtexturename);
	pDDSDamageTexture=CreateATextureFromFile(pDD, temppath);
	return true;
}

// MSL 5.03 Target Damage Display
bool CMFD_Device::LoadTargetTexture(const char *mechtexturename)
{
	SAFE_RELEASE(pDDSTargetTexture);

	char temppath[MAX_PATH];
	sprintf(temppath,"%s\\hsh\\%s.bmp",AssetsDirectory1,mechtexturename);
	pDDSTargetTexture=CreateATextureFromFile(pDD, temppath);
	return true;
}

bool CMFD_Device::DrawMFDBackText(char text[8][32], const int* pnStates/* = NULL*/)
{
	for(int i=0;i<8;i++){
		if(text[i][0]){
			float x=(float)(80+160*(i%4));
			float y=(float)(20+(i/4)*440);
            DWORD dwColor = 0XFFFFFFFF;
            if (pnStates) {
                if (pnStates[i]==0) {
                    dwColor = 0xFF808080;
                } else if (pnStates[i]==2) {
                    DrawQuad((int)x - 80, (int)y - 20,(int)x+80,(int)y+20,0xFFFFFFFF);
                    dwColor = 0XFF000000;
                }
            }
			pFont[2].DrawTextMultiLine(x,y,dwColor,text[i],TEXTALIGN_ORG);
		}
	}
	return true;
}
/*
bool CMFD_Device::DrawMFDBackText(char text[8][32],RIOBUTTON * state)
{
	for(int i=0;i<8;i++){
		if(text[i][0]){
			float x=(float)(80+160*(i%4));
			float y=(float)(20+(i/4)*440);
			if(state[7-i].lamp==LAMP_DIM 
				|| state[7-i].lamp==LAMP_BRIGHT
				|| state[7-i].lamp==LAMP_FLASH){
				pFont[2].DrawTextMultiLine(x,y,0XFFFFFFFF,text[i],TEXTALIGN_ORG);
			}else{
				pFont[2].DrawTextMultiLine(x,y,0XFF808080,text[i],TEXTALIGN_ORG);
			}
		}
	}
	return true;
}
*/
static POINTF mfd_text_coord[8]={//mfd text coord
	{80, 20},{240, 20},{400, 20},{560, 20},
	{80,460},{240,460},{400,460},{560,460}
};

static char mfd_text_weapon[8][32]={
	"FIRING MODE","","NEXTWEAPON","PREVWEAPON",
	"CHAINFIRE","ASSIGNGROUP1","ASSIGNGROUP2","ASSIGNGROUP3"
};

#if 1
static char mfd_text_weapon2[8][32]={
	"FIRING MODE","","","",
	"GROUP FIRE","","",""
};
#else
static char mfd_text_weapon2[8][32]={
	"FIRING MODE","","NEXTWEAPON","PREVWEAPON",
	"GROUP FIRE","ASSIGNGROUP1","ASSIGNGROUP2","ASSIGNGROUP3"
};
#endif

bool CMFD_Device::DrawMFDBackTextAux3(int state)
{
	if(state){//chain fire mode
		for(int i=0;i<8;i++){
			if(mfd_text_weapon[i][0]){
				POINTF &tc = mfd_text_coord[i];
				if(i!=4){
					pFont[2].DrawTextMultiLine(tc.x,tc.y,0XFFFFFFFF,mfd_text_weapon[i],TEXTALIGN_ORG);
				}else{//display chain fire
					DrawQuad((int)tc.x-80,(int)tc.y-20,(int)tc.x+80,(int)tc.y+20,0xFFFFFFFF);
					pFont[2].DrawTextMultiLine(tc.x,tc.y,0XFF000000,mfd_text_weapon[i],TEXTALIGN_ORG);
				}
			}
		}
	}else{//group fire mode
		for(int i=0;i<8;i++){
			if(mfd_text_weapon2[i][0]){
				POINTF &tc = mfd_text_coord[i];
				DWORD color=(i==0||i==4 )?0xFFFFFFFF:0xFF808080;
				pFont[2].DrawTextMultiLine(tc.x,tc.y,color,mfd_text_weapon2[i],TEXTALIGN_ORG);
			}
		}
	}
	return true;
}

static RECT rcs1280[14]={
	{0,40,1280,42},
	{ 160-1,0, 160+1,40},
	{ 320-1,0, 320+1,40},
	{ 480-1,0, 480+1,40},
	{ 800-1,0, 800+1,40},
	{ 960-1,0, 960+1,40},
	{1120-1,0,1120+1,40},
	{0,480-42,1280,480-40},
	{ 160-1,440, 160+1,480},
	{ 320-1,440, 320+1,480},
	{ 480-1,440, 480+1,480},
	{ 800-1,440, 800+1,480},
	{ 960-1,440, 960+1,480},
	{1120-1,440,1120+1,480},
};

static RECT rcs640[8]={
	{640,40,1280,42},
	{ 800-1,0, 800+1,40},
	{ 960-1,0, 960+1,40},
	{1120-1,0,1120+1,40},
	{640,480-42,1280,480-40},
	{ 800-1,440, 800+1,480},
	{ 960-1,440, 960+1,480},
	{1120-1,440,1120+1,480},
};

bool CMFD_Device::DrawMFDBackGrid()
{
	pD3DDevice->SetTexture(0,0);
	pD3DDevice->SetTextureStageState(0,D3DTSS_MAGFILTER, D3DTFG_POINT);
	pD3DDevice->SetTextureStageState(0,D3DTSS_MINFILTER, D3DTFG_POINT);
	
	switch(g_nTypeOfMFDs)
	{
	case 1:
		DrawQuadList(14,rcs1280,0xFFFFFFFF);
		break;
	case 2:
		DrawQuadList(8,rcs640,0xFFFFFFFF);
		break;
	case 4:
		// Left device uses the left-half grid (0..640).
		// Right device grid is drawn separately in BeginScene.
		DrawQuadList(8,rcs640_solo,0xFFFFFFFF);
		break;
	}

	return true;
}

char aux1_messages[14 + 2][60] =
{
    { "1 - Attack my Target" },
	{ "2 - Defend my Target" },
	{ "3 - Form up on Me" },
	{ "4 - Advance" },
	{ "5 - Fall Back" },
	{ "6 - Enemy Spotted" },
	{ "7 - Taking Fire, Need Assistance" },
	{ "1 - OHHHH, That'll Leave a Mark..." },
	{ "2 - Feel the Love!!!" },
	{ "3 - Here, Hold my Ammo!!!" },
	{ "4 - Like Shooting Fish in a Barrel" },
	{ "5 - Is that the best you can DO!!!" },
	{ "6 - Here, let me remove that for you!!" },
    { "7 - There's more where that came from!!" },
    { "1 - Order Acknowledged" }, //
    { "2 - Order Not Acknowledged" },
};

static char mfd_text_comm2[8][32]={
	"1","2","3","4",
	"5","6","7","EXIT",
};

static RECT aux1freequads[]={
	{0,180-1,640,180+1},
	
	{160-1, 40,160+1,180},
	{320-1, 40,320+1,180},
	{480-1, 40,480+1,180},

	{0,300-1,640,300+1},

	{160-1,300,160+1,440},
	{320-1,300,320+1,440},
	{480-1,300,480+1,440},
};
enum {TEAMORDER_NONE, TEAM_MODE, FREEFORALL_MODE, TEAM_MESSAGE1, TEAM_MESSAGE2};


bool CMFD_Device::DrawMFDDefaultBackAux1(int state)
{
	if(state==TEAM_MODE){
		//Show mech status.
		DrawQuad(0,240-1,640,240+1,0xFFFFFFFF);
		DrawQuad(160-1,0,160+1,240,0xFFFFFFFF);
		DrawQuad(320-1,0,320+1,240,0xFFFFFFFF);
		DrawQuad(480-1,0,480+1,240,0xFFFFFFFF);
	}else if(state==FREEFORALL_MODE){
		DrawQuadList(8,aux1freequads,0xFFFFFFFF);
	}else if(state==TEAM_MESSAGE1){//nothing more to draw.
		DrawMFDBackText(mfd_text_comm2);
		for(int i=0;i<7;i++){
			int y=80+i*40;
			pFont[0].DrawText(80,(float)y,0xFFFFFFFF,&aux1_messages[i][0],0);
		}
	}else if(state==TEAM_MESSAGE2){//nothing more to draw.
		DrawMFDBackText(mfd_text_comm2);
		for(int i=0;i<7;i++){
			int y=80+i*40;
			pFont[0].DrawText(80,(float)y,0xFFFFFFFF,&aux1_messages[i + 7][0],0);
		}
	}

	return true;
}

//_____________________________________________________________________________________________________
//
//									Font3D
//_____________________________________________________________________________________________________

static DWORD GetFontAreaHeight(DWORD width,HFONT hfont)
{
	HDC hdc=GetDC(NULL);
	HFONT holdfont=(HFONT)SelectObject(hdc,hfont);

	char str[4];
	DWORD x=0,y=0;
	SIZE size={0,};
	for( char c=32; c<127; c++ ){
		str[0] = c;
		GetTextExtentPoint32( hdc, str, 1, &size );
		
		if( (DWORD)(x+size.cx+1) > width ){
			x  = 0;
			y += size.cy+1;
		}
		x += size.cx+1;
	}

	SelectObject(hdc,holdfont);
	ReleaseDC(NULL,hdc);
	return (y+ size.cy+1);
}

static HFONT CreateFont(DWORD dwHeight, bool fBold,bool fItalic,const char* FaceName)
{
	DWORD dwBold   = fBold	? FW_BOLD : FW_NORMAL;
	DWORD dwItalic = fItalic ? TRUE   : FALSE;

	return CreateFont( dwHeight, 0, 0, 0, dwBold, dwItalic,
						FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
						CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY,
						VARIABLE_PITCH, FaceName );
}

static int Get2NHeight(int h)
{
	for(int i=6;i<=10;i++){
		if(h<=(1<<i))return (1<<i);
	}
	return 0;
}

//input:Font Handle,Font Height(One Character)
//output:expected width and height
static void GetFontTextureSize(HFONT hFont,DWORD dwHeight,DWORD &w,DWORD& h)
{
	//Width
	w=(dwHeight>=50)?512:256;
	//Height
	DWORD height=GetFontAreaHeight(w,hFont);
	h=Get2NHeight(height);
}

static HBITMAP CreateTopDownDIB32(int Width,int Height,DWORD**ppBitmapBits)
{
	BITMAPINFO bmi;
	ZeroMemory( &bmi.bmiHeader,  sizeof(BITMAPINFOHEADER) );
	bmi.bmiHeader.biSize		= sizeof(BITMAPINFOHEADER);
	bmi.bmiHeader.biWidth		=  (int)Width;
	bmi.bmiHeader.biHeight		= -(int)Height;
	bmi.bmiHeader.biPlanes		= 1;
	bmi.bmiHeader.biCompression = BI_RGB;
	bmi.bmiHeader.biBitCount	= 32;
	
	return CreateDIBSection( NULL, &bmi, DIB_RGB_COLORS,(VOID**)ppBitmapBits, NULL, 0 );
}

CHSHFont::CHSHFont()
{
	m_pd3dDevice=0;
	m_pTexture=0;
	
	m_dwSavedStateBlock=0;
	m_dwDrawTextStateBlock=0;
}

CHSHFont::~CHSHFont()
{
}

void CHSHFont::Init(LPDIRECTDRAW7 pDD, LPDIRECT3DDEVICE7 pd3dDevice ,const char* strFontName, DWORD dwHeight, bool fBold,bool fItalic)
{
	if(pd3dDevice==NULL)return;
	m_pd3dDevice = pd3dDevice;
	m_pd3dDevice->AddRef();

	HFONT hFont    = CreateFont( dwHeight, fBold, fItalic,strFontName);
	
	GetFontTextureSize(hFont,dwHeight,m_dwTexWidth,m_dwTexHeight);

	m_pTexture=CreateRGBATexture(pDD,m_dwTexWidth,m_dwTexHeight,16);
	
	// Prepare to create a bitmap
	DWORD * pBitmapBits;
	HBITMAP hbmBitmap;
	hbmBitmap=CreateTopDownDIB32(m_dwTexWidth,m_dwTexHeight,&pBitmapBits);

	// Create a DC and a bitmap for the font
	HDC 	hDC 	  = CreateCompatibleDC( NULL );
	SelectObject( hDC, hbmBitmap );
	SelectObject( hDC, hFont );
	SetBkColor(hDC,0);
	SetTextColor(hDC,RGB(255,255,255));
	
	DWORD x = 0;
	DWORD y = 0;
	char str[4] = {0,};//For DWORD alignment.. (originally 2 would suffice.)
	SIZE size;
	m_dwMaxWidth=0;//Initialize to minimum value.
	for( char c=32; c<127; c++ ){

		str[0] = c;
		GetTextExtentPoint32( hDC, str, 1, &size );
		
		if( (DWORD)(x+size.cx+1) > m_dwTexWidth ){
			x  = 0;
			y += size.cy+1;
		}
		if(size.cx>(int)m_dwMaxWidth){//widest single character..
			m_dwMaxWidth=size.cx;
		}

		//j invades the region of i. Take appropriate action...
		ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL );
		
		m_fTexCoords[c-32][0] = ((float)(x+0))/m_dwTexWidth;
		m_fTexCoords[c-32][1] = ((float)(y+0))/m_dwTexHeight;
		m_fTexCoords[c-32][2] = ((float)(x+0+size.cx))/m_dwTexWidth;
		m_fTexCoords[c-32][3] = ((float)(y+0+size.cy))/m_dwTexHeight;
		
		x += size.cx+1;
	}
	
	WORD* pDst16 = (WORD*)GetSurfacePointer(m_pTexture);
	
	for( y=0; y < m_dwTexHeight; y++ ){
		for( x=0; x < m_dwTexWidth; x++ ){
			//bAlpha = (BYTE)((pBitmapBits[m_dwTexWidth*y + x] & 0xff) >> 4);
			int alpha= pBitmapBits[m_dwTexWidth*y + x] & 0xff;
			alpha=alpha*alpha/0xFF;
			alpha >>= 4;
			if (alpha> 0)
				*pDst16++ = (WORD)((alpha << 12) | 0x0fff);
			else
				*pDst16++ = 0x0000;
		}
	}
	
	ReleaseSurfacePointer(m_pTexture);

	DeleteObject( hbmBitmap );
	DeleteDC( hDC );
	DeleteObject( hFont );

	//////StateBlock related..
	for( UINT which=0; which<2; which++ ){
		m_pd3dDevice->BeginStateBlock();
		m_pd3dDevice->SetTexture( 0, m_pTexture );
		m_pd3dDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
		m_pd3dDevice->SetRenderState( D3DRENDERSTATE_SRCBLEND,	D3DBLEND_SRCALPHA );
		m_pd3dDevice->SetRenderState( D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );

		LPDWORD blocktosave = (which==0) ? &m_dwSavedStateBlock:&m_dwDrawTextStateBlock;

		m_pd3dDevice->EndStateBlock(blocktosave);
	}
}

/*
void CHSHFont::Init(LPDIRECTDRAW7 pDD, LPDIRECT3DDEVICE7 pd3dDevice ,const char* strFontName, DWORD dwHeight, bool fBold,bool fItalic)
{
	if(pd3dDevice==NULL)return;
	m_pd3dDevice = pd3dDevice;
	m_pd3dDevice->AddRef();

	HFONT hFont    = CreateFont( dwHeight, fBold, fItalic,strFontName);
	
	GetFontTextureSize(hFont,dwHeight,m_dwTexWidth,m_dwTexHeight);

	m_pTexture=CreateRGBATexture(pDD,m_dwTexWidth,m_dwTexHeight,32);
	
	// Prepare to create a bitmap
	DWORD * pBitmapBits;
	HBITMAP hbmBitmap;
	hbmBitmap=CreateTopDownDIB32(m_dwTexWidth,m_dwTexHeight,&pBitmapBits);

	// Create a DC and a bitmap for the font
	HDC 	hDC 	  = CreateCompatibleDC( NULL );
	SelectObject( hDC, hbmBitmap );
	SelectObject( hDC, hFont );
	SetBkColor(hDC,0);
	SetTextColor(hDC,RGB(255,255,255));
	
	DWORD x = 0;
	DWORD y = 0;
	char str[4] = {0,};//For DWORD alignment.. (originally 2 would suffice.)
	SIZE size;
	m_dwMaxWidth=0;//Initialize to minimum value.
	for( char c=32; c<127; c++ ){

		str[0] = c;
		GetTextExtentPoint32( hDC, str, 1, &size );
		
		if( (DWORD)(x+size.cx+1) > m_dwTexWidth ){
			x  = 0;
			y += size.cy+1;
		}
		if(size.cx>(int)m_dwMaxWidth){//widest single character..
			m_dwMaxWidth=size.cx;
		}

		//j invades the region of i. Take appropriate action...
		ExtTextOut( hDC, x+0, y+0, ETO_OPAQUE, NULL, str, 1, NULL );
		
		m_fTexCoords[c-32][0] = ((float)(x+0))/m_dwTexWidth;
		m_fTexCoords[c-32][1] = ((float)(y+0))/m_dwTexHeight;
		m_fTexCoords[c-32][2] = ((float)(x+0+size.cx))/m_dwTexWidth;
		m_fTexCoords[c-32][3] = ((float)(y+0+size.cy))/m_dwTexHeight;
		
		x += size.cx+1;
	}
	
	DWORD* pDst32 = (DWORD*)GetSurfacePointer(m_pTexture);
	BYTE bAlpha;
	
	for( y=0; y < m_dwTexHeight; y++ ){
		for( x=0; x < m_dwTexWidth; x++ ){
			DWORD w= pBitmapBits[m_dwTexWidth*y + x];
			bAlpha = (BYTE)(w & 0xff);
			if (bAlpha > 0)
				*pDst32++ = ((bAlpha << 24) | w);
			else
				*pDst32++ = 0x0000;
		}
	}
	
	ReleaseSurfacePointer(m_pTexture);

	DeleteObject( hbmBitmap );
	DeleteDC( hDC );
	DeleteObject( hFont );

	//////StateBlock related..
	for( UINT which=0; which<2; which++ ){
		m_pd3dDevice->BeginStateBlock();
		m_pd3dDevice->SetTexture( 0, m_pTexture );
		m_pd3dDevice->SetRenderState( D3DRENDERSTATE_ALPHABLENDENABLE, TRUE );
		m_pd3dDevice->SetRenderState( D3DRENDERSTATE_SRCBLEND,	D3DBLEND_SRCALPHA );
		m_pd3dDevice->SetRenderState( D3DRENDERSTATE_DESTBLEND, D3DBLEND_INVSRCALPHA );

		LPDWORD blocktosave = (which==0) ? &m_dwSavedStateBlock:&m_dwDrawTextStateBlock;

		m_pd3dDevice->EndStateBlock(blocktosave);
	}
}

*/

void CHSHFont::Cleanup()
{
	// Delete the state blocks
	if( m_pd3dDevice ){
		if( m_dwSavedStateBlock ){
			m_pd3dDevice->DeleteStateBlock( m_dwSavedStateBlock );
			m_dwSavedStateBlock    = 0L;
		}
		if( m_dwDrawTextStateBlock ){
			m_pd3dDevice->DeleteStateBlock( m_dwDrawTextStateBlock );
			m_dwDrawTextStateBlock = 0L;
		}
		SAFE_RELEASE( m_pTexture );
		SAFE_RELEASE( m_pd3dDevice );
	}//If m_pd3dDevice==NULL, do nothing.
	
}
HRESULT CHSHFont::GetTextExtent(const char* strText, SIZE* pSize )
{
	if( NULL==strText || NULL==pSize )return E_FAIL;
	
	float fRowWidth  = 0.0f;
	float fRowHeight = (m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight;
	float fWidth	 = 0.0f;
	float fHeight	 = fRowHeight;
	
	char c;
	while( (c=*strText++)!=0 ){
		if( c == '\n' ){
			fRowWidth = 0.0f;
			fHeight  += fRowHeight;
		}

		if( c < ' ' )continue;
		
		float tx1 = m_fTexCoords[c-32][0];
		float tx2 = m_fTexCoords[c-32][2];
		
		fRowWidth += (tx2-tx1)*m_dwTexWidth;
		
		if( fRowWidth > fWidth )fWidth = fRowWidth;
	}
	
	pSize->cx = (int)fWidth;
	pSize->cy = (int)fHeight;
	
	return S_OK;
}

HRESULT CHSHFont::DrawText( float sx, float sy, DWORD dwColor,const char* strText)
{
	if( m_pd3dDevice == NULL )
		return E_FAIL;
	
	// Setup renderstate
	m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
	m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
	m_pd3dDevice->SetTexture(0,m_pTexture);
	
	// Fill vertex buffer
	DWORD		  dwNumVtx = 0;
	D3DTLVERTEX *	pVertices =m_pVB;
	char c;
	float osx=sx;//original sx;
	float h = (m_fTexCoords[0][3]-m_fTexCoords[0][1]) *  m_dwTexHeight ;//Height of each character should all be the same.

	while( (c = *strText++)!=0 ){
		
		if( c == '\n')sy+=h,sx=osx;//when displaying multiple lines...

		if( c < ' ' )continue;
		
		float *TexCoords=m_fTexCoords[c-32];
		float tx1 = TexCoords[0];
		float ty1 = TexCoords[1];
		float tx2 = TexCoords[2];
		float ty2 = TexCoords[3];
		
		float w = (tx2-tx1) *  m_dwTexWidth ;
		
		*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+0-0.5f,sy+h-0.5f,0.9f),1.0f, dwColor,0, tx1, ty2 );
		*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+0-0.5f,sy+0-0.5f,0.9f),1.0f, dwColor,0, tx1, ty1 );
		*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+w-0.5f,sy+h-0.5f,0.9f),1.0f, dwColor,0, tx2, ty2 );
		*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+w-0.5f,sy+0-0.5f,0.9f),1.0f, dwColor,0, tx2, ty1 );
		*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+w-0.5f,sy+h-0.5f,0.9f),1.0f, dwColor,0, tx2, ty2 );
		*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+0-0.5f,sy+0-0.5f,0.9f),1.0f, dwColor,0, tx1, ty1 );
		dwNumVtx += 6;
		
		if( dwNumVtx > (MAX_NUM_VERTICES-6) ){
			m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX ,m_pVB,dwNumVtx,0 );
			pVertices = m_pVB;
			dwNumVtx = 0L;
		}
		
		sx += w;
	}
	
	//Draw the remaining items.
	if(dwNumVtx> 0 ){
		m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX ,m_pVB,dwNumVtx,0 );
	}
	
	// Restore the modified renderstates
	m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
	
	return S_OK;
}

HRESULT CHSHFont::DrawText( float sx, float sy, DWORD dwColor,const char* strText,DWORD dwFlags)
{
	SIZE size;
	GetTextExtent(strText, &size );

	int offsetx=0;

	switch(dwFlags&TEXTALIGN_HORZ){
	case TEXTALIGN_LEFT:
		offsetx=0;
		break;
	case TEXTALIGN_RIGHT:
		offsetx = -size.cx;
		break;
	case TEXTALIGN_CENTER:
		offsetx = -size.cx/2;
		break;
	}

	int offsety=0;
	switch(dwFlags&TEXTALIGN_VERT){
	case TEXTALIGN_TOP:
		offsety=0;
		break;
	case TEXTALIGN_BOTTOM:
		offsety=-size.cy;
		break;
	case TEXTALIGN_VCENTER:
		offsety=-size.cy/2;
		break;
	}

	return DrawText(sx+(float)offsetx,sy+(float)offsety,dwColor,strText);
}

HRESULT CHSHFont::DrawTextMultiLine( float sx, float sy, DWORD dwColor,const char* strText,DWORD dwFlags)
{
	SIZE size;
	GetTextExtent(strText, &size );
	int RowHeight = (int)((m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight);

	int offsetx=0;


	int offsety=0;
	switch(dwFlags&TEXTALIGN_VERT){
	case TEXTALIGN_TOP:
		offsety=0;
		break;
	case TEXTALIGN_BOTTOM:
		offsety=-size.cy;
		break;
	case TEXTALIGN_VCENTER:
		offsety=-size.cy/2;
		break;
	}

	char string[128];//Max length set arbitrarily.
	strcpy(string,strText);
	char * seps="\n";
	char * token;
	token = strtok( string, seps );

	while( token != NULL ){
		GetTextExtent(token, &size );

		switch(dwFlags&TEXTALIGN_HORZ){
		case TEXTALIGN_LEFT:
			offsetx=0;
			break;
		case TEXTALIGN_RIGHT:
			offsetx = -size.cx;
			break;
		case TEXTALIGN_CENTER:
			offsetx = -size.cx/2;
			break;
		}
		DrawText(sx+(float)offsetx,sy+(float)offsety,dwColor,token);
		offsety+=RowHeight;
		token = strtok( NULL, seps );
	}

	return S_OK;
}

HRESULT CHSHFont::DrawTextVerticalOrg( float sx, float sy, DWORD dwColor,const char* strText)
{
	if( NULL==strText)return E_FAIL;

	float h = (float)((m_fTexCoords[0][3]-m_fTexCoords[0][1])*m_dwTexHeight);
	float w = (float)m_dwMaxWidth;

	//Name assuming horizontal (left-to-right) text layout.
	int col_count=0;//maximum column count
	int row_count=1;

	
	char c;
	int ccount=0;//column count
	const char * text=strText;
	while( (c=*text++)!=0 ){
		if( c == '\n' ){
			ccount=0;
			row_count++;
		}

		if( c < ' ' )continue;
		ccount++;
		if(ccount>col_count)col_count=ccount;//update the max value
	}
	//This is the size when writing from scratch.
	SIZE size;
	size.cx=(int)(row_count*w);
	size.cy=(int)(col_count*h);

	if( m_pd3dDevice == NULL )
		return E_FAIL;

	// Setup renderstate
	m_pd3dDevice->CaptureStateBlock( m_dwSavedStateBlock );
	m_pd3dDevice->ApplyStateBlock( m_dwDrawTextStateBlock );
	m_pd3dDevice->SetTexture(0,m_pTexture);

	char string[128];//Max length set arbitrarily.
	strcpy(string,strText);
	char * seps="\n";
	char * token;

	DWORD		  dwNumVtx = 0;
	D3DTLVERTEX *	pVertices =m_pVB;

	float osy=sy-size.cy/2;//original sy: topmost coordinate..;
	sx=sx-size.cx/2;


	token = strtok( string, seps );
	while( token != NULL ){
		sy=osy+(col_count-strlen(token))*h/2;

		char c;
		while( (c = *token ++)!=0 ){
			if( c < ' ' )continue;
			
			float *TexCoords=m_fTexCoords[c-32];
			float tx1 = TexCoords[0];
			float ty1 = TexCoords[1];
			float tx2 = TexCoords[2];
			float ty2 = TexCoords[3];
			
			float W=(tx2-tx1)*m_dwTexWidth;
			int W1=(int)(w-W)/2;
			int W2=(int)(w+W)/2;
			*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+W1-0.5f,sy+h-0.5f,0.9f),1.0f, dwColor,0, tx1, ty2 );
			*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+W1-0.5f,sy+0-0.5f,0.9f),1.0f, dwColor,0, tx1, ty1 );
			*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+W2-0.5f,sy+h-0.5f,0.9f),1.0f, dwColor,0, tx2, ty2 );
			*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+W2-0.5f,sy+0-0.5f,0.9f),1.0f, dwColor,0, tx2, ty1 );
			*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+W2-0.5f,sy+h-0.5f,0.9f),1.0f, dwColor,0, tx2, ty2 );
			*pVertices++ = D3DTLVERTEX(D3DVECTOR(sx+W1-0.5f,sy+0-0.5f,0.9f),1.0f, dwColor,0, tx1, ty1 );
			dwNumVtx += 6;
			
			if( dwNumVtx > (MAX_NUM_VERTICES-6) ){
				m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX ,m_pVB,dwNumVtx,0 );
				pVertices = m_pVB;
				dwNumVtx = 0L;
			}
			sy += h;
		}
		sx+=w;
		token = strtok( NULL, seps );
	}
	
	//Draw the remaining items.
	if(dwNumVtx> 0 ){
		m_pd3dDevice->DrawPrimitive( D3DPT_TRIANGLELIST, D3DFVF_TLVERTEX ,m_pVB,dwNumVtx,0 );
	}
	
	// Restore the modified renderstates
	m_pd3dDevice->ApplyStateBlock( m_dwSavedStateBlock );
	
	return S_OK;
}

//_____________________________________________________________________________________________________
//
//									CopyTargetImage
//_____________________________________________________________________________________________________

static LPVOID GetSurfacePointer(LPDIRECTDRAWSURFACE7 psurf,RECT& rc,LONG& lPitch,DWORD flag)
{
	DDSURFACEDESC2 desc={0,};
	desc.dwSize=sizeof(desc);

	psurf->Lock(&rc,&desc,DDLOCK_WAIT|DDLOCK_NOSYSLOCK|flag  ,NULL);
	lPitch=desc.lPitch;
	return desc.lpSurface;
}

static void ReleaseSurfacePointer(LPDIRECTDRAWSURFACE7 psurf,RECT& rc)
{
	psurf->Unlock(&rc);
}

extern LPDIRECTDRAWSURFACE7 BackBufferSurface;
extern IDirectDrawSurface7*	SH_TargetBufferSurface;

//stage
//0:init
//1:normal function
//2:cleanup
int sh_step;

int __cdecl CopyTargetImage(int stage,LPDIRECTDRAWSURFACE7 tex,int step)
{
	if(hsh_initialized){
	static DWORD* mem_org;
	static bool inited=false;
	static LPDIRECTDRAWSURFACE7 texture;

	if(stage==1){
		if(inited){
		//normal function
		//Placed at the top for performance reasons..
			RECT rc={0,0,128,128};
			LONG lPitch;
			LPDWORD agp_org,agp,pci_org,pci,mem;
			int x,y;
			int sx=0,sy=10,ex=120,ey=112;
			//int hy=ey-sy;//height.
//			if(1<=sh_step&&sh_step<=3){
				//1. AGP->MEM
				//int h=(sh_step-1)*hy/3;//segment offset..
				mem=mem_org;
				agp_org=(DWORD*)GetSurfacePointer(SH_TargetBufferSurface,rc,lPitch,DDLOCK_READONLY );
				if(agp_org!=NULL){
					if(lPitch%4==0){// execute only when DWORD aligned.
						for(y=sy;y<ey;y++){
							agp=agp_org+lPitch/4*y;
							mem=mem_org+128*2/4*y;
							for(x=sx;x<ex*2/4;x++){
								*mem++=*agp++;
							}
						}
					}
					ReleaseSurfacePointer(SH_TargetBufferSurface,rc);
				}
//			}else if(sh_step==4){
				//2. MEM Only
				WORD* wmem;
				for(y=sy;y<ey;y++){
					wmem=((WORD*)mem_org)+128*y;
					for(x=sx;x<ex;x++){
						DWORD p=*wmem;//pixel.
						DWORD r=p>>11;
						DWORD g=(p>>6)&0x1F;
						DWORD b=p&0x1F;
						DWORD s=r+g+b+10;
						s=(s>31)?31:s;
						s=(p==0x07FF)?0:s;
						
						*wmem++=(WORD)(s|(s<<6)|(s<<11));
					}
				}
//			}else if(sh_step==5){
				//3. MEM->PCI
				mem=mem_org;
				pci_org=(DWORD*)GetSurfacePointer(texture,rc,lPitch,DDLOCK_WRITEONLY );
				if(pci_org){
					if(lPitch%4==0){// execute only when DWORD aligned.
						for(y=sy;y<ey;y++){
							pci=pci_org+lPitch/4*y;
							mem=mem_org+128*2/4*y;
							for(x=sx;x<ex*2/4;x++){
								*pci++=*mem++;
							}
						}
					}
					ReleaseSurfacePointer(texture,rc);
				}
//			}

		}
	}else if(stage==0){
		//init
		if(tex){
			texture=tex;
			texture->AddRef();
			mem_org=(DWORD*)LocalAlloc(LPTR,128*128*2);
			inited=true;
		}
	}else if(stage==2){
		//cleanup
		if(inited){
			texture->Release();
			texture=0;
			LocalFree((HLOCAL)mem_org);
			mem_org=0;
			inited=false;
		}
	}
	}
	return 0;
}

//_____________________________________________________________________________________________________
//
//									Full Screen
//_____________________________________________________________________________________________________

//Previously served a role similar to SCREENS
//Set by command line parameter and does not change thereafter.
bool use_multimonitor;

//Normally true.. but becomes false when entering windowed mode..
//If true.. runs all drawing routines; if false, does nothing.
bool draw_mfd_huds;

//Force to true when windowed mode is entered. (currently..)
//Unrelated to multi-monitor drawing.
bool draw_main_huds;
CRadar_Device radar_device;
CMFD_Device mfd_device;
extern int g_nTypeOfMFDs; // 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual)
extern int g_nDualHead2;

bool IsMultimonitorAvaliable()
{
    if (g_pfnCTCL_GetType) {
		if ((*g_pfnCTCL_GetType)()==_ECTCL_CameraShip)
            return false;
    }
	// Mode 4 uses its own device slots ? g_nDualHead is not required.
	if (g_nTypeOfMFDs == 4)
		return (g_nMFD1 != -1 && g_nMFD2 != -1);
	if (g_nDualHead != -1) {
		// 0 - no MFDs, 1 - orginal(5+1=dual & single), 2 - B&W(3 + 1=1 dual), 3 - color(3 + 1=2 dual)
		switch(g_nTypeOfMFDs)
        {
		case 1:
			if (g_nNonDualHead != -1)
				return true;
			break;
		case 2:
			return true;
		case 3:
			if (g_nDualHead2 != -1)
				return true;
			break;
		}
	}
	return false;
}

bool IsSecondaryMonitorAvaliable()
{
    if (!IsMultimonitorAvaliable()) {
        if ((g_nNonDualHead != -1) || (g_nDualHead != -1))
            return true;
    }

		return false;
}

void HSH_EnterFullScreen2()
{
	if(IsMultimonitorAvaliable()){
		mfd_device.InitFirst();
		radar_device.InitFirst();

		mfd_device.InitSecond();
		radar_device.InitSecond();

		hsh_initialized=true;
		if(g_f3dtarget){
			CopyTargetImage(0,mfd_device.pDDSMechTexture);
		}
	}else if(IsSecondaryMonitorAvaliable()){
		mr_device.InitFirst();
		mr_device.InitSecond();
		hsh_mrdev_initialized=true;
	}
}

void HSH_DirectDrawRelease2()
{
	if(hsh_initialized){
		radar_device.Release();
		mfd_device.Release();
		if(g_f3dtarget){
			CopyTargetImage(2);
		}
		hsh_initialized=false;
	}else if(hsh_mrdev_initialized){
		mr_device.Release();
		hsh_mrdev_initialized=false;

	}
}
#define PI2F	6.283185307179F
const float MULFX=1024.0f/800.0f;

void MakeTorus(D3DTLVERTEX* Vertices,float cx,float cy,float r1,float r2,int seg,DWORD ci,DWORD co,float zi,float zo,float xi,float yi,float xo,float yo)
{
	for(int i=0;i<=seg;i++){
		Vertices[i*2+0] = D3DTLVERTEX(D3DVECTOR(  r1*cosf(-i*PI2F/seg)+cx+xi, r1*sinf(-i*PI2F/seg)+cy+yi,zi),1.0f,ci,0, i/(float)seg, 0.0f );
		Vertices[i*2+1] = D3DTLVERTEX(D3DVECTOR(  r2*cosf(-i*PI2F/seg)+cx+xo, r2*sinf(-i*PI2F/seg)+cy+yo,zo),1.0f,co,0, i/(float)seg, 1.0f );
	}
}

void MoveTorus(D3DTLVERTEX* Vertices,int seg,float offset,float off_z,int seg2,int part,
			   float x1,float y1,float x2,float y2)
{
	for(int i=0;i<=seg;i++){
		float newtu=((float)(seg-i)+offset)/(float)seg;
		D3DTLVERTEX& verti=Vertices[i*2+0];
		D3DTLVERTEX& verto=Vertices[i*2+1];
		
		verti.tu=newtu;
		verti.tv=1-off_z;
		verti.sx+=x1;
		verti.sy+=y1;
		verto.tu=newtu;
		verto.tv=1-off_z+1;
		verto.sx+=x2;
		verto.sy+=y2;
	}
}

void __cdecl DrawSwrling(LPDIRECT3DDEVICE7	pd3dDevice,LPDIRECTDRAWSURFACE7	pTexture,bool freload)
{
	const int seg=36;
	const int seg2=3;
	const int segvert=(seg+1)*2;
	static D3DTLVERTEX Vertices[seg2][segvert]; // Vertices for the cube
	static bool vertices_initialized=false;
	//int rcount,scount;//num rotation-direction segments, num straight-direction segments..
	static float off_z=0;
	if(freload){
		char temppath[MAX_PATH];
		sprintf(temppath,"%s\\hsh\\%s",AssetsDirectory1,"swirling.bmp");
		DrawBitmapFileToTexture(pTexture, temppath);
		off_z=0;
	}
	if(!vertices_initialized){
		float w=800.0f,h=600.0f,f=1.0f;
		LPDIRECTDRAWSURFACE7 RenderTarget;
		if(SUCCEEDED(pd3dDevice->GetRenderTarget(&RenderTarget))){
			DDSURFACEDESC2 desc2;
			desc2.dwSize=sizeof(desc2);
			if(SUCCEEDED(RenderTarget->GetSurfaceDesc(&desc2))){
				w=(float)desc2.dwWidth;
				h=(float)desc2.dwHeight;
				f=w/800.0f;
			}
		}

		MakeTorus(Vertices[0],w/2,h/2,200*f,510*f,seg,0xFFAAAAAA,0xFFFFFFFF,0.7f,1.0f,0,-80,0,0);
		MakeTorus(Vertices[1],w/2,h/2,100*f,200*f,seg,0xFF666666,0xFFAAAAAA,0.5f,0.7f,0,-200,0,-80);
		MakeTorus(Vertices[2],w/2,h/2,  0*f,100*f,seg,0xFF000000,0xFF666666,0.3f,0.5f,0,-500,0,-200);
		vertices_initialized=true;
	}else{
		//If initialized, keep changing texture coordinates.
		static float offset=0;
		static float off=0;
		float bb=sinf(off)*2;
		float aa=0;//cosf(off)*0.5f;
		MoveTorus(Vertices[0],seg,offset,off_z,seg2,1,aa*0.4f,bb*0.4f,0,0);
		MoveTorus(Vertices[1],seg,offset,off_z,seg2,2,aa*1.0f,bb*1.0f,aa*0.4f,bb*0.4f);
		MoveTorus(Vertices[2],seg,offset,off_z,seg2,3,aa*2.5f,bb*2.5f,aa*1.0f,bb*1.0f);
		offset+=0.3f;
		off+=0.01f;
		off_z+=0.03f;
		if(offset>seg)offset-=seg;
	}
	pd3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE,D3DSHADE_GOURAUD);
	pd3dDevice->SetTextureStageState(0,D3DTSS_ADDRESS,D3DTADDRESS_WRAP);
	//pd3dDevice->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_WRAP);
	pd3dDevice->SetTextureStageState(0,D3DTSS_MAGFILTER ,D3DTFG_LINEAR);
	pd3dDevice->SetTextureStageState(0,D3DTSS_MINFILTER ,D3DTFG_LINEAR);
	pd3dDevice->SetTexture(0,pTexture);
	pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices[2], (seg+1)*2/**seg2*/, NULL );
	pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices[1], (seg+1)*2/**seg2*/, NULL );
	pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices[0], (seg+1)*2/**seg2*/, NULL );
}


void __cdecl DrawGameEndScreen(LPDIRECT3DDEVICE7	pd3dDevice,LPDIRECTDRAWSURFACE7	pTexture,bool freload)
{
	static D3DTLVERTEX Vertices[4]; // Vertices for the cube
	static bool vertices_initialized=false;
	//int rcount,scount;//num rotation-direction segments, num straight-direction segments..
	static float off_z=0;
	if(freload){
		extern bool g_bCOOP; // COin OPeration
		char temppath[MAX_PATH];
        if (!g_bCOOP && (g_pfnCTCL_GetType && ((*g_pfnCTCL_GetType)() == _ECTCL_Game)))
		    sprintf(temppath,"%s\\hsh\\%s",AssetsDirectory1,"missionend.bmp");
        else
            sprintf(temppath,"%s\\hsh\\%s",AssetsDirectory1,"missionover.bmp");
		DrawBitmapFileToTexture(pTexture, temppath);
		off_z=0;
	}
	if(!vertices_initialized){
		float w=800.0f,h=600.0f,f=1.0f;
		LPDIRECTDRAWSURFACE7 RenderTarget;
		if(SUCCEEDED(pd3dDevice->GetRenderTarget(&RenderTarget))){
			DDSURFACEDESC2 desc2;
			desc2.dwSize=sizeof(desc2);
			if(SUCCEEDED(RenderTarget->GetSurfaceDesc(&desc2))){
				w=(float)desc2.dwWidth;
				h=(float)desc2.dwHeight;
				f=w/800.0f;
			}
		}
        static float z_pos = 0.999f;
        Vertices[0] = D3DTLVERTEX(D3DVECTOR( 0.0f, 0.0f, z_pos),1.0f,0xFFFFFFFF,0, 0.0f, 0.0f );
        Vertices[1] = D3DTLVERTEX(D3DVECTOR( (float)w, 0.0f, z_pos),1.0f,0xFFFFFFFF,0, 800.0f/1024.0f, 0.0f );
        Vertices[2] = D3DTLVERTEX(D3DVECTOR( 0.0f, (float)h, z_pos),1.0f,0xFFFFFFFF,0, 0.0f, 600.0f/1024.0f );
        Vertices[3] = D3DTLVERTEX(D3DVECTOR( (float)w, (float)h, z_pos),1.0f,0xFFFFFFFF,0, 800.0f/1024.0f, 600.0f/1024.0f );
		vertices_initialized=true;
	}else{
		//If initialized, keep changing texture coordinates.
	}
	pd3dDevice->SetTextureStageState(0,D3DTSS_COLOROP ,D3DTOP_MODULATE);
	pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG1 ,D3DTA_TEXTURE);
	pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG2 ,D3DTA_CURRENT);

	pd3dDevice->SetTextureStageState(0,D3DTSS_ALPHAOP  ,D3DTOP_SELECTARG1);
	pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG2 ,D3DTA_TEXTURE);
	pd3dDevice->SetTextureStageState(0,D3DTSS_COLORARG2 ,D3DTA_CURRENT);

	pd3dDevice->SetRenderState(D3DRENDERSTATE_SHADEMODE,D3DSHADE_GOURAUD);
	pd3dDevice->SetTextureStageState(0,D3DTSS_ADDRESS,D3DTADDRESS_WRAP);
	//pd3dDevice->SetTextureStageState(0,D3DTSS_ADDRESSV,D3DTADDRESS_WRAP);
	pd3dDevice->SetTextureStageState(0,D3DTSS_MAGFILTER ,D3DTFG_LINEAR);
	pd3dDevice->SetTextureStageState(0,D3DTSS_MINFILTER ,D3DTFG_LINEAR);
	pd3dDevice->SetTexture(0,pTexture);
	pd3dDevice->DrawPrimitive( D3DPT_TRIANGLESTRIP, D3DFVF_TLVERTEX , Vertices, 4, NULL );
}

