/****************************************************************************************************

		PanePart.cpp
		Copyright: (c) 2001 Eovia Corp. All rights reserved.

		Author:	Arnaud
		Date:	11/23/2004

****************************************************************************************************/

#include "PanePart.h"


#include "I3DEditorHostPart.h"


#include "COM3DUtilities.h"
#include "COMUtilities.h"
#include "COMSafeUtilities.h"
#include "I3DExRendererBox.h"
#include "I3DShObject.h"
#include "I3DShShader.h"
#include "IShComponent.h"
#include "IShUtilities.h"
#include "MCCountedPtrHelper.h"
#include "ISceneDocument.h"

#include "Modeler.h"



TPanePart::TPanePart()
{
}

TPanePart::~TPanePart()
{
}


MCCOMErr TPanePart::QueryInterface(const MCIID& riid, void** ppvObj)
{
	if (MCIsEqualIID(riid, TPanePart::sClassID))
	{
		TMCCountedGetHelper<TPanePart> result(ppvObj);
		result = this;
		return MC_S_OK;
	}
	else if(MCIsEqualIID(riid,IID_IEx3DEditorHostPanePart))
	{
		TMCCountedGetHelper<IEx3DEditorHostPanePart> result(ppvObj);
		result = this;
		return MC_S_OK;
	}
	else
		return TBasicPart::QueryInterface(riid, ppvObj);
}


void TPanePart::SelfPrepareToDestroy()
{
	fLightSource			= NULL;
	fLightSourceRenderable	= NULL;

	TBasicPart::SelfPrepareToDestroy();
}

void TPanePart::SetModeler(TModeler* inModeler)
{
	fModeler= inModeler; 
}

boolean TPanePart::IsPerspective()
{
	I3DShCamera* camera=f3DEditorHostPanePart->GetCurrentCameraNoAddRef();
	return (camera->GetCanonicalCameraType() == kCanonicalCameraType_NotCanonical);
}


void TPanePart::InternalSelfDraw(IMCGraphicContext* graphicContext, TMCRect* inZone)
{
	TMCCountedPtr<I3DShScene>  scene;
	TMCCountedPtr<ISceneDocument>  scenedoc ;
	GetCurrentScene(&scene, true);
	if(scene)
	{
		scene->GetSceneDocument(&scenedoc);
		
	}
	f3DEditorHostPanePart->RenderDraw(graphicContext, inZone, scenedoc);

}

void TPanePart::SelfDraw(IMCGraphicContext* graphicContext, const TMCRect& inZone)
{
	if (fModeler && fModeler->GetImmediateUpdate())
	{
		return;
	}

	TMCRect theZone(inZone);
	InternalSelfDraw(graphicContext, &theZone);	
}


TMFEventResult TPanePart::SelfMouseDown(const TMCPoint& 		inWhere, 
										const TMCPlatformEvent& inEvent)
{	
	TMFEventResult result;

	if (fModeler->MouseDownInPane(this, inWhere, inEvent))
	{
		return TMFEventResult(true, true);
	}
	else 
		return result;
}


void TPanePart::Set3DEditorHostPanePart(I3DEditorHostPanePart* editorHostPanePart)
{
	f3DEditorHostPanePart = editorHostPanePart;
}


void TPanePart::GetCameraToolsStatus	(TCameraToolsStatus& outStatus, boolean& outAllowSavePos)
{
	boolean isCanonical= false;
	if (MCVerify(f3DEditorHostPanePart))
	{
		I3DShCamera* camera= f3DEditorHostPanePart->GetCurrentCameraNoAddRef();
		isCanonical= camera && (camera->GetCanonicalCameraType() != kCanonicalCameraType_NotCanonical);
	}

	outStatus		= (isCanonical) ? k2DToolsEnabled : kAllEnabled;
	outAllowSavePos	= !isCanonical;
}


MCCOMErr TPanePart::SelfRenderDraw(TRenderable2DArray& renderables2D)
{
	// Provides the graphic content for a pane
	ThrowIfNil(f3DEditorHostPanePart);
	I3DShCamera* paneCamera= f3DEditorHostPanePart->GetCurrentCameraNoAddRef();
	ThrowIfNil(paneCamera);
	
	TRenderableAndTfmArray	ita;

	//--  Add the working box and its planes selectively
	TMCCountedPtr<IWorkingBox> workingBox;
	f3DEditorHostPanePart->Get3DEditorHost()->GetWorkingBox(&workingBox);
	if (IsPerspective())
	{
		workingBox->AddRenderables(ita);
	}
	else
	{
		int32 planeIndex= -1;
		switch (paneCamera->GetCanonicalCameraType())
		{
		case kCanonicalCameraType_Front:
		case kCanonicalCameraType_Back:
			planeIndex= kWBLeftPlane;
			break;
		case kCanonicalCameraType_Top:
		case kCanonicalCameraType_Bottom:
			planeIndex= kWBBottomPlane;
			break;
		case kCanonicalCameraType_Left:
		case kCanonicalCameraType_Right:
			planeIndex= kWBRightPlane;
			break;
		}

		if (planeIndex != -1)
		{
			TMCCountedPtr<IWorkingBoxPlane> workingBoxPlane;
			workingBox->GetPlane( planeIndex, &workingBoxPlane);
			ThrowIfNil(workingBoxPlane);
		
			workingBoxPlane->AddRenderables(ita);
		}
	}

	fModeler->AddPrimitiveRenderables(ita);

	//Let there be light (useful for actual lighting mode)
	if (!fLightSourceRenderable)
	{
		CreateLightSource();
		ThrowIfNil(fLightSourceRenderable);
	}
	ita.AddElem(*fLightSourceRenderable);


	//-- Launch rendering
	if (ita.GetElemCount())
	{
		TMCCountedPtr<I3DExRendererBox> interactiveRenderer;
		f3DEditorHostPanePart->GetInteractiveRenderer(&interactiveRenderer);
		interactiveRenderer->DrawInstances(ita,renderables2D);
	}

	return MC_S_OK;
}

void TPanePart::CreateLightSource()
{
	gComponentUtilities->CoCreateInstance(CLSID_StandardDistantLight, NULL, 1, IID_I3DShLightsource, (void**)&fLightSource);
	ThrowIfNil(fLightSource);

	TMCCountedPtr<IShComponent>				lightSourceComponent;
	TMCCountedPtr<IShParameterComponent>	lightSourceParameterComponent;
	TMCCountedPtr<I3DShInstance>			instance;

	fLightSource->QueryInterface(IID_I3DShInstance, (void**) &instance); ThrowIfNil(instance);
	fLightSource->GetLightComponent(&lightSourceComponent); ThrowIfNil(lightSourceComponent);
	lightSourceComponent->QueryInterface(IID_IShParameterComponent, (void**) &lightSourceParameterComponent); ThrowIfNil(lightSourceParameterComponent);
	

	real brightness = 0.8f;		
	lightSourceParameterComponent->SetParameter('brit', &brightness);

	fLightSourceRenderable= new TRenderableAndTfm();

	fLightSourceRenderable->fInstance	= instance;
	fLightSourceRenderable->fRenderable = NULL;

	real kInvSqrt2 = 1.0f/sqrt(2.0);
	fLightSourceRenderable->fT.fRotationAndScale= TMatrix33(kInvSqrt2,	0.0f,	kInvSqrt2,
															0.0f,		1.0f,	0.0f,
															-kInvSqrt2,	0.0f,	kInvSqrt2);

	fLightSourceRenderable->fT.GetInverse(fLightSourceRenderable->fModelFromWorldTfm);
}


MCCOMErr TPanePart::InvalidateRender(boolean invalidate, boolean cameraChanged)
{
	f3DEditorHostPanePart->InvalidateRender();

	if(invalidate) 
	{
		TMCCountedPtr<IMFPart> part;
		f3DEditorHostPanePart->QueryInterface(IID_IMFPart, (void**) &part);
		ThrowIfNil(part);
		part->Invalidate();
	}

	return MC_S_OK;
}


MCCOMErr TPanePart::SelfRenderPickDraw(I3DExPickRenderer* pickRenderer)
{
	return MC_E_NOTIMPL;
}


void TPanePart::GetCurrentScene(I3DShScene **scene, boolean createIfNone)
{
	if(createIfNone)
	{
		I3DShPrimitive* primitive = fModeler->GetPrimitive();

		TMCCountedPtr<I3DShObject> object;
		primitive->QueryInterface(IID_I3DShObject,(void**)&object);
		ThrowIfNil(object);

		TMCCountedPtr<I3DShObject> clone;
		object->Clone(&clone,kNoAnim);

		// get the shader of the object
		TMCCountedPtr<I3DShMasterShader> masterShader;

		TMCCountedPtrArray<I3DShInstance> instances;
		object->GetInstanceArray(instances);

		ThrowIfNil(instances.GetElemCount()); // there should always be an instance
		instances[0]->GetShader(&masterShader);
		TMCCountedPtrArray<I3DShMasterShader>* masterShaders;
		masterShaders->AddElem(masterShader);
		gShell3DUtilities->CreateScene(scene,clone,masterShaders);
	}
}
