// MFC Gos.cpp : Defines the class behaviors for the application.
//

// Note:
// Unresolved Problems:
// Imagehlp.dll Not Found on Load from Double Click
// Wire only works on Scenes


#include "stdafx.h"
#include "MFC Gos.h"

#include "MainFrm.h"
#include "MFC GosDoc.h"
#include "MFC GosView.h"
#include <Gameos\Toolos.hpp>

HGOSHEAP client;

extern DWORD _stdcall RunGameOSLogic();

#define DEBUGPOINT(x) MessageBox(NULL,x,"Test Point",MB_OK)

#include <ElementRenderer\ElementRenderer.hpp>
#include <ElementRenderer\GroupElement.hpp>
#include <ElementRenderer\StateChange.hpp>
#include <ElementRenderer\CameraElement.hpp>
#include <ElementRenderer\PointCloudElement.hpp>
#include <ElementRenderer\LineCloudElement.hpp>
#include <ElementRenderer\ElementRenderer.hpp>
#include <ElementRenderer\GroupElement.hpp>
#include <ElementRenderer\StateChange.hpp>
#include <ElementRenderer\CameraElement.hpp>
#include <ElementRenderer\ShapeElement.hpp>
#include <ElementRenderer\ListElement.hpp>
#include <ElementRenderer\GridElement.hpp>
#include <ElementRenderer\SwitchElement.hpp>
#include <ElementRenderer\LODElement.hpp>

#include <gosFX\gosFX.hpp>
#include <gosFX\EffectLibrary.hpp>
#include <MLR\MLR.hpp>
#include <MFCPlatform\MFCPlatform.hpp>
#include <MLR\MLRPointCloud.hpp>
#include <MLR\MLRLineCloud.hpp>
#include <MLR\MLRPointLight.hpp>
#include <MLR\MLRLightMap.hpp>
#include "LightListDlg.h"

extern DWORD gCurrentHeapStackLevel; 

BumpAnime bumpAnime;
int animeCounter = 0;

//
// Global variables
//
const char* Command_Line=NULL;

int UpdateLevel=0;
ElementRenderer::GroupElement *Scene=NULL;
ElementRenderer::Element *ErfElement=NULL;
ElementRenderer::CameraElement *Camera=NULL;
ElementRenderer::StateChange *LightState=NULL;
CLightListDlg *LightDlg;

Stuff::Point3D Camera_Pivot(Stuff::Point3D::Identity);
Stuff::YawPitchRange Camera_Direction(0.0f, 0.0f, -10.0f);
Stuff::Vector2DOf<Stuff::Scalar> Camera_Shift(0.0f, 0.0f);
//Stuff::Point3D Camera_Loc(0.0f,100.0f,-100.0f),
Stuff::Point3D Camera_LookAt(0.0f,0.0f,0.0f);


//Bump Map Test 


ElementRenderer::StateChange *Camera_State=NULL;
Stuff::RGBAColor fogColor(0.3f, 0.3f, 0.3f, 1.0f);
bool Window3DOpen=false;

bool drawPointsYes = false;
bool drawNormalsYes = false;
MidLevelRenderer::DrawEffectInformation *drawEffectInfo[2];
unsigned Point_Count=MidLevelRenderer::Limits::Max_Number_Vertices_Per_Mesh;
Stuff::RGBAColor Color_Data[2][2*MidLevelRenderer::Limits::Max_Number_Vertices_Per_Mesh];

Stuff::MString *erf_texture_path,*erf_effects_path;
CList<Stuff::MString*, Stuff::MString*> m_pErf_Name_List;


#undef SHADOW_TEST

#ifdef SHADOW_TEST
MidLevelRenderer::MLRTexture *shadowTexture;
MidLevelRenderer::MLRShape *shadowShape;
MidLevelRenderer::DrawShapeInformation drawShapeInfo;
Stuff::LinearMatrix4D shadowMatrix;

extern void _stdcall End3DScene();
#endif

#define APPNAME "3dViewTest"

extern DWORD _stdcall RunGameOSLogic();
extern bool DebuggerActive;


/////////////////////////////////////////////////////////////////////////////
// CMFCGosApp

BEGIN_MESSAGE_MAP(CMFCGosApp, CWinApp)
//{{AFX_MSG_MAP(CMFCGosApp)
ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
ON_COMMAND(ID_OPTIONS_TEXTUREPATH, OnOptionsTexturepath)
ON_COMMAND(ID_VIEW_3DVIEWWINDOW, OnView3dviewwindow)
ON_UPDATE_COMMAND_UI(ID_VIEW_3DVIEWWINDOW, OnUpdateView3dviewwindow)
ON_COMMAND(ID_VIEW_UPDATEONIDLE, OnViewUpdateonidle)
ON_UPDATE_COMMAND_UI(ID_VIEW_UPDATEONIDLE, OnUpdateViewUpdateonidle)
ON_COMMAND(ID_WINDOWS_LIGHTLIST, OnWindowsLightlist)
ON_UPDATE_COMMAND_UI(ID_WINDOWS_LIGHTLIST, OnUpdateWindowsLightlist)
	//}}AFX_MSG_MAP
// Standard file based document commands
ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
ON_COMMAND(ID_FILE_OPEN,OnFileOpen)
ON_COMMAND(ID_VIEW_EXPANDALL, OnExpandAll)
ON_COMMAND(ID_VIEW_COLLAPSEALL, OnCollapseAll)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CMFCGosApp construction

CMFCGosApp::CMFCGosApp()
{
	GOSActive=false;
	DrawOnIdle=true;
	m_pFileSet_List.RemoveAll();
	m_phashErfNameMapping = NULL;
}

/////////////////////////////////////////////////////////////////////////////
// The one and only CMFCGosApp object

CMFCGosApp theApp;

/////////////////////////////////////////////////////////////////////////////
// CMFCGosApp initialization

BOOL CMFCGosApp::InitInstance()
{
	AfxEnableControlContainer();
		// Standard initialization
	
#ifdef _AFXDLL
	Enable3dControls();			// Call this when using MFC in a shared DLL
#else
	Enable3dControlsStatic();	// Call this when linking to MFC statically
#endif
	
	
	// Change the registry key under which our settings are stored.
	// jcem - SetRegistryKey(_T("Local AppWizard-Generated Applications"));
	
	LoadStdProfileSettings();  // Load standard INI file options (including MRU)
	
	// Register document templates

CString mutexstr;
mutexstr.LoadString(AFX_IDS_APP_TITLE);
	CreateMutex(NULL,TRUE,mutexstr);
if(ERROR_ALREADY_EXISTS==GetLastError())
{	
MessageBox(NULL,"Another Instance of this Application is Currently Running","Error...",MB_OK);
exit(1);
}	
	
	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CMFCGosDoc),
		RUNTIME_CLASS(CMainFrame),       // main SDI frame window
		RUNTIME_CLASS(CMFCGosView));
	AddDocTemplate(pDocTemplate);
	
	
	// Parse command line for standard shell commands, DDE, file open
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);
	
	// Dispatch commands specified on the command line
	if (!ProcessShellCommandNoLoad(cmdInfo))
		return FALSE;
	
	
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();
	
	
	
	
	Window3D = new ViewWnd3D;
	
	
	Window3D->Create(NULL,
		"3D View Window",
		WS_OVERLAPPED|WS_CAPTION,
		//|WS_MINIMIZEBOX|WS_SYSMENU,
		Window3D->rectDefault,
		//		m_pMainWnd,				//This Will make The render Window Stay ontop of the main window
		NULL,
		MAKEINTRESOURCE(IDR_RENDERMENU),
		NULL);
	
	CRect rct;
	rct.top=rct.left=0;
	rct.right=640;
	rct.bottom=480+18;
	
	
	Window3D->ShowWindow(SW_SHOW);
	Window3D->CalcWindowRect(&rct,CWnd::adjustOutside);
	Window3D->SetWindowPos(NULL,rct.left,rct.top,rct.Width(),rct.Height(),SWP_SHOWWINDOW|SWP_NOOWNERZORDER|SWP_NOMOVE);      
	Window3D->SetIcon(LoadIcon(IDI_ICON3D),TRUE);
	
	
	Command_Line = m_lpCmdLine;
	InitGameOS(  m_hInstance , Window3D->m_hWnd, m_lpCmdLine );
	//	client=gos_CreateMemoryHeap("PixelProHeap");
	//	gos_PushCurrentHeap(client);
	theApp.Window3D->GOSActive=true;
	theApp.Window3D->GOSInit=true;
	theApp.Window3D->Fix3DView();
	DrawScreen();
	GOSActive=true;
	
	
	LightDlg=new CLightListDlg;
	LightDlg->Create( CLightListDlg::IDD,m_pMainWnd);
	LightDlg->ShowWindow(SW_HIDE);
	
	// has to be initialized in InitializeGameEngine()
//	m_pstrErfNameMapping = new CMap<DWORD, DWORD, Stuff::MString*, Stuff::MString*>;
	
	//
	//-----------------------
	// Parse the command line
	//-----------------------
	//
	const char* space = strchr(Command_Line, ' ');
	if (!space || space == Command_Line)
	{
		//		Abort_Program("Need both ERF file and texture path");
		//		GetTexturePath();
	}	
	else
	{
		MString * tmp = new MString(Command_Line);
		m_pErf_Name_List.AddHead(tmp); 
		//		((LPCSTR)(erf_name))[space - Command_Line] = '\0';
		//		erf_name.SetAt(space - Command_Line],'\0');
		
		static_cast<char*>(*(m_pErf_Name_List.GetHead()))[space - Command_Line] = '\0';
		(*(theApp.m_phashErfNameMapping)).DeletePlugs();
		(*(theApp.m_phashErfNameMapping)).AddValue(new Stuff::PlugOf<MString *> (tmp), 0); // this is only a copy...
		while (*space == ' ')
			++space;
		if (!*space)
		{
			STOP(( "Need both ERF file and texture path" ));
		}
		else
		{
			*erf_texture_path = space;
		}
	}	
	
	
	
	// CG: The following block was inserted by the 'Document Registration' component.
	{
		// Enable DDE Execute open
		EnableShellOpen();
		RegisterShellFileTypes(TRUE);
		
		m_pMainWnd->DragAcceptFiles();
	}
	
	if (!ProcessShellCommandOnlyLoad(cmdInfo))
		return FALSE;
	
	
	return TRUE;
}


/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();
	
	// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA
	
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL
	
	// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
	// No message handlers
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()

// App command to run the dialog
void CMFCGosApp::OnAppAbout()
{
	CAboutDlg aboutDlg;
	aboutDlg.DoModal();
}

/////////////////////////////////////////////////////////////////////////////
// CMFCGosApp message handlers




BOOL CMFCGosApp::OnIdle(LONG lCount) 
{
	DWORD level = gCurrentHeapStackLevel; 
	
	if(DrawOnIdle || DebuggerActive)
	{
		DrawScreen();
		Verify(level == gCurrentHeapStackLevel);
		return 1;
	}
	else
	{
		Verify(level == gCurrentHeapStackLevel);
		return CWinApp::OnIdle(lCount);
	}
}

int CMFCGosApp::ExitInstance() 
{
	ExitGameOS();	
	if(Window3D)
	{
		//delete Window3D;	
		Window3D=NULL;	
	}
	return CWinApp::ExitInstance();
}


void _stdcall InitializeGameEngine()
{
	//
	//---------------------
	// Initialize libraries
	//---------------------
	//
	Stuff::InitializeClasses();
	MidLevelRenderer::InitializeClasses(NULL, 8192, 1024*64);
	
	gosFX::InitializeClasses();
	ElementRenderer::InitializeClasses();
	if (!theApp.m_phashErfNameMapping)
	{
	//	BYTE * memory = new BYTE[sizeof(CMap<DWORD, DWORD, Stuff::MString*, Stuff::MString*>)];
		//theApp.m_pstrErfNameMapping = new(memory) (CMap<DWORD, DWORD, Stuff::MString*, Stuff::MString*>);
		theApp.m_phashErfNameMapping =	new Stuff::HashOf<Stuff::PlugOf<Stuff::MString *>*,DWORD>(67, NULL, true);
	}
	while (m_pErf_Name_List.GetCount() && m_pErf_Name_List.GetHead()) 
		{Unregister_Object(m_pErf_Name_List.GetHead()); delete m_pErf_Name_List.GetHead(); m_pErf_Name_List.RemoveHead();}
	(*(theApp.m_phashErfNameMapping)).DeletePlugs();
	m_pErf_Name_List.AddHead(new Stuff::MString);
	Register_Object(m_pErf_Name_List.GetHead());
	(*(theApp.m_phashErfNameMapping)).AddValue(new Stuff::PlugOf<MString *> (m_pErf_Name_List.GetHead()), 0);
	erf_texture_path = new Stuff::MString;
	Register_Object(erf_texture_path);
	erf_effects_path = new Stuff::MString;
	Register_Object(erf_effects_path);
	
	//
	//---------------------
	// Build the scene root
	//---------------------
	//
	theApp.GetTexturePath();
	theApp.GetEffectsPath();
	
	
	Scene = new ElementRenderer::GroupElement;
	Register_Object(Scene);
	Scene->SetRootMode();
	Scene->LockBounds();
	
	LightState = new ElementRenderer::StateChange;
	Register_Object(LightState);
	for(int li=0;li<MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive;li++)
		LightState->m_lights[li]=NULL;
	Scene->AdoptStateChange(LightState);
	
	//
	//------------------------
	// Set up the texture pool
	//------------------------
	//
	if(erf_texture_path->GetLength())
	{
		gos_PushCurrentHeap(MidLevelRenderer::TexturePoolHeap);
		MidLevelRenderer::TGAFilePool *pool =
			new MidLevelRenderer::TGAFilePool(*erf_texture_path, "textures.hint");
		Register_Object(pool);
		MidLevelRenderer::MLRTexturePool::Instance = new MidLevelRenderer::MLRTexturePool(pool);
		Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
		Register_Object(MidLevelRenderer::MLRTexturePool::Instance);
		gos_PopCurrentHeap();
		
#if 0
		Stuff::MString effects_name = *erf_texture_path;
		int content_root_length = effects_name.GetLength() - 9;
		Verify(!_stricmp(&((char*)effects_name)[content_root_length], "Textures\\"));
		((char*)effects_name)[content_root_length] = '\0';
		effects_name.SetLength(content_root_length);
		effects_name += "Effects\\mw.effects";
		
		Stuff::FileStream *stream = Stuff::FileStream::MakeFileStream(effects_name);
		Register_Object(stream);
		gosFX::EffectLibrary::Instance = new gosFX::EffectLibrary;
		Register_Object(gosFX::EffectLibrary::Instance);
		gosFX::EffectLibrary::Instance->Load(stream);
		Unregister_Object(stream);
		delete stream;
#endif
	}
	else
	{
		// fatal warning 
	}
	
	//
	//----------------------------------------------
	// Load the .ERF file and attach it to the scene
	//----------------------------------------------
	//
	//if(erf_name->GetLength())
/*	if (erf_name)
	{
    theApp.m_perf_file =  new Stuff::FileStream(*erf_name);

		ErfElement =
			ElementRenderer::Element::Create(
			theApp.m_perf_file,
			ElementRenderer::ReadERFVersion(theApp.m_perf_file)
			);
		Scene->AttachChild(ErfElement);
	}*/
	
	//---------------
	// Build a camera
	//---------------
	//
	gos_PushCurrentHeap(ElementRenderer::g_Heap);
	Camera_State = new ElementRenderer::StateChange();
	Register_Object(Camera_State);
	Camera_State->EnableBackfaceCulling();
	Camera_State->EnableDithering();
	Camera_State->EnablePerspectiveCorrection();
	Camera_State->EnableZBufferWrite();
	Camera_State->EnableZBufferCompare();
	Camera_State->SetFogColor(fogColor);
	Camera_State->SetFogMode(ElementRenderer::StateChange::DisableFogMode);
	Camera = new ElementRenderer::CameraElement(Camera_State);
	Register_Object(Camera);
	Scene->AttachChild(Camera);
	Camera->SetPerspective(1.0f, 1000.0f, Stuff::Pi_Over_3);
 	Camera->SetViewport(1.0f, 1.0f, 0.0f, 0.0f);
	Camera->SetScene(Scene);
	Stuff::LinearMatrix4D origin;
	origin.BuildRotation(
		Stuff::EulerAngles(Camera_Direction.pitch, Camera_Direction.yaw, 0.0f)
		);
	origin.BuildTranslation(Stuff::Point3D(Camera_Direction));
	Camera->SetLocalToParent(origin);


	CString strWindowTitle;
	strWindowTitle.Format("%s = %f", "Camera Distance", Camera_Direction.range);
	theApp.Window3D->SetWindowText((LPCSTR)strWindowTitle);
	
	gos_PopCurrentHeap();
	//	Camera->SetFogColor(fogColor);
	
#if 0
	//Make a Point Cloud
	drawEffectInfo = new MidLevelRenderer::DrawEffectInformation;
	Register_Pointer(drawEffectInfo);
	drawEffectInfo->effect = new MidLevelRenderer::MLRPointCloud(Point_Count, 4);
	Register_Object(drawEffectInfo->effect);
	
	drawEffectInfo->clippingFlags.SetClippingState(0x3f);
	drawEffectInfo->effectToWorld = NULL;
	drawEffectInfo->effect->TurnAllOn();
	drawEffectInfo->state.SetFogMode(MidLevelRenderer::MLRState::DisableFogMode);
	drawEffectInfo->state.SetZBufferWriteOff();
	drawEffectInfo->state.SetZBufferCompareOff();
	
	unsigned i;
	for (i=0; i<MidLevelRenderer::Limits::Max_Number_Vertices_Per_Mesh; ++i)
	{
		Color_Data[i] = Stuff::RGBAColor(
			0.95f + Stuff::Random::GetFraction()*0.05f, 
			0.0f, 
			0.0f, 
			1.0f
			);
	}
#endif
	
	//Make a Point Cloud
	gos_PushCurrentHeap(MidLevelRenderer::EffectHeap);
	drawEffectInfo[0] = new MidLevelRenderer::DrawEffectInformation;
	Register_Pointer(drawEffectInfo[0]);
	drawEffectInfo[0]->effect = new MidLevelRenderer::MLRPointCloud(Point_Count, 4);
	Register_Object(drawEffectInfo[0]->effect);
	gos_PopCurrentHeap();
	
	drawEffectInfo[0]->clippingFlags.SetClippingState(0x3f);
	drawEffectInfo[0]->effectToWorld = NULL;
	drawEffectInfo[0]->effect->TurnAllOn();
	
	//	drawEffectInfo[0]->state.SetFogMode(MidLevelRenderer::MLRState::DisableFogMode);
	drawEffectInfo[0]->state.SetFogMode(0);
	drawEffectInfo[0]->state.SetZBufferWriteOff();
	drawEffectInfo[0]->state.SetZBufferCompareOff();
	
	drawEffectInfo[0]->state.SetPriority(15);
	
	unsigned i;
	for (i=0; i<MidLevelRenderer::Limits::Max_Number_Vertices_Per_Mesh; ++i)
	{
		Color_Data[0][i] = Stuff::RGBAColor(
			0.95f + Stuff::Random::GetFraction()*0.05f, 
			0.0f, 
			0.0f, 
			1.0f
			);
	}
	
	//Make a Line Cloud
	gos_PushCurrentHeap(MidLevelRenderer::EffectHeap);
	drawEffectInfo[1] = new MidLevelRenderer::DrawEffectInformation;
	Register_Pointer(drawEffectInfo[1]);
	drawEffectInfo[1]->effect = new MidLevelRenderer::MLRLineCloud(Point_Count, 4);
	Register_Object(drawEffectInfo[1]->effect);
	gos_PopCurrentHeap();
	
	drawEffectInfo[1]->clippingFlags.SetClippingState(0x3f);
	drawEffectInfo[1]->effectToWorld = NULL;
	drawEffectInfo[1]->effect->TurnAllOn();
	
	//	drawEffectInfo[1]->state.SetFogMode(MidLevelRenderer::MLRState::DisableFogMode);
	drawEffectInfo[1]->state.SetFogMode(0);
	drawEffectInfo[1]->state.SetZBufferWriteOff();
	drawEffectInfo[1]->state.SetZBufferCompareOn();
	drawEffectInfo[1]->state.SetFilterMode(MidLevelRenderer::MLRState::BiLinearFilterMode);
	
	drawEffectInfo[1]->state.SetPriority(15);
	
	for (i=0; i<MidLevelRenderer::Limits::Max_Number_Vertices_Per_Mesh; ++i)
	{
		Color_Data[1][2*i] = Stuff::RGBAColor(
			0.0f, 
			0.9f,
			0.0f, 
			1.0f
			);
	}
	//
	//-----------------------------------------------------
	// Sync the matrices of the scene and load the textures
	//-----------------------------------------------------
	//
	Scene->Sync();

#ifdef SHADOW_TEST
	gos_PushCurrentHeap(MidLevelRenderer::LightsHeap);
	DWORD hints = gosHint_DisableMipmap | gosHint_DontShrink;
	shadowTexture = MLRTexturePool::Instance->Add("Shadow Test", gos_Texture_Keyed, 256, (gos_TextureHints)hints);

	MidLevelRenderer::MLR_I_TMesh *shadowMesh = new MidLevelRenderer::MLR_I_TMesh;
	Register_Object(shadowMesh);
	shadowMesh->AttachReference();
	
	shadowMesh->dataStore->coords.SetLength(4);
	shadowMesh->dataStore->coords[0] = Point3D(-5.0f, 0.0f, 0.0f);
	shadowMesh->dataStore->coords[1] = Point3D(-5.0f, 0.0f, 10.0f);
	shadowMesh->dataStore->coords[2] = Point3D(5.0f, 0.0f, 10.0f);
	shadowMesh->dataStore->coords[3] = Point3D(5.0f, 0.0f, 0.0f);
	shadowMesh->SetCoordData(shadowMesh->dataStore->coords.GetData(), 4);

	shadowMesh->dataStore->texCoords.SetLength(4);
	shadowMesh->dataStore->texCoords[0] = Vector2DScalar(0.0f, 0.0f);
	shadowMesh->dataStore->texCoords[1] = Vector2DScalar(0.0f, 1.0f);
	shadowMesh->dataStore->texCoords[2] = Vector2DScalar(1.0f, 1.0f);
	shadowMesh->dataStore->texCoords[3] = Vector2DScalar(1.0f, 0.0f);
	shadowMesh->SetTexCoordData(shadowMesh->dataStore->texCoords.GetData(), 4);

	shadowMesh->dataStore->index.SetLength(6);
	shadowMesh->dataStore->index[0] = 0;
	shadowMesh->dataStore->index[1] = 1;
	shadowMesh->dataStore->index[2] = 2;
	shadowMesh->dataStore->index[3] = 0;
	shadowMesh->dataStore->index[4] = 2;
	shadowMesh->dataStore->index[5] = 3;
	shadowMesh->SetIndexData(shadowMesh->dataStore->index.GetData(), 6);
	
	shadowMesh->SetSubprimitiveLengths(NULL, 2);

	MLRState state;
	state.SetTextureHandle(shadowTexture->GetTextureHandle());
	state.SetZBufferCompareOn();

	shadowMesh->SetReferenceState(state);
	gos_PopCurrentHeap();

	gos_PushCurrentHeap(MidLevelRenderer::ShapesHeap);
	shadowShape = new MidLevelRenderer::MLRShape(1);
	Register_Object(shadowShape);

	shadowShape->Add(shadowMesh);

	shadowMatrix = Stuff::LinearMatrix4D::Identity;
	shadowMatrix.BuildTranslation(Point3D(0.0f, -10.0f, 5.0));

	drawShapeInfo.shape = shadowShape;
	drawShapeInfo.nrOfActiveLights = 0;
	drawShapeInfo.clippingFlags.SetClippingState(0x3f);
	drawShapeInfo.shapeToWorld = &shadowMatrix;
	drawShapeInfo.worldToShape = &shadowMatrix;
	drawShapeInfo.paintMeColor = &RGBAColor::White;
	
	gos_PopCurrentHeap();
#endif
	
	MidLevelRenderer::MLRTexturePool::Instance->LoadImages();
}

#ifdef SHADOW_TEST
void 
	TraversErfBranch(ElementRenderer::Element *elmt)
{
	if(elmt->GetClassID() == ElementRenderer::CameraElementClassID)
	{
		return;
	}
	
	switch(elmt->GetClassID())
	{
		case ElementRenderer::GroupElementClassID:
		{	
			ElementRenderer::GroupElement *group = Cast_Pointer(ElementRenderer::GroupElement *, elmt);
			
			Stuff::ChainIteratorOf<ElementRenderer::Element*> *children = group->MakeIterator();
			Register_Object(children);
			
			ElementRenderer::Element *child = NULL;
			while ((child = children->ReadAndNext()) != NULL)
			{
				TraversErfBranch( child);
			}
			Unregister_Object(children);
			delete children;
		}
		break;
			
		case ElementRenderer::ListElementClassID:
		{
			ElementRenderer::ListElement *group = Cast_Pointer(ElementRenderer::ListElement *, elmt);
			
			for(int i=0;i<group->GetActiveCount();i++)
			{
				TraversErfBranch(group->GetIndexedElement(i));
			}				
		}
		break;
		case ElementRenderer::GridElementClassID:
		{
			ElementRenderer::GridElement *group = Cast_Pointer(ElementRenderer::GridElement *, elmt);
			
			unsigned xSize, zSize;
			group->GetSize(&xSize, &zSize);
			for(int i=0;i<zSize;i++)
				for(int j=0;j<xSize;j++)
				{
					TraversErfBranch( group->GetIndexedElement(i, j));
				}				
		}
		break;
		case ElementRenderer::LODElementClassID:
		{
			ElementRenderer::ListElement *group = Cast_Pointer(ElementRenderer::ListElement *, elmt);
			
			for(int i=0;i<group->GetActiveCount();i++)
			{
				TraversErfBranch(group->GetIndexedElement(i));
			}				
		}
		break;
		case ElementRenderer::PointCloudElementClassID:
		{
		}
		break;
		case ElementRenderer::ScalableShapeElementClassID:
		{
			ElementRenderer::ShapeElement *group = Cast_Pointer(ElementRenderer::ShapeElement *, elmt);
			MidLevelRenderer::MLRShape *shape=group->GetMLRShape();	

			UnitVector3D uvec;
			uvec.Normalize(UnitVector3D(0.0f, -1.0f, 1.0f));
			shape->DrawMyShadow(shadowMatrix, uvec);
		}
		break;
		case ElementRenderer::ScreenQuadsElementClassID:
			{
			}
			break;
			
		case ElementRenderer::ShapeElementClassID:
		{
			ElementRenderer::ShapeElement *group = Cast_Pointer(ElementRenderer::ShapeElement *, elmt);
			MidLevelRenderer::MLRShape *shape = group->GetMLRShape();	

			UnitVector3D uvec;
			uvec.Normalize(UnitVector3D(0.0f, -1.0f, 1.0f));
			shape->DrawMyShadow(shadowMatrix, uvec);
		}
		break;
		case ElementRenderer::SwitchElementClassID:
		{
			ElementRenderer::ListElement *group = Cast_Pointer(ElementRenderer::ListElement *, elmt);
			
			for(int i=0;i<group->GetActiveCount();i++)
			{
				TraversErfBranch(group->GetIndexedElement(i));
			}				
		}
		break;
		case ElementRenderer::TriangleCloudElementClassID:
		{
		}
		break;
	}
}
#endif


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void _stdcall DoGameLogic()
{
	DWORD level = gCurrentHeapStackLevel;
	
	//
	//-----------------------------------------------
	// Read the keyboard to see how to set the switch
	//-----------------------------------------------
	//
	if(!Camera_State)
	{
		Verify(gCurrentHeapStackLevel == level);
		return;
	}
	
	Check_Object(Camera_State);
	MidLevelRenderer::MLRState mlr_state = Camera_State->GetMLRState();
	
	//
	//---------------
	// Read the mouse
	//---------------
	//
	int
		x_delta,
		y_delta;
	Stuff::Scalar 
		n_xdelta,
		n_ydelta;
	
	DWORD
		buttons;
	gos_GetMouseInfo(NULL, NULL, &x_delta, &y_delta, NULL, &buttons);
	Stuff::Scalar
		x_speed = x_delta * 0.01f,
		y_speed = y_delta * 0.01f;
	
	n_xdelta=(Stuff::Scalar)x_delta/Environment.screenWidth;
	n_ydelta=(Stuff::Scalar)y_delta/Environment.screenHeight;
	
	//
	//------------------------------------------------------
	// If the left Ctrl button is held down, move the camera
	//------------------------------------------------------
	//
	gosEnum_KeyStatus status = gos_GetKeyStatus(KEY_LCONTROL);
	if (status != KEY_FREE && status != KEY_RELEASED)
	{
		Camera_Direction.pitch += y_speed;
		Camera_Direction.yaw -= x_speed;
		if(theApp.Window3D)
			theApp.Window3D->SetCapture();
		
	}
	
	//
	//------------------------------------------------------
	// If the left Shift button is held down, pan the camera
	//------------------------------------------------------
	//
	status = gos_GetKeyStatus(KEY_LSHIFT);
	if (status != KEY_FREE && status != KEY_RELEASED)
	{
		Camera_Shift.x += n_xdelta*Camera_Direction.range;
		Camera_Shift.y += n_ydelta*Camera_Direction.range;
		if(theApp.Window3D)
			theApp.Window3D->SetCapture();

	}
	
	//
	//-----------------------------------------------------
	// If the left Alt button is held down, zoom the camera
	//-----------------------------------------------------
	//
	status = gos_GetKeyStatus(KEY_LMENU);
	if (status != KEY_FREE && status != KEY_RELEASED)
	{
		Camera_Direction.range *=(Stuff::Scalar)pow(2, n_ydelta);
		if(theApp.Window3D)
			theApp.Window3D->SetCapture();

	}

	
	Stuff::LinearMatrix4D ZTrans(true);
	Stuff::LinearMatrix4D LookAtTrans(true);
	Stuff::LinearMatrix4D RotMat(true);
	Stuff::LinearMatrix4D PanMat(true);
	Stuff::LinearMatrix4D TempMat1(true),TempMat2(true),CameraMatrix(true);
	
	ZTrans.BuildTranslation(Stuff::Point3D(0.0f,0.0f,-Camera_Direction.range));
	RotMat.BuildRotation(Stuff::EulerAngles(Camera_Direction.pitch,Camera_Direction.yaw , 0.0f));
	LookAtTrans.BuildTranslation(Camera_LookAt);
	PanMat.BuildTranslation(Stuff::Point3D(Camera_Shift.x,Camera_Shift.y,0.0f));

	TempMat1.Multiply(PanMat,ZTrans);
	TempMat2.Multiply(TempMat1,RotMat);
	CameraMatrix.Multiply(TempMat2,LookAtTrans);

	Camera->SetLocalToParent(CameraMatrix);
	CString strWindowTitle;
	static Stuff::Scalar old_camera_range = 0.0f;
	if (old_camera_range != Camera_Direction.range)
	{
		strWindowTitle.Format("%s = %f", "Camera Distance", Camera_Direction.range);
		theApp.Window3D->SetWindowText((LPCSTR)strWindowTitle);
		old_camera_range = Camera_Direction.range;
	}

	
	//
	//-------------------------------------------------------
	// Now that we have moved everything, update the matrices
	//-------------------------------------------------------
	//
	Camera->Sync();
		
	MidLevelRenderer::MLRTexturePool::Instance->LoadImages();
	Verify(gCurrentHeapStackLevel == level);

#ifdef SHADOW_TEST
	MidLevelRenderer::MLRState dState;

	Camera->GetClipper()->StartDraw(
		Stuff::LinearMatrix4D::Identity,
		Stuff::LinearMatrix4D::Identity,
		Stuff::RGBAColor::White,
		&Stuff::RGBAColor::White,
		dState,
		NULL
	);

	gos_StartRenderToTexture( shadowTexture->GetImage()->GetHandle() );
	TraversErfBranch(Scene);
	gos_EndRenderToTexture();

	End3DScene();
#endif
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void _stdcall UpdateDisplay()
{
	DWORD level = gCurrentHeapStackLevel;
	
 	Camera->SetViewport(1.0f, 1.0f, 0.0f, 0.0f);
	Camera->DrawScene();

	MidLevelRenderer::MLRState dState;
	Camera->GetClipper()->ResetSorter(dState);
	
	if(drawPointsYes == true)
	{
		Camera->GetClipper()->DrawEffect(drawEffectInfo[0]);
	}
	if(drawNormalsYes == true)
	{
		Camera->GetClipper()->DrawEffect(drawEffectInfo[1]);
	}
	
#ifdef SHADOW_TEST
	Camera->GetClipper()->DrawShape(&drawShapeInfo);
#endif

	if(drawPointsYes == true || drawNormalsYes == true)
	{
		Camera->GetClipper()->RenderNow();
	}

	MLRTexture *tex = NULL;
	if(bumpAnime.water>0 && (tex = (*MidLevelRenderer::MLRTexturePool::Instance)[bumpAnime.water])!=NULL)
	{
		Stuff::AffineMatrix4D *texture_matrix = tex->GetTextureMatrix();
		texture_matrix->entries[3] = bumpAnime.wu*animeCounter;
		texture_matrix->entries[7] = bumpAnime.wv*animeCounter;
	}
	tex = NULL;
	if(bumpAnime.bump>0 && (tex = (*MidLevelRenderer::MLRTexturePool::Instance)[bumpAnime.bump])!=NULL)
	{
		Stuff::AffineMatrix4D *texture_matrix = tex->GetTextureMatrix();
		texture_matrix->entries[3] = bumpAnime.bu*animeCounter;
		texture_matrix->entries[7] = bumpAnime.bv*animeCounter;
	}
	tex = NULL;
	if(bumpAnime.normal>0 && (tex = (*MidLevelRenderer::MLRTexturePool::Instance)[bumpAnime.normal])!=NULL)
	{
		Stuff::AffineMatrix4D *texture_matrix = tex->GetTextureMatrix();
		texture_matrix->entries[3] = bumpAnime.nu*animeCounter;
		texture_matrix->entries[7] = bumpAnime.nv*animeCounter;
	}

	animeCounter++;

	static float lasttime=(float)gos_GetElapsedTime();
	float thistime=(float)gos_GetElapsedTime();
	float timepast=(thistime-lasttime);
	YawPitchRoll ypr(thistime*Stuff::Pi_Over_2/5.0f,Stuff::Pi_Over_4,0.0f);
	LinearMatrix4D mat(ypr);
	Vector3D vect(0,0,1),v2;
	v2.Multiply(vect,mat);
	v2.Normalize(v2);
	MLR_BumpyWater::SetSunLight(UnitVector3D(v2));
	//MLR_Water::SetSunLight(UnitVector3D(v2));

	lasttime=thistime;
}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
void _stdcall TerminateGameEngine()
{
	while (m_pErf_Name_List.GetCount() && m_pErf_Name_List.GetHead()) 
		{Unregister_Object(m_pErf_Name_List.GetHead()); delete m_pErf_Name_List.GetHead(); m_pErf_Name_List.RemoveHead();}
	(*(theApp.m_phashErfNameMapping)).DeletePlugs();
	delete theApp.m_phashErfNameMapping;
	Unregister_Object(erf_texture_path);
	delete erf_texture_path;
	
	Unregister_Object(drawEffectInfo[0]->effect);
	delete drawEffectInfo[0]->effect;
	Unregister_Pointer(drawEffectInfo[0]);
	delete drawEffectInfo[0];
	
	Unregister_Object(drawEffectInfo[1]->effect);
	delete drawEffectInfo[1]->effect;
	Unregister_Pointer(drawEffectInfo[1]);
	delete drawEffectInfo[1];
	
	//
	//-------------------
	// Turn off libraries
	//-------------------
	//
	ElementRenderer::TerminateClasses();
	gosFX::TerminateClasses();
	MidLevelRenderer::TerminateClasses();
	Stuff::TerminateClasses();
	
	Camera_State=NULL;
}


//
// Setup the GameOS structure
//
void __stdcall GetGameOSEnvironment( char* CommandLine )
{
	//	Command_Line=CommandLine;
	Environment.applicationName		= "ERFViewer";
	Environment.screenWidth				= 640;
	Environment.screenHeight			= 480;
	Environment.fullScreen				= FALSE;
	Environment.bitDepth					= 16;
	Environment.debugLog					= "ErfViewer.txt";
	Environment.spew						= "";			//"GameOS*";
	
	Environment.UpdateRenderers		= UpdateDisplay;
	Environment.DoGameLogic				= DoGameLogic;
	Environment.InitializeGameEngine	= InitializeGameEngine;
	Environment.TerminateGameEngine	= TerminateGameEngine;
	
	Environment.Renderer					= 0;
	Environment.FullScreenDevice		= 0;
	
	Environment.AntiAlias				= 0;			// true/false - Enable full screen antialiasing
	
	//
	// Texture infomation
	//
	Environment.Texture_S_256			= 13;
	Environment.Texture_S_128			= 12;
	Environment.Texture_S_64			= 1;
	Environment.Texture_S_32			= 1;
	Environment.Texture_S_16			= 1;
	
	Environment.Texture_K_256			= 1;
	Environment.Texture_K_128			= 1;
	Environment.Texture_K_64			= 1;
	Environment.Texture_K_32			= 1;
	Environment.Texture_K_16			= 1;
	
	Environment.Texture_A_256			= 1;
	Environment.Texture_A_128			= 1;
	Environment.Texture_A_64			= 1;
	Environment.Texture_A_32			= 1;
	Environment.Texture_A_16			= 1;

	Environment.dontClearRegistry		= true;
}


void __stdcall ILFree(LPITEMIDLIST pidl); 


void CMFCGosApp::OnOptionsTexturepath() 
{
	NewTexturePath();
	MessageBox(NULL,"These changes will not take effect until the program is restarted","Warning!!!",MB_OK|MB_ICONEXCLAMATION);   	
}


void __stdcall ILFree(LPITEMIDLIST pidl) 
{ 
	LPMALLOC pMalloc; 
	
    if (pidl) 
    { 
#ifdef DEBUG 
		UINT cbSize = ILGetSize(pidl); 
		VALIDATE_PIDL(pidl); 
		
		// Fill the memory with some bad value... 
		_fmemset(pidl, 0xE5, cbSize); 
		
		// If large enough try to save the call return address of who 
		// freed us in the 3-6 byte of the structure. 
		if (cbSize >= 6) 
			*((UINT*)((LPSTR)pidl + 2)) =  *(((UINT*)&pidl) - 1); 
		
#endif 
		SHGetMalloc(&pMalloc); 
		pMalloc->Free( pidl); 
		pMalloc->Release(); 
		
    } 
} 

void CMFCGosApp::GetTexturePath()
{
	
	TexturePath=GetProfileString("ERF Viewer MFC","TexturePath");
	if(TexturePath.GetLength()==0) 
	{
		NewTexturePath();
	} // end if string in Registry
	
	
	*erf_texture_path =  Stuff::MString((LPCSTR)TexturePath);
	if(erf_texture_path->GetLength())
	{
		if(MidLevelRenderer::MLRTexturePool::Instance)
		{
			MidLevelRenderer::TGAFilePool *pool =
				new MidLevelRenderer::TGAFilePool(*erf_texture_path, "textures.hint");
			Register_Object(pool);
			MidLevelRenderer::MLRTexturePool::Instance = new MidLevelRenderer::MLRTexturePool(pool);
			Check_Object(MidLevelRenderer::MLRTexturePool::Instance);
			Register_Object(MidLevelRenderer::MLRTexturePool::Instance);
		}
	}
	
	
}

void CMFCGosApp::NewTexturePath()
{
	char pname[MAX_PATH];
	BROWSEINFO bi; 
	if(m_pMainWnd==NULL)
		bi.hwndOwner =NULL;
	else
		bi.hwndOwner = m_pMainWnd->m_hWnd; 
	
	bi.pidlRoot = NULL; 
	bi.pszDisplayName = NULL; 
	bi.lpszTitle = "Choose Texture Path..."; 
	bi.ulFlags = BIF_RETURNONLYFSDIRS; 
	bi.lpfn = NULL; 
	bi.lParam = (LPARAM)this; 
	
	LPITEMIDLIST pidl = SHBrowseForFolder(&bi); 
	
	if (SHGetPathFromIDList(pidl,pname))  
	{
		TexturePath=pname;
		TexturePath+="\\";
		
		
		WriteProfileString("ERF Viewer MFC","TexturePath",TexturePath);
	}
	
	if (bi.pidlRoot) 
	{ 
		ILFree( const_cast< ITEMIDLIST* >( bi.pidlRoot ) );
	} 
	
}

void CMFCGosApp::GetEffectsPath()
{
	
	EffectsPath=GetProfileString("ERF Viewer MFC","EffectsPath");
	if(EffectsPath.GetLength()==0) 
	{
		NewEffectsPath();
	} // end if string in Registry
	
	
	*erf_effects_path =  Stuff::MString((LPCSTR)EffectsPath);
	if(erf_effects_path->GetLength())
	{
	}
	
	
}

void CMFCGosApp::NewEffectsPath()
{
	char pname[MAX_PATH];
	BROWSEINFO bi; 
	if(m_pMainWnd==NULL)
		bi.hwndOwner =NULL;
	else
		bi.hwndOwner = m_pMainWnd->m_hWnd; 
	
	bi.pidlRoot = NULL; 
	bi.pszDisplayName = NULL; 
	bi.lpszTitle = "Choose effects Path..."; 
	bi.ulFlags = BIF_RETURNONLYFSDIRS; 
	bi.lpfn = NULL; 
	bi.lParam = (LPARAM)this; 
	
	LPITEMIDLIST pidl = SHBrowseForFolder(&bi); 
	
	if (SHGetPathFromIDList(pidl,pname))  
	{
		EffectsPath=pname;
		EffectsPath+="\\";
		
		
		WriteProfileString("ERF Viewer MFC","EffectsPath",EffectsPath);
	}
	
	if (bi.pidlRoot) 
	{ 
		ILFree( const_cast< ITEMIDLIST* >( bi.pidlRoot ) );
	} 
	
}

BOOL CMFCGosApp::ProcessShellCommandNoLoad(CCommandLineInfo &rCmdInfo)
{
	BOOL bResult = TRUE;
	switch (rCmdInfo.m_nShellCommand)
	{
	case CCommandLineInfo::FileNew:
	case CCommandLineInfo::FileOpen:
		if (!AfxGetApp()->OnCmdMsg(ID_FILE_NEW, 0, NULL, NULL))
			OnFileNew();
		if (m_pMainWnd == NULL)
			bResult = FALSE;
		break;
		
	case CCommandLineInfo::FilePrintTo:
	case CCommandLineInfo::FilePrint:
		m_nCmdShow = SW_HIDE;
		ASSERT(m_pCmdInfo == NULL);
		OpenDocumentFile(rCmdInfo.m_strFileName);
		m_pCmdInfo = &rCmdInfo;
		m_pMainWnd->SendMessage(WM_COMMAND, ID_FILE_PRINT_DIRECT);
		m_pCmdInfo = NULL;
		bResult = FALSE;
		break;
		
		// If we're doing DDE, hide ourselves
		
	case CCommandLineInfo::FileDDE:
		m_pCmdInfo = (CCommandLineInfo*)m_nCmdShow;
		m_nCmdShow = SW_HIDE;
		break;
		
		// If we've been asked to unregister, unregister and then terminate
	case CCommandLineInfo::AppUnregister:
		{
			UnregisterShellFileTypes();
			BOOL bUnregistered = Unregister();
			
			// if you specify /EMBEDDED, we won't make an success/failure box
			// this use of /EMBEDDED is not related to OLE
			
			if (!rCmdInfo.m_bRunEmbedded)
			{
				if (bUnregistered)
					AfxMessageBox(AFX_IDP_UNREG_DONE);
				else
					AfxMessageBox(AFX_IDP_UNREG_FAILURE);
			}
			bResult = FALSE;    // that's all we do
			
			// If nobody is using it already, we can use it.
			// We'll flag that we're unregistering and not save our state
			// on the way out. This new object gets deleted by the
			// app object destructor.
			
			if (m_pCmdInfo == NULL)
			{
				m_pCmdInfo = new CCommandLineInfo;
				m_pCmdInfo->m_nShellCommand = CCommandLineInfo::AppUnregister;
			}
		}
		break;
	}
	return bResult;
}

BOOL CMFCGosApp::ProcessShellCommandOnlyLoad(CCommandLineInfo &rCmdInfo)
{
	BOOL bResult = TRUE;
	switch (rCmdInfo.m_nShellCommand)
	{
		// If we've been asked to open a file, call OpenDocumentFile()
		
	case CCommandLineInfo::FileOpen:
		if (!OpenDocumentFile(rCmdInfo.m_strFileName))
			bResult = FALSE;
		break;
		
	}
	return bResult;
}

void CMFCGosApp::OnView3dviewwindow() 
{
	// TODO: Add your command handler code here
	if(Window3D)
		Window3D->ShowWindow(Window3D->IsWindowVisible( )?SW_HIDE:SW_SHOW);
}

void CMFCGosApp::OnUpdateView3dviewwindow(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	if(Window3D)
		pCmdUI->SetCheck(	Window3D->IsWindowVisible( )); 
}

void CMFCGosApp::GosShutDown()
{
	
	theApp.Window3D->PreGosCleanUp();
	
	if(Scene)
	{
		Unregister_Object(Scene);
		delete Scene;
	}
	Stuff::FileStream * pFile;
  while (theApp.m_pFileSet_List.GetCount() && ((pFile = theApp.m_pFileSet_List.GetHead()) != NULL))
  {
		delete pFile;
		theApp.m_pFileSet_List.RemoveHead();
  }

	
	
	TerminateGameEngine();
	//	gos_PopCurrentHeap();
	//	gos_DestroyMemoryHeap(client);
	ExitGameOS();
	theApp.Window3D->GOSActive=false;
	GOSActive=false;
}

void CMFCGosApp::DrawScreen()
{
	DWORD level = gCurrentHeapStackLevel;
	Verify(UpdateLevel>=0);
	if(UpdateLevel==0)
	{
		UpdateLevel++;
		if(RunGameOSLogic()) PostQuitMessage(0);
		if(Window3DOpen==true) Window3D->UpdateMenu();
		UpdateLevel--;
	}
	Verify(gCurrentHeapStackLevel == level);
}

void CMFCGosApp::OnViewUpdateonidle() 
{
	DrawOnIdle=!DrawOnIdle;
}

void CMFCGosApp::OnUpdateViewUpdateonidle(CCmdUI* pCmdUI) 
{
	pCmdUI->SetCheck(DrawOnIdle?1:0);
}

void CMFCGosApp::UpdateLightList()
{
	int i,idx;
	
	LightDlg->m_LightList.ResetContent();
	for(i=0;i<MidLevelRenderer::Limits::Max_Number_Of_Lights_Per_Primitive && LightState->m_lights[i];i++)
	{
		switch(LightState->m_lights[i]->GetLightType())
		{
		case MidLevelRenderer::MLRLight::AmbientLight:
			idx=LightDlg->m_LightList.AddString("Ambient Light");
			break;
			
		case MidLevelRenderer::MLRLight::InfiniteLight:
			idx=LightDlg->m_LightList.AddString("Infinite Light");
			break;
			
		case MidLevelRenderer::MLRLight::PointLight:
			idx=LightDlg->m_LightList.AddString("Point Light");
			break;
			
		case MidLevelRenderer::MLRLight::SpotLight:
			idx=LightDlg->m_LightList.AddString("Spot Light");
			break;
		case MidLevelRenderer::MLRLight::ProjectLight:
			idx=LightDlg->m_LightList.AddString("Project Light");
			break;
		}
		LightDlg->m_LightList.SetItemDataPtr(idx,LightState->m_lights[i]);
		
	}
	
}

void CMFCGosApp::OnWindowsLightlist() 
{
	if(LightDlg)
		LightDlg->ShowWindow(LightDlg->IsWindowVisible()?SW_HIDE:SW_SHOW);
}

void CMFCGosApp::OnUpdateWindowsLightlist(CCmdUI* pCmdUI) 
{
	if(LightDlg)
		pCmdUI->SetCheck(LightDlg->IsWindowVisible()?1:0);
}



void CMFCGosApp::OnFileOpen()
{
	CFileDialog dlg(true,"*.erf",NULL,OFN_ALLOWMULTISELECT | OFN_EXPLORER | OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST | OFN_SHAREAWARE,"MLR Files (*.erf;*.mlr)|*.erf;*.mlr||");

	char szFileListOriginal[64*1024 +1] = "";
	char szFileList[64*1024 +1] = "";
	char *tmp= szFileList;

	dlg.m_ofn.lpstrFile = szFileListOriginal;
	dlg.m_ofn.nMaxFile = 64 * 1024 - 1;


	if (IDOK==dlg.DoModal())
	{
		int count = 00;





		POSITION pos = dlg.GetStartPosition();
		CString strFileName;
		while (pos)
		{
			count++;
			if (count >= 64)
			{
				MessageBox(NULL, "Too many files. Files > 64.", "Error", MB_OK);
				return;
			}
			strFileName = dlg.GetNextPathName(pos);
			strcpy(tmp, (LPCSTR) strFileName);
			if (pos) // there are more
			{
				tmp += strFileName.GetLength();
				*tmp = '/';
				tmp++;
			}
		}
	CMFCGosDoc * pDoc = GetActiveErfDocument();
	if (!pDoc)
		return;
	CWinApp::OnFileNew();
	pDoc->OnOpenDocument(szFileList);
	}
	else
	{
		DWORD dwTemp = CommDlgExtendedError();

	}
}


void CMFCGosApp::OnExpandAll()
{
	CFrameWnd * pWnd = (CFrameWnd *)this->GetMainWnd();
	CMFCGosView * pView = (CMFCGosView *)pWnd->GetActiveView();
	pView->OnExpandAll();

}

void CMFCGosApp::OnCollapseAll()
{
	CFrameWnd * pWnd = (CFrameWnd *)this->GetMainWnd();
	CMFCGosView * pView = (CMFCGosView *)pWnd->GetActiveView();
	pView->OnCollapseAll();

}


#define CAMERA_KEY_SPEED (1.0f)
void CMFCGosApp::UpdateCameraFromKeyMessage(UINT message, WPARAM wParam, LPARAM lParam)
{
#define HIGHBITON(M_X) ((M_X & (1<<((sizeof(SHORT)*8)-1))) != 0)
	BOOL controlDown = HIGHBITON(GetKeyState(VK_CONTROL));
	BOOL shiftDown = HIGHBITON(GetKeyState(VK_SHIFT));
	BOOL altDown = controlDown && shiftDown;//HIGHBITON(GetKeyState(VK_MENU));
	if (altDown)
		{
		controlDown = shiftDown = false;
		}
	
	switch (wParam)
		{
		case VK_UP:
			if (controlDown)
				Camera_Direction.pitch -= CAMERA_KEY_SPEED * .05f;
			if (shiftDown)
				Camera_Shift.y += CAMERA_KEY_SPEED;
			if (altDown)
				Camera_Direction.range -= CAMERA_KEY_SPEED;
			break;
		case VK_DOWN:
			if (controlDown)
				Camera_Direction.pitch += CAMERA_KEY_SPEED * .05f;
			if (shiftDown)
				Camera_Shift.y -= CAMERA_KEY_SPEED;
			if (altDown)
				Camera_Direction.range += CAMERA_KEY_SPEED;
			break;
		case VK_LEFT:
			if (controlDown)
				Camera_Direction.yaw -= CAMERA_KEY_SPEED * .05f;
			if (shiftDown)
				Camera_Shift.x += CAMERA_KEY_SPEED;
			break;
		case VK_RIGHT:
			if (controlDown)
				Camera_Direction.yaw += CAMERA_KEY_SPEED * .05f;
			if (shiftDown)
				Camera_Shift.x -= CAMERA_KEY_SPEED;
			break;
		}
}



