// RcRcMaterialModifyExample.cpp : Implementation of CRcRcMaterialModifyExample

#include "stdafx.h"
#include "RcMaterialModifyExample.h"
#include "RpExamplesPlugin.h"


// CRcMaterialModifyExample

STDMETHODIMP CRcMaterialModifyExample::OnGetValue(CONID conID, IRsDataCache* pDataCache, VARIANT* pVtData, RtBool* pHandled)
{
	return S_OK;
}

STDMETHODIMP CRcMaterialModifyExample::OnSetValue(CONID con_id, IRsDataCache* pDataCache, VARIANT* pvtData, RtBool* pHandled)
{
	return S_OK;
}
STDMETHODIMP CRcMaterialModifyExample::OnDefaultValue(CONID con_id, VARIANT* pVtData, RtBool* pHandled)
{
	return S_OK;
}

STDMETHODIMP CRcMaterialModifyExample::OnInvalidate(CONID con_id, RtBool* pHandled)
{
	return S_OK;
}

STDMETHODIMP CRcMaterialModifyExample::OnInitialize(void)
{
	return S_OK;
}

STDMETHODIMP CRcMaterialModifyExample::OnLoadDefault(void)
{
	CComQIPtr<IRsBaseNode> spBase = m_spUnkAgg;   // Get the BaseNode interface
	ATLASSERT(spBase);

	HRESULT hr;

	//declare command connector which will serve as input parameter
	RtConDesc sSelection	= {&CON_MME_SELECTION, L"Selection",	  L"Selection",		VT_BSTR,  NULL, CONFLG_IN};

	//create connector from descriptor and add it to our command node
	if (FAILED(hr = spBase->AddNewConnector(&sSelection, NULL))) return hr;

	return S_OK;
}

STDMETHODIMP CRcMaterialModifyExample::OnDestroy(void)
{
	return S_OK;
}

HRESULT CRcMaterialModifyExample::FinalConstruct()
{
	// kernel package
	CComPtr<IRpKernel> spKernelPck;
	HRESULT hRes = CRpExamplesPlugin::GetKernelPackage(&spKernelPck);
	
	// create base node
	if (SUCCEEDED(hRes))
		hRes = spKernelPck->CreateBaseNode(GetControllingUnknown(), &m_spUnkAgg);

	return hRes;
}

STDMETHODIMP CRcMaterialModifyExample::Execute(void)
{
	//get our basenode interface
	CComQIPtr<IRsBaseNode> spBase = m_spUnkAgg;
	_ASSERT(spBase);

	CComPtr<IRpKernel> spKernel;
	CRpExamplesPlugin::GetKernelPackage(&spKernel);

	CComPtr<IRsNode> spSelectedNode;

	//get object name
	CComVariant v;
	CComBSTR szName;
	spBase->GetValue(CON_MME_SELECTION, &v);
	if (v.ChangeType(VT_BSTR) == S_OK)
		szName = v.bstrVal;
	
	
	if (szName == L"") {
		//no name was specified, use first selected object
		CComPtr<IRsSelectionManager> spSelectionManager;
		spKernel->GetSelectionManager(&spSelectionManager);

		//get nodes selection
		CComPtr<IRsBaseSelection> spSelection;
		spSelectionManager->GetSelection(DEF_GUIDNAME(IRdSelNodeSelection), &spSelection);
		CComQIPtr<IRdSelNodeSelection> spNodeSelection = spSelection;
		if (!spNodeSelection) {
			//no node selection exist
			return E_FAIL;
		};
		if (spNodeSelection->GetCount() == 0)  {
			//no object is selected
			return E_FAIL;
		};
		spNodeSelection->GetAt(0, &spSelectedNode);
	}
	else {
		//name is specified, locate node 

		//get dependency graph root
		CComPtr<IRnKernel> spRoot;
		spKernel->GetKernelNode(&spRoot);
		//get root encapsulator interface
		CComQIPtr<IRnEncapsulator> spRootEnc = spRoot;
		if (!spRootEnc)
			return E_FAIL;

		//locate node
		spRootEnc->FindNodeByName(szName, &spSelectedNode);
	};

	if (!spSelectedNode)
		return E_FAIL;

	//Find Space3D package.
	CComPtr<IRsUnknownPackage> spUnkPck;
	spKernel->FindPackage(DEF_GUIDNAME(CRpSpace3DPck), &spUnkPck);
	CComQIPtr<IRpSpace3DPck> spSpace3d = spUnkPck;
	if (!spSpace3d) {
		//Space3d is not registered
		return E_FAIL;
	};

	//create material fn set
	CComPtr<IRfMaterialListSet> spMaterialSet;
	spSpace3d->CreateMaterialListFnSet(&spMaterialSet);


	//create event recorder for handling undo/redo. Note that m_spLogSession is NULL as execute is called only once.
	spKernel->CreateEventLogSession(&m_spLogSession);
	if (!m_spLogSession) {
		//some error has occured and recorder failed to create.
		return E_FAIL;
	};

	//initialize event recording on whole dependency graph. From now on, each change to dependency graph will be recorded into m_spLogSession.
	//it it strongly advised to record only subgraph you are modifying for performance reasons. We record events in object subgraph only.
	m_spLogSession->StartLog(spSelectedNode);


	//attach node to material list set
	spMaterialSet->Attach(spSelectedNode);

	//prepare simple red material
	CComPtr<IRdMaterialGeneric> spGenericMaterial;
	CRpExamplesPlugin::CreateDataObject(&spGenericMaterial);

	//set default material
	spGenericMaterial->SetDefaultMaterial();

	//set color shader from to red
	spGenericMaterial->SetColorItem(GS_PLAIN_COLOR_R, CComVariant(1.0f));
	spGenericMaterial->SetColorItem(GS_PLAIN_COLOR_G, CComVariant(0.0f));
	spGenericMaterial->SetColorItem(GS_PLAIN_COLOR_B, CComVariant(0.0f));


	//first check for material count
	RtDWORD dwMatCnt;
	spMaterialSet->GetMaterialsCount(&dwMatCnt);
	if (dwMatCnt == 0) {
		//we don't have any materials specified, create simple red material using generic material description
		spMaterialSet->SetMaterialFromGeneric(0, spGenericMaterial);
	}
	else {
		//material at index 0 found. Update color shaders only.
		spMaterialSet->SynchronizeMaterialFromGeneric(0, spGenericMaterial, GENMAT_COMPONENT_COLOR);
	};

	//stop event recording. 
	m_spLogSession->FinishLog();
	return S_OK;
}

STDMETHODIMP CRcMaterialModifyExample::Undo(void)
{
	//apply previous states to dependency graph
	if (m_spLogSession)
		m_spLogSession->Undo();
	return S_OK;
}

STDMETHODIMP CRcMaterialModifyExample::Redo(void)
{
	//apply new states to dependency graph
	if (m_spLogSession)
		m_spLogSession->Redo();
	return S_OK;
}

STDMETHODIMP CRcMaterialModifyExample::HasUndo(RtBool* isUndoable)
{
	//Command IS undoable.
	*isUndoable = true;
	return S_OK;
}


