void OutputESS::ei_declare(const char *name, const eiInt storage_class, const eiInt type/*, const void *tag*/)
	{
		//CM_TRACE_FUNC("OutputESS::ei_declare(\""<<name<<"\","<<storage_class<<","<<type<<", &tag)");
		std::string str_storage_class;
		switch(storage_class)
		{
		case EI_CONSTANT: str_storage_class="const";   break;
		case EI_UNIFORM:  str_storage_class="uniform"; break;
		case EI_VARYING:  str_storage_class="varying"; break;
		case EI_VERTEX:   str_storage_class="vertex";  break;
		default:
			liquidMessage2(messageError, "ei_declare(%s, %d(unknown), %d), ", name, storage_class, type);
			a(boost::str(boost::format("error: ei_declare(%s, %d(unknown), %d)")%name %storage_class %type));
			break;
		}

		std::string str_type;
		switch(type)
		{
		case EI_TYPE_NONE:		str_type = "";			break;
			/* atomic types */
		case EI_TYPE_TOKEN:		str_type = "token";		break;
		case EI_TYPE_BYTE:		str_type = "byte";		break;
		case EI_TYPE_SHORT:		str_type = "short";		break;
		case EI_TYPE_INT:		str_type = "int";		break;
		case EI_TYPE_BOOL:		str_type = "bool";		break;
		case EI_TYPE_TAG:		str_type = "tag";		break;
		case EI_TYPE_INDEX:		str_type = "index";		break;
		case EI_TYPE_LONG:		str_type = "long";		break;
		case EI_TYPE_SCALAR:	str_type = "scalar";	break;
		case EI_TYPE_GEOSCALAR:	str_type = "geoscalar";	break;
		case EI_TYPE_VECTOR:	str_type = "vector";	break;
		case EI_TYPE_VECTOR2:	str_type = "vector2";	break;
		case EI_TYPE_VECTOR4:	str_type = "vector4";	break;
		case EI_TYPE_MATRIX:	str_type = "matrix";	break;
		case EI_TYPE_BOUND:		str_type = "bound";		break;
		case EI_TYPE_RECT:		str_type = "rect";		break;
		case EI_TYPE_RECT4I:	str_type = "rect4i";	break;
		case EI_TYPE_INTARRAY:	str_type = "intarray";	break;
			/* compound types */
		case EI_TYPE_JOB_TEST:	str_type = "jobtest";	break;
		case EI_TYPE_ARRAY:		str_type = "array";		break;
		case EI_TYPE_TABLE:		str_type = "table";		break;
		case EI_TYPE_BLOCK:		str_type = "block";		break;
		case EI_TYPE_USER:		str_type = "user";		break;
		default:
			liquidMessage2(messageError, "ei_declare(%s, %d, %d(unknown)), ", name, storage_class, type);
			a(boost::str(boost::format("error: ei_declare(%s, %d, %d(unknown))")%name %storage_class %type));
			break;
		}
		m_outputfile<<"declare \""<<name<<"\" \""<<str_storage_class<<"\" \""<<str_type<<"\" "<<std::endl;
	}
	void OutputESS::ei_variable(const char *name, const void *tag)
	{
		//CM_TRACE_FUNC("OutputESS::ei_variable(\""<<name<<"\", &tag)");
		liquidMessage2(messageError, "OutputESS::ei_declare(&tag)");
		a("error: ei_variable(&tag)");
		m_outputfile<<"variable \""<<name<<"\"  &tag);"<<std::endl;
	}
	void Renderer::write(
		/*const*/ liqRibShaveData* pData,
		const MString &ribFileName,
		const structJob &currentJob,
		const bool bReference)
	{
		CM_TRACE_FUNC("Renderer::write("<<pData->getFullPathName()<<","<<ribFileName.asChar()<<","<<currentJob.name.asChar()<<",ref="<<bReference<<")");

		assert(liqglo.m_ribFileOpen&&"rm_writeShaveData.cpp");

	 	if( !bReference ){//write data at first time
			if( !currentJob.isShadow ){
				assert(pData->getRibFileFullPath().length()==0&&"rm_writeShaveData.cpp");
			}
			pData->setRibFileFullPath(ribFileName);

			//1)make a reference
			RiReadArchive( const_cast< RtToken >( pData->getRibFileFullPath().asChar() ), NULL, RI_NULL );

			//2)call shave command to write the rib file(not support motion blur)
			MString cmd("shaveWriteRib -hairNode \""+pData->objDagPath.partialPathName()+"\" \""+pData->getRibFileFullPath()+"\";");
			if( MFAIL(MGlobal::executeCommand(cmd, true) )){
				liquidMessage2(messageError,"write shave rib file fail: [%s]", cmd.asChar());
			}
	 	}else{
	 		//write the reference
	 		assert(pData->getRibFileFullPath() == ribFileName);
	 		RiReadArchive( const_cast< RtToken >( pData->getRibFileFullPath().asChar() ), NULL, RI_NULL );
	 	}
	}
	eiTag OutputESS::ei_tab(const eiInt type, const eiUint nkeys, const eiInt items_per_slot)
	{
		//CM_TRACE_FUNC("OutputESS::ei_tab("<<type<<","<<nkeys<<","<<items_per_slot<<")");
		m_outputfile<<"##ei_tab( "<<type<<", "<<nkeys<<","<<items_per_slot<<" );"<<std::endl;
		liquidMessage2(messageError, "OutputESS::ei_tab(), return 0;");
		return 0;
	}
	void GroupMgr::addObjectInstance(
		const GroupID &id, 
		const std::string &objInstanceName,
		const GroupInstanceType type
		)
	{
		if( groups.find(id) == groups.end() )
		{
			// not exist
			createGroup(id);
		}

		std::map<GroupID, Group>::iterator i = groups.find(id);
		assert(i != groups.end());
		
		switch( type )
		{
		case GIT_Camera:
			i->second.addCameraInstance( objInstanceName );
			break;
		case GIT_Geometry:
			i->second.addMeshInstance( objInstanceName );
			break;
		default:
			liquidMessage2(messageError, "group instance type %d is unknown.",type);
			assert(0&&"group instance type is unknown. see script window for more details.");
		}

		
	}
	static void _write(liqRibImplicitSphereData* pData, const structJob &currentJob__)
	{
		CM_TRACE_FUNC("er_writeImplicitSphereData.cpp::write("<<pData->getFullPathName().asChar()<<","<<currentJob__.name.asChar()<<",...)");
		OutputMgr &o = Renderer::getOutputMgr();

		o.a(boost::str(boost::format("Implicit Sphere [%s] is not implemented yet.")%pData->getFullPathName().asChar()));
		liquidMessage2(messageError, "ImplicitSphere type is not implemented yet. [%s]", pData->getFullPathName().asChar());
	}
	void OutputESS::ei_shader_param(
		const char *param_name, 
		const void *param_value)
	{
		//CM_TRACE_FUNC("OutputESS::ei_shader_param(\""<<param_name<<"\", \""<<param_value<<"\") not implemented");
		liquidMessage2(messageError, "OutputESS::ei_shader_param() not implemented");
		a("error: ei_shader_param(): OutputESS::ei_shader_param() not implemented");
		m_outputfile<<"    shader_param \""<<param_name<<"\" \""<<param_value<<"\" "<<std::endl;
	}
	void Helper4::endSS()
	{
		if(m_assembly->surface_shaders().get_by_name(m_nodename.c_str()) == nullptr)
		{
			if("ao_surface_shader"==m_ss_model)
			{
				m_assembly->surface_shaders().insert(
					asr::AOSurfaceShaderFactory().create(
					m_nodename.c_str(),
					m_ss_params
					)
				);
			}
			else if("diagnostic_surface_shader"==m_ss_model)
			{
				m_assembly->surface_shaders().insert(
					asr::DiagnosticSurfaceShaderFactory().create(
					m_nodename.c_str(),
					m_ss_params
					)
					);
			}
			else if("fast_sss_surface_shader"==m_ss_model)
			{
				m_assembly->surface_shaders().insert(
					asr::FastSubSurfaceScatteringSurfaceShaderFactory().create(
					m_nodename.c_str(),
					m_ss_params
					)
					);
			}
			else if("physical_surface_shader"==m_ss_model)
			{
				m_assembly->surface_shaders().insert(
					asr::PhysicalSurfaceShaderFactory().create(
					m_nodename.c_str(),
					m_ss_params
					)
				);
			}
			else if("constant_surface_shader"==m_ss_model)
			{
				m_assembly->surface_shaders().insert(
					asr::ConstantSurfaceShaderFactory().create(
					m_nodename.c_str(),
					m_ss_params
					)
				);
			}
			//
			else 
			{
				liquidMessage2(messageError, "surface model [%s] is not supported.",m_ss_model.c_str() );
			}
		}
	}
	void OutputESS::liq_hair(
		const std::string &objname,
		MFnPfxGeometry &fnPfxGeometry,
		int degree,
		unsigned setOn)
	{
		//CM_TRACE_FUNC("OutputESS::liq_hair(objname)");
		liquidMessage2(messageError, "OutputESS::liq_hair() is not implemented.");
		a("OutputESS::liq_hair() is not implemented.");
	}
const MStringArray& 
ShaderValidConnection::getValidConnectionRef(const char* shadertype) const
{
	if( hasShaderType(shadertype) ){
		return validConnectionMap.find(shadertype)->second;
	}else{
		liquidMessage2(messageError, "shader type \"%s\" is not supported.", shadertype);
		assert(0&&"shader type is not supported.");
		return validConnectionMap.find("null")->second;
	}
}
void tLocatorMgr::scanScene(const float lframe__, const int sample__,
						  boost::shared_ptr< liqRibHT > &htable__,
						  int &count__,
						  MStatus &returnStatus__)
{
	CM_TRACE_FUNC("tLocatorMgr::scanScene("<<lframe__<<","<<sample__<<",htable__,count__,returnStatus__)");

	//[refactor 10] beg from scanScene()
	MItDag dagCoordSysIterator( MItDag::kDepthFirst, MFn::kLocator, &returnStatus__);

	for (; !dagCoordSysIterator.isDone(); dagCoordSysIterator.next()) 
	{
#if (Refactoring == 0)
		LIQ_CHECK_CANCEL_REQUEST;
#endif
		MDagPath path;
		MObject currentNode;
		currentNode = dagCoordSysIterator.item();
		MFnDagNode dagNode;
		dagCoordSysIterator.getPath( path );
		if(MS::kSuccess != returnStatus__) 
			continue;
		if(!currentNode.hasFn(MFn::kDagNode)) 
			continue;
		returnStatus__ = dagNode.setObject( currentNode );
		if(MS::kSuccess != returnStatus__) 
			continue;

		// scanScene: if it's a coordinate system then insert it into the hash table
		if( dagNode.typeName() == "liquidCoordSys" ) 
		{
			int coordType = 0;
			MPlug typePlug = dagNode.findPlug( "type", &returnStatus__ );
			if( MS::kSuccess == returnStatus__ ) 
				typePlug.getValue( coordType );

			bool useSamples( ( sample__ > 0 ) && isObjectMotionBlur( path ) );

			ObjectType mrttype = getMRTType(currentNode, coordType);
			ObjectType mrttype_shouldbe = ( coordType == 5 )? MRT_ClipPlane : MRT_Coord;
			if( mrttype != mrttype_shouldbe ){
				liquidMessage2(messageError, "mrttype[%d] should be %d", mrttype_shouldbe);
			}
			htable__->insert( path, 
				lframe__, 
				( useSamples )? sample__ : 0, 
				mrttype, //( coordType == 5 )? MRT_ClipPlane : MRT_Coord, 
				count__++ );
			continue;
		}
	}
	//[refactor 10] end from scanScene()
}
	OutputESS::OutputESS(const std::string &filefullpath)
		:OutputBase()
	{
		CM_TRACE_FUNC("OutputESS::OutputESS("<<filefullpath<<")");

		const std::string logFileName(filefullpath+".ess");
		m_outputfile.open(logFileName.c_str(), std::ios_base::out);
		if( !m_outputfile.is_open() )
		{
			liquidMessage2(messageError,"can't open file: [%s]", logFileName.c_str() );
		}
	}
	static int getSegment(const int degree) 
	{
		int ret = 0;
		switch(degree)
		{
		case 1: case 2: case 3: 
			ret = degree; break;
		default:
			liquidMessage2(messageError, "invalid pfxhair degree:%d", degree);
		}
		return ret;
	}
	void RendererMgr::createFactory(const std::string& renderername)
	{
		CM_TRACE_FUNC("RendererMgr::createFactory("<<renderername<<")");

		if(renderername=="renderman"){
			m_factory = new renderman::Factory();
		}
		else if(renderername=="elvishray"){
			m_factory = new elvishray::Factory();
		}
		else {
			liquidMessage2(messageError, "Unkown renderer:%s.",renderername.c_str() );
		}
	}
	void Renderer::generate_shavehair(liqRibNodePtr &ribNode__, liqRibShaveData* pData, const int degree)
	{
		CM_TRACE_FUNC("generate_pfxhair("<<ribNode__->getTransformNodeFullPath().asChar()<<")");

		MStatus status;

		shaveAPI::HairInfo hairInfo;
		status = shaveAPI::exportAllHair(&hairInfo);
		if(MFAIL(status)){
			liquidMessage2(messageError,"shaveAPI::exportAllHair(&hairInfo)=[%s]", status.errorString().asChar());
			return;
		}

		//todo
	}
MString Visitor::getRSLShaderType(const MString &mayaplug)
{
	MString shaderType;

	if(mayaplug=="surfaceShader"){
		shaderType = "surface";
	}else if(mayaplug=="displacementShader"){
		shaderType = "displacement";
	}else if(mayaplug=="volumeShader"){
		shaderType = "volume";
	}else{
		liquidMessage2(messageError,"unkown shader type for plug %s", mayaplug.asChar());
	}
	return shaderType;
}
void liquidIPR_AttributeChangedCallback( MNodeMessage::AttributeMessage msg, 
	MPlug & plug, MPlug & otherPlug, void *userData )
{
	MGlobal::displayInfo( "liquidIPR_AttributeChangedCallback(msg, "+ plug.name()+","+otherPlug.name()+", userData)");
	//liquidMessage2(messageInfo, "msg=%0x", msg);

	static std::size_t iHowMantThreadEnters = 0;
	iHowMantThreadEnters++;
	//liquidMessage2(messageInfo, "HowMantThreadEnters=%d", iHowMantThreadEnters);

	if ( msg & MNodeMessage::kConnectionMade ) {
		MGlobal::displayInfo("Connection made ");
	}
	else if ( msg & MNodeMessage::kConnectionBroken ) {
		MGlobal::displayInfo("Connection broken ");
	}
	else if ( msg & MNodeMessage::kAttributeEval ) {
		MGlobal::displayInfo("kAttributeEval");
	}
	else if ( msg & MNodeMessage::kAttributeSet ) {
		MGlobal::displayInfo("kAttributeSet");

		//liqRibTranslator::getInstancePtr()->IPRRenderBegin();

		//if( canExport() )
		{
			liquid::RendererMgr::getInstancePtr()->getRenderer()
				->IPR_AttributeChangedCallback(msg, plug, otherPlug, userData);
		}

		//liqRibTranslator::getInstancePtr()->IPRRenderEnd();
	}
	else {
		liquidMessage2(messageInfo, "else: msg=%0x", msg);
	}

// 	cout << plug.info();
// 	if ( msg & MNodeMessage::kOtherPlugSet ) {
// 		if ( msg & MNodeMessage::kIncomingDirection ) {
// 				cout << "  <--  " << otherPlug.info();
// 		} else {
// 				cout << "  -->  " << otherPlug.info();
// 		}
// 	}
// 	cout << endl;
	--iHowMantThreadEnters;

}
	void Helper4::endEDF()
	{
		if(m_assembly->edfs().get_by_name(m_nodename.c_str()) == nullptr)
		{
			if("diffuse_edf"==m_edf_model)
			{
				m_assembly->edfs().insert(
					asr::DiffuseEDFFactory().create(
					m_nodename.c_str(),
					m_edf_params
					)
				);
			}else{
				liquidMessage2(messageError,"appleseed only support diffuse_edf model");
			}
		}
	}
	//	Output Statements:
	void OutputESS::ei_output( const char *filename, const char *fileformat, const eiInt datatype)
	{
		//CM_TRACE_FUNC("OutputESS::ei_output(\""<< filename <<"\",\""<<fileformat<<"\","<<datatype<<")");
		std::string str_datatype;
		switch(datatype)
		{
		case EI_IMG_DATA_NONE:	str_datatype = "";		break;
		case EI_IMG_DATA_RGB:	str_datatype = "rgb";	break;
		case EI_IMG_DATA_RGBA:	str_datatype = "rgba";	break;
		case EI_IMG_DATA_RGBAZ: str_datatype = "rgbaz";	break;
		default:
			liquidMessage2(messageError, "error: ei_output(): image data type [%d] is unknown", datatype);
			a( boost::str(boost::format("error: ei_output(): image data type [%d] is unknown")%datatype) );
			break;
		}
		m_outputfile<<"    output \""<< filename <<"\" \""<<fileformat<<"\" \""<<str_datatype<<"\" "<<std::endl;
	}
// MFloatVector GlobalNodeHelper::getVector3(const MString& attrName )
// {
//  	MStatus status;
//  	MFloatVector value(-1.0f, -1.0f, -1.0f);
// // 	liquidGetPlugValue(m_GlobalNode, attrName.asChar(), value, status);
// // 	IfMErrorMsgWarn(status,"elvishray::GlobalNodeHelper::getVector("+attrName+")"
// 	MStringArray a(getStringArray(attrName));
// 	switch(a.length())
// 	{
// 		case 1: 
// 			value.x = a[0].asFloat();	
// 			break;
// 		case 2: 
// 			value.x = a[0].asFloat(); 
// 			value.y = a[1].asFloat();	
// 			break;
// 		case 3: 
// 			value.x = a[0].asFloat();
// 			value.y = a[1].asFloat();
// 			value.z = a[2].asFloat();	
// 			break;
// 		default:
// 			liquidMessage2(messageError, "GlobalNodeHelper::getVector3(%s), sub-element length=%d", attrName.asChar(), a.length());
// 	}
// 	return value;
// }
MFloatPoint GlobalNodeHelper::getVector(const MString& attrName )
{
 	MStatus status;
 	MFloatPoint value(-1.0f, -1.0f, -1.0f, -1.0f);
// 	liquidGetPlugValue(m_GlobalNode, attrName.asChar(), value, status);
// 	IfMErrorMsgWarn(status,"elvishray::GlobalNodeHelper::getVector("+attrName+")"
	MStringArray a(getStringArray(attrName));
	switch(a.length())
	{
		case 4: value.w = a[3].asFloat();
		case 3: value.z = a[2].asFloat();
		case 2: value.y = a[1].asFloat();
		case 1: value.x = a[0].asFloat(); break;
		default:
			liquidMessage2(messageError, "GlobalNodeHelper::getVector(%s), sub-element length=%d", attrName.asChar(), a.length());
	}
	return value;
}
//--------------------------------------------------------
RtVoid RiBegin_liq(RtToken name)
{
	CM_TRACE_FUNC("RiBegin_liq("<<name<<"(strlen="<<strlen(name)<<")");
	std::string newname(name);

	if( strlen(name)>=_POSIX_PATH_MAX )//file name is too long
	{
		liquidMessage2( messageError, "file name is too long(>=%d(_POSIX_PATH_MAX)):%s", _POSIX_PATH_MAX, name );
		assert(0&&"FATAL ERROE: file name is too long!");
#ifdef _WIN32
		newname = "\\\\?\\";//see MAX_PATH: http://msdn.microsoft.com/en-us/library/aa365247.aspx#maxpath
		newname+= name;
#else
#error "If the file path name is too long, how to handle this case on linux?"
		exit(0);
#endif
	}
	
	RiBegin( const_cast<RtToken>(newname.c_str()) );
}
	void OutputESS::ei_output_variable(const char *name, const eiInt datatype)
	{
		//CM_TRACE_FUNC("OutputESS::ei_output_variable(\""<< name <<"\","<<datatype<<")");
		std::string str_datatype;
		switch(datatype)
		{
		case EI_TYPE_NONE:		str_datatype = "";			break;
		/* atomic types */
		case EI_TYPE_TOKEN:		str_datatype = "token";		break;
		case EI_TYPE_BYTE:		str_datatype = "byte";		break;
		case EI_TYPE_SHORT:		str_datatype = "short";		break;
		case EI_TYPE_INT:		str_datatype = "int";		break;
		case EI_TYPE_BOOL:		str_datatype = "bool";		break;
		case EI_TYPE_TAG:		str_datatype = "tag";		break;
		case EI_TYPE_INDEX:		str_datatype = "index";		break;
		case EI_TYPE_LONG:		str_datatype = "long";		break;
		case EI_TYPE_SCALAR:	str_datatype = "scalar";	break;
		case EI_TYPE_GEOSCALAR:	str_datatype = "geoscalar";	break;
		case EI_TYPE_VECTOR:	str_datatype = "vector";	break;
		case EI_TYPE_VECTOR2:	str_datatype = "vector2";	break;
		case EI_TYPE_VECTOR4:	str_datatype = "vector4";	break;
		case EI_TYPE_MATRIX:	str_datatype = "matrix";	break;
		case EI_TYPE_BOUND:		str_datatype = "bound";		break;
		case EI_TYPE_RECT:		str_datatype = "rect";		break;
		case EI_TYPE_RECT4I:	str_datatype = "rect4i";	break;
		case EI_TYPE_INTARRAY:	str_datatype = "intarray";	break;
			/* compound types */
		case EI_TYPE_JOB_TEST:	str_datatype = "jobtest";	break;
		case EI_TYPE_ARRAY:		str_datatype = "array";		break;
		case EI_TYPE_TABLE:		str_datatype = "table";		break;
		case EI_TYPE_BLOCK:		str_datatype = "block";		break;
		case EI_TYPE_USER:		str_datatype = "user";		break;
		default:
			liquidMessage2(messageError, "error: ei_output_variable(): image data type [%d] is unknown", datatype);
			a( boost::str(boost::format("error: ei_output_variable(): image data type [%d] is unknown")%datatype) );
			break;
		}
		m_outputfile<<"    output_variable \""<< name <<"\" \""<<str_datatype<<"\" "<<std::endl;
	}
MStatus liqIPRNodeMessage::doIt( const MArgList& args)
//
// Takes the  nodes that are on the active selection list and adds an
// attriubte changed callback to each one.
//
{	
	MStatus 		stat;

	for( unsigned i( 0 ); i < args.length(); i++ ) 
	{
		MString arg = args.asString( i, &stat );
		IfMErrorWarn(stat);

		if( (arg == kRegisterFlag) || (arg == kRegisterFlagLong) ){
			isRunningIPR = 1;
			liqRibTranslator::getInstancePtr()->IPRRenderBegin();
			IfMErrorWarn(registerCallback());
			//liqRibTranslator::getInstancePtr()->IPRDoIt();
		}
		else if( (arg == kUnregisterFlag) || (arg == kUnregisterFlagLong) ){
			IfMErrorWarn(unregisterCallback());

			liqRibTranslator::getInstancePtr()->IPRRenderEnd();
			isRunningIPR = 0;
		}
		else if( (arg == kIsRunningIPR) || (arg == kIsRunningIPRLong) ){
			setResult(isRunningIPR);
		}
		else{
			liquidMessage2(messageError,"Parameter [%s] is undefined in liqIPRNodeMessage.", arg.asChar());
			return MS::kUnknownParameter;
		}
	}

	return MS::kSuccess;
}
	static void _write(liqRibParticleData* pData, const structJob &currentJob__)
	{
		CM_TRACE_FUNC("rm_writeParticleData.cpp::write("<<pData->getFullPathName().asChar()<<","<<currentJob__.name.asChar()<<",...)");

		LIQDEBUGPRINTF( "-> writing particles\n");

#ifdef DEBUG
		RiArchiveRecord( RI_COMMENT, "Number of Valid Particles: %d", pData->m_numValidParticles );
		RiArchiveRecord( RI_COMMENT, "Number of Discarded Particles: %d", pData->m_numParticles - pData->m_numValidParticles );
#endif
		MString notes("Make sure the particle is generated(e.g. sometimes particle is not generated, drag the time slider from frame0 to generate particles.)");
		if(pData->m_numValidParticles <= 0 ){
			RiArchiveRecord( RI_COMMENT, "Number of Valid Particles: %d. %s", pData->m_numValidParticles, notes.asChar() );
			liquidMessage2(messageError, "%s. [%s]", notes.asChar(), pData->getFullPathName().asChar());
			return;
		}

		unsigned numTokens( pData->tokenPointerArray.size() );
		boost::scoped_array< RtToken > tokenArray( new RtToken[ numTokens ] );
		boost::scoped_array< RtPointer > pointerArray( new RtPointer[ numTokens ] );
		assignTokenArraysV( pData->tokenPointerArray, tokenArray.get(), pointerArray.get() );

		switch( pData->particleType ) 
		{
		case liqRibParticleData::MPTBlobbies: 
			{
				// Build an array that can be given to RiBlobby
				std::vector< RtString > stringArray;
				for( int i(0); i < pData->m_stringArray.size(); i++ ) 
				{
					stringArray.push_back( const_cast<char *>( pData->m_stringArray[i].c_str()) );
				}
				RiBlobbyV( pData->m_numValidParticles,
					pData->m_codeArray.size(), const_cast< RtInt* >( &pData->m_codeArray[0] ),
					pData->m_floatArray.size(), const_cast< RtFloat* >( &pData->m_floatArray[0] ),
					stringArray.size(), const_cast< RtString* >( &stringArray[0] ),
					numTokens,
					tokenArray.get(),
					const_cast< RtPointer* >( pointerArray.get() ) );
				pData->grain = 0;
			}
			break;

		case liqRibParticleData::MPTMultiPoint:
		case liqRibParticleData::MPTPoints:
			RiArchiveRecord( RI_COMMENT, "normal has to be reversed to show the MultiPoint/Points particles. //  [10/9/2012 yaoyansi]" );
			RiReverseOrientation();
#ifdef DELIGHT
		case liqRibParticleData::MPTSpheres:
		case liqRibParticleData::MPTSprites:
#endif
			{
				RiPointsV( pData->m_numValidParticles * pData->m_multiCount, numTokens, tokenArray.get(), pointerArray.get() );
			}
			break;

		case liqRibParticleData::MPTMultiStreak:
		case liqRibParticleData::MPTStreak: 
			{
				unsigned nStreaks( pData->m_numValidParticles * pData->m_multiCount / 2 );
				std::vector< RtInt > verts( nStreaks, 2 );
				// Alternatively:
				//   scoped_array< RtInt >verts( new RtInt[ nStreaks ] );
				//   fill( verts.get(), verts.get() + nStreaks, ( RtInt )2 );
				// Both ways are way faster than the frickin for() lop that was here before -- Moritz

				RiCurvesV( "linear", nStreaks, &verts[ 0 ], "nonperiodic", numTokens, tokenArray.get(), pointerArray.get() );
			}
			break;
#ifndef DELIGHT
		case liqRibParticleData::MPTSpheres: 
			{
				int posAttr  = -1,
					radAttr  = -1,
					colAttr  = -1,
					opacAttr = -1;

				for ( unsigned i = 0; i < pData->tokenPointerArray.size(); i++ )
				{
					const std::string tokenName( pData->tokenPointerArray[i].getTokenName() );
					if ( "P" == tokenName )
					{
						posAttr = i;
					}
					else if ( "radius" == tokenName )
					{
						radAttr = i;
					}
					else if ( "Cs" == tokenName )
					{
						colAttr = i;
					}
					else if ( "Os" == tokenName )
					{
						opacAttr = i;
					}
				}

				for ( unsigned i = 0; i < pData->m_numValidParticles; i++)
				{
					RiAttributeBegin();
					if ( colAttr != -1 )
					{
						RiColor( &((RtFloat*)pointerArray[colAttr])[i*3] );
					}
					if ( opacAttr != -1 )
					{
						RiOpacity( &((RtFloat*)pointerArray[opacAttr])[i*3] );
					}
					RiTransformBegin();
					RiTranslate(((RtFloat*)pointerArray[posAttr])[i*3+0],
						((RtFloat*)pointerArray[posAttr])[i*3+1],
						((RtFloat*)pointerArray[posAttr])[i*3+2]);

					RtFloat radius = ((RtFloat*)pointerArray[radAttr])[i];
					RiSphere(radius, -radius, radius, 360, RI_NULL);
					RiTransformEnd();
					RiAttributeEnd();
				}
			}
			break;

		case liqRibParticleData::MPTSprites: 
			{
				int posAttr   = -1,
					numAttr    = -1,
					twistAttr  = -1,
					scaleXAttr = -1,
					scaleYAttr = -1,
					colAttr    = -1,
					opacAttr   = -1;

				for ( unsigned i( 0 ); i < pData->tokenPointerArray.size(); i++ )
				{
					const std::string tokenName( pData->tokenPointerArray[i].getTokenName() );
					if ( "P" == tokenName )
					{
						posAttr = i;
					}
					else if ( "spriteNum" == tokenName )
					{
						numAttr = i;
					}
					else if ( "spriteTwist" == tokenName )
					{
						twistAttr = i;
					}
					else if ( "spriteScaleX" == tokenName )
					{
						scaleXAttr = i;
					}
					else if ( "spriteScaleY" == tokenName )
					{
						scaleYAttr = i;
					}
					else if ( "Cs" == tokenName )
					{
						colAttr = i;
					}
					else if ( "Os" == tokenName )
					{
						opacAttr = i;
					}
				}

				MVector camUp( 0, 1, 0 );
				MVector camRight( 1, 0, 0 );
				MVector camEye( 0, 0, 1 );

				camUp    *= currentJob__.camera[0].mat.inverse();
				camRight *= currentJob__.camera[0].mat.inverse();
				camEye   *= currentJob__.camera[0].mat.inverse();

				for( unsigned ui( 0 ); ui < pData->m_numValidParticles; ui++ ) 
				{
					MVector up( camUp );
					MVector right( camRight );

					float spriteRadiusX( 0.5 );
					float spriteRadiusY( 0.5 );
					RiAttributeBegin();

					RiArchiveRecord( RI_COMMENT, "normal has to be reversed to show the Sprite particles. //  [10/9/2012 yaoyansi]" );
					RiReverseOrientation();

					if ( -1 != colAttr ) 
						RiColor( &( ( RtFloat* )pointerArray[ colAttr ] )[ ui * 3 ] );

					if ( -1 != opacAttr ) 
						RiOpacity( &( ( RtFloat* )pointerArray[ opacAttr ] )[ ui * 3 ] );

					if ( -1 != twistAttr ) 
					{
						float twist( -( ( RtFloat* )pointerArray[ twistAttr ] )[ ui ] * M_PI / 180 );
						MQuaternion twistQ( twist, camEye );
						right = camRight.rotateBy( twistQ );
						up    = camUp.rotateBy( twistQ );
					}

					if ( scaleXAttr != -1 ) 
						spriteRadiusX *= ( ( RtFloat* )pointerArray[ scaleXAttr ] )[ ui ];

					if ( scaleYAttr != -1 ) 
						spriteRadiusY *= ( ( RtFloat* )pointerArray[ scaleYAttr ] )[ ui ];

					if ( posAttr != -1 ) 
					{
						float *P( &( ( RtFloat* ) pointerArray[ posAttr ] )[ ui * 3 ] );
						float spriteNumPP = 0;
						if ( numAttr != -1 ) 
							spriteNumPP = ( ( RtFloat* )pointerArray[ numAttr ] )[ ui ];

						float x0 = P[ 0 ] - spriteRadiusX * right[ 0 ] + spriteRadiusY * up[ 0 ];
						float y0 = P[ 1 ] - spriteRadiusX * right[ 1 ] + spriteRadiusY * up[ 1 ];
						float z0 = P[ 2 ] - spriteRadiusX * right[ 2 ] + spriteRadiusY * up[ 2 ];
						float x1 = P[ 0 ] + spriteRadiusX * right[ 0 ] + spriteRadiusY * up[ 0 ];
						float y1 = P[ 1 ] + spriteRadiusX * right[ 1 ] + spriteRadiusY * up[ 1 ];
						float z1 = P[ 2 ] + spriteRadiusX * right[ 2 ] + spriteRadiusY * up[ 2 ];
						float x2 = P[ 0 ] - spriteRadiusX * right[ 0 ] - spriteRadiusY * up[ 0 ];
						float y2 = P[ 1 ] - spriteRadiusX * right[ 1 ] - spriteRadiusY * up[ 1 ];
						float z2 = P[ 2 ] - spriteRadiusX * right[ 2 ] - spriteRadiusY * up[ 2 ];
						float x3 = P[ 0 ] + spriteRadiusX * right[ 0 ] - spriteRadiusY * up[ 0 ];
						float y3 = P[ 1 ] + spriteRadiusX * right[ 1 ] - spriteRadiusY * up[ 1 ];
						float z3 = P[ 2 ] + spriteRadiusX * right[ 2 ] - spriteRadiusY * up[ 2 ];

						float patch[ 12 ] = { x0, y0, z0,
							x1, y1, z1,
							x2, y2, z2,
							x3, y3, z3 };
						// !!! if not GENERIC_RIBLIB use RiPatch( "bilinear", "P", &patch, "float spriteNum", &spriteNum, RI_NULL );                                  
						// RiPatch( "bilinear", "P", &patch, "float spriteNum", (RtFloat*)&spriteNumPP, RI_NULL );
						// Patch "bilinear"  "P" [0.446265 0.316269 -0.647637 1.27725 0.316269 -1.20393 0.615752 -0.636188 -0.39446 1.44674 -0.636188 -0.950756 ]  "float spriteNum" [2 0 0 0 ]
						RiArchiveRecord( RI_VERBATIM, "Patch \"bilinear\" \"P\" [%f %f %f %f %f %f %f %f %f %f %f %f] \"float spriteNum\" [%f]", 
							x0, y0, z0,x1, y1, z1, x2, y2, z2,x3, y3, z3,
							spriteNumPP ); 
					} 
					else {
						RiIdentity();
					}
					RiAttributeEnd();
				}//for
			}
			break;

#endif // #ifndef DELIGHT


		case liqRibParticleData::MPTCloudy:
			{
				int posAttr  = -1,
					radAttr  = -1,
					colAttr  = -1,
					opacAttr = -1,
					rotAttr  = -1;

				for ( unsigned i = 0; i < pData->tokenPointerArray.size(); i++ )
				{
					const std::string tokenName( pData->tokenPointerArray[i].getTokenName() );
					if ( "P" == tokenName )
					{
						posAttr = i;
					}
					else if ( "radius" == tokenName )
					{
						radAttr = i;
					}
					else if ( "Cs" == tokenName )
					{
						colAttr = i;
					}
					else if ( "Os" == tokenName )
					{
						opacAttr = i;
					}
					else if ( "rotation" == tokenName )
					{
						rotAttr = i;
					}
				}
				// Build an array that can be given to RiBlobby
				std::vector< RtString > stringArray;
				for( unsigned int i(0); i < pData->m_stringArray.size(); i++ ) {
					stringArray.push_back( const_cast<char *>( pData->m_stringArray[i].c_str()) );
				}
				if(stringArray.size()==0)//added by yaoyansi, or it leads a crash on windows
					stringArray.push_back( "" );

				boost::scoped_array< RtToken > ithTokenArray( new RtToken[ numTokens ] );
				boost::scoped_array< RtPointer > ithPointerArray( new RtPointer[ numTokens ] );

				for ( unsigned i = 0; i < pData->m_numValidParticles; i++)
				{
					assignIthTokenArraysV( pData->tokenPointerArray, ithTokenArray.get(), ithPointerArray.get(), i );
					RiAttributeBegin();
					if ( colAttr != -1 )
					{
						RiColor( &((RtFloat*)pointerArray[colAttr])[i*3] );
					}
					if ( opacAttr != -1 )
					{
						RiOpacity( &((RtFloat*)pointerArray[opacAttr])[i*3] );
					}
					RiTransformBegin();
					RiTranslate(((RtFloat*)pointerArray[posAttr])[i*3+0],
						((RtFloat*)pointerArray[posAttr])[i*3+1],
						((RtFloat*)pointerArray[posAttr])[i*3+2]);

					if ( rotAttr != -1 )
					{
						RiRotate( (( RtFloat *) pointerArray[rotAttr])[i*3] * 360.0, 1.0, 0.0, 0.0 );
						RiRotate( (( RtFloat *) pointerArray[rotAttr])[i*3+1] * 360.0, 0.0, 1.0, 0.0 );
						RiRotate( (( RtFloat *) pointerArray[rotAttr])[i*3+2] * 360.0, 0.0, 0.0, 1.0 );
					}

					RtFloat radius = ((RtFloat*)pointerArray[radAttr])[i];
					RiScale( radius, radius, radius );
					//RiSphere(radius, -radius, radius, 360, RI_NULL);
					float dummy[] = { 0.0, 0.0, 0.0 }; // Worst case : three floats are needed
					RiBlobbyV( 1,
						pData->m_codeArray.size(), const_cast< RtInt* >( &pData->m_codeArray[0] ),
						pData->m_floatArray.size(), const_cast< RtFloat* >( &pData->m_floatArray[0] ),
						stringArray.size(), const_cast< RtString* >( &stringArray[0] ),
						numTokens, ithTokenArray.get(), ithPointerArray.get() );
//						"vertex color incandescence", (RtPointer *)( dummy ),
//						"vertex color Cs", (RtPointer *)( dummy ),
//						"vertex float selfshadow", (RtPointer *)( dummy ),
//						RI_NULL );
					RiTransformEnd();
					RiAttributeEnd();

				}
				break;
			}
		case liqRibParticleData::MPTNumeric:
			RiArchiveRecord( RI_COMMENT, "Numeric Particles are not supported" );
			break;
		case liqRibParticleData::MPTTube:
			RiArchiveRecord( RI_COMMENT, "Tube Particles are not supported" );
			break;

			break;
		}
	}
	int Renderer::preview( const std::string& fileName, const liqPreviewShaderOptions& options )
	{
		CM_TRACE_FUNC("Renderer::preview("<<fileName<<","<<options.shaderNodeName<<")");

		  std::string shaderFileName;
  liqShader currentShader;
  MObject	shaderObj;
  MString shader_type_TempForRefactoring;//  [2/14/2012 yaoyansi]

  if ( options.fullShaderPath ) 
  {
	  // a full shader path was specified
	  //cout <<"[liquid] got full path for preview !"<<endl;
	  //shaderFileName = const_cast<char*>(options.shaderNodeName);

	  std::string tmp( options.shaderNodeName );
	  currentShader.setShaderFileName(tmp.substr( 0, tmp.length() -  4 ) );

	  if ( options.type == "surface" ){
		  assert(0&&"we should use currentShader.shader_type_ex = \"surface\"");
		  //currentShader.shader_type = SHADER_TYPE_SURFACE;//  [2/14/2012 yaoyansi]
		  shader_type_TempForRefactoring = "surface";
	  }else if ( options.type == "displacement" ){
		  assert(0&&"we should use currentShader.shader_type_ex = \"displacement\"");
		  //currentShader.shader_type = SHADER_TYPE_DISPLACEMENT;//  [2/14/2012 yaoyansi]
		  shader_type_TempForRefactoring = "displacement";
	  }
	  //cout <<"[liquid]   options.shaderNodeName = " << options.shaderNodeName << endl;
	  //cout <<"[liquid]   options.type = "<<options.type<<endl;
  } 
  else 
  {
	  // a shader node was specified
	  MSelectionList shaderNameList;
	  shaderNameList.add( options.shaderNodeName.c_str() );
	  shaderNameList.getDependNode( 0, shaderObj );
	  if( shaderObj == MObject::kNullObj )
	  {
		  MGlobal::displayError( std::string( "Can't find node for " + options.shaderNodeName ).c_str() );
		  RiEnd();
		  return 0;
	  }
	  currentShader = liqShader( shaderObj );
	  shader_type_TempForRefactoring = currentShader.shader_type_ex;
	  shaderFileName = currentShader.getShaderFileName();
  }
  MFnDependencyNode assignedShader( shaderObj );


  // Get the Pathes in globals node
  MObject globalObjNode;
  MString liquidShaderPath = "",liquidTexturePath = "",liquidProceduralPath = "";
  MStatus status;
  MSelectionList globalList;
	
	// get the current project directory
  MString MELCommand = "workspace -q -rd";
  MString MELReturn;
  MGlobal::executeCommand( MELCommand, MELReturn );
  MString liquidProjectDir = MELReturn;
	
  status = globalList.add( "liquidGlobals" );
  if ( globalList.length() > 0 ) 
	{
    status.clear();
    status = globalList.getDependNode( 0, globalObjNode );
    MFnDependencyNode globalNode( globalObjNode );
		liquidGetPlugValue( globalNode, "shaderPath", liquidShaderPath, status);
    liquidGetPlugValue( globalNode, "texturePath", liquidTexturePath, status);
    liquidGetPlugValue( globalNode, "proceduralPath", liquidProceduralPath, status);
  }
  if( fileName.empty() ) 
	{
    RiBegin_liq( NULL );
#ifdef DELIGHT
    //RtPointer callBack( progressCallBack );
    //RiOption( "statistics", "progresscallback", &callBack, RI_NULL );
#endif
  } 
	else {
	liquidMessage2(messageInfo,"preview rib file: [%s]", fileName.c_str());
    RiBegin_liq( (RtToken)fileName.c_str() );
  }

  std::string liquidHomeDir = liquidSanitizeSearchPath( getEnvironment( "LIQUIDHOME" ) );
  std::string shaderPath( "&:@:.:~:" + liquidHomeDir + "/lib/shaders" );
  std::string texturePath( "&:@:.:~:" + liquidHomeDir + "/lib/textures" );
  std::string proceduralPath( "&:@:.:~:" + liquidHomeDir + "/lib/shaders" );

  std::string projectDir = std::string( liquidSanitizeSearchPath( liquidProjectDir ).asChar() );
  if ( liquidProjectDir != "")
  {
    shaderPath += ":" + projectDir;	
    texturePath += ":" + projectDir;
    proceduralPath += ":" + projectDir;
  }
  if ( liquidShaderPath != "" )
		shaderPath += ":" + std::string( liquidSanitizeSearchPath( parseString( liquidShaderPath, false ) ).asChar());	
  if ( liquidTexturePath != "" )
		texturePath += ":" + std::string( liquidSanitizeSearchPath( parseString( liquidTexturePath, false) ).asChar());	
  if ( liquidProceduralPath != "" )
		proceduralPath += ":" + std::string( liquidSanitizeSearchPath( parseString( liquidProceduralPath, false) ).asChar());	
	
  RtString list( const_cast< RtString >( shaderPath.c_str() ) );
  RiOption( "searchpath", "shader", &list, RI_NULL );
	
  RtString texPath( const_cast< RtString >( texturePath.c_str() ) );
  if( texPath[ 0 ] )
    RiOption( "searchpath","texture", &texPath, RI_NULL );
	
  RtString procPath( const_cast< RtString >( proceduralPath.c_str() ) );
  
  if( procPath[ 0 ] )
    RiOption( "searchpath","procedural", &procPath, RI_NULL );

  RiShadingRate( ( RtFloat )options.shadingRate );
  RiPixelSamples( options.pixelSamples, options.pixelSamples );

#ifdef PRMAN
  if ( MString( "PRMan" ) == liqglo.liquidRenderer.renderName )
	RiPixelFilter( RiCatmullRomFilter, 4., 4. );
#elif defined( DELIGHT )
  if ( MString( "3Delight" ) == liqglo.liquidRenderer.renderName )
    RiPixelFilter( RiSeparableCatmullRomFilter, 4., 4. );
//    RiPixelFilter( RiMitchellFilter, 4., 4.);
#else
  RiPixelFilter( RiCatmullRomFilter, 4., 4. );
#endif

  RiFormat( ( RtInt )options.displaySize, ( RtInt )options.displaySize, 1.0 );
  if( options.backPlane ) 
	{
    RiDisplay( const_cast< RtString >( options.displayName.c_str() ),
               const_cast< RtString >( options.displayDriver.c_str() ), RI_RGB, RI_NULL );
  } 
	else 
	{ // Alpha might be useful
    RiDisplay( const_cast< RtString >( options.displayName.c_str() ),
               const_cast< RtString >( options.displayDriver.c_str() ), RI_RGBA, RI_NULL );
  }
  RtFloat fov( 22.5 );
  RiProjection( "perspective", "fov", &fov, RI_NULL );
  RiTranslate( 0, 0, 2.75 );
  RiExposure(1, currentShader.m_previewGamma);
  
  RtInt visible = 1;
  RtString transmission = "transparent";

  RiAttribute( "visibility", ( RtToken ) "camera", &visible, RI_NULL );
  RiAttribute( "visibility",  ( RtToken ) "trace", &visible, RI_NULL );
  // RiAttribute( "visibility", ( RtToken ) "transmission", ( RtPointer ) &transmission, RI_NULL );
  
  RiWorldBegin();
  RiReverseOrientation();
  RiTransformBegin();
  RiRotate( -90., 1., 0., 0. );
  RiCoordinateSystem( "_environment" );
  RiTransformEnd();
  RtLightHandle ambientLightH, directionalLightH;
  RtFloat intensity;
  intensity = 0.05 * (RtFloat)options.previewIntensity;
  ambientLightH = RiLightSource( "ambientlight", "intensity", &intensity, RI_NULL );
  intensity = 0.9 * (RtFloat)options.previewIntensity;
  RtPoint from;
  RtPoint to;
  from[0] = -1.; from[1] = 1.5; from[2] = -1.;
  to[0] = 0.; to[1] = 0.; to[2] = 0.;
  RiTransformBegin();
    RiRotate( 55.,  1, 0, 0 );
    RiRotate( 30.,  0, 1, 0 );
    directionalLightH = RiLightSource( "liquiddistant", "intensity", &intensity, RI_NULL );
  RiTransformEnd();
  intensity = 0.2f * (RtFloat)options.previewIntensity;
  from[0] = 1.3f; from[1] = -1.2f; from[2] = -1.;
  RiTransformBegin();
    RiRotate( -50.,  1, 0, 0 );
    RiRotate( -40.,  0, 1, 0 );
    directionalLightH = RiLightSource( "liquiddistant", "intensity", &intensity, RI_NULL );
  RiTransformEnd();

  RiAttributeBegin();


  //ymesh omit this section, because liqShader::writeRibAttributes() do this work in that branch
  //I don't use liqShader::writeRibAttributes(), so I use this section. -yayansi
  float displacementBounds = 0.;
	liquidGetPlugValue( assignedShader, "displacementBound", displacementBounds, status);
  
  if ( displacementBounds > 0. ) 
	{
    RtString coordsys = "shader";
	RiArchiveRecord( RI_COMMENT, "ymesh omit this section, because liqShader::writeRibAttributes do this work in that branch" );
    RiAttribute( "displacementbound", "coordinatesystem", &coordsys, RI_NULL );	
    RiAttribute( "displacementbound", "sphere", &displacementBounds, "coordinatesystem", &coordsys, RI_NULL );
  }

  //LIQ_GET_SHADER_FILE_NAME( shaderFileName, options.shortShaderName, currentShader );

	// output shader space
  MString shadingSpace;
	liquidGetPlugValue( assignedShader, "shaderSpace", shadingSpace, status);
  
  if ( shadingSpace != "" ) 
	{
    RiTransformBegin();
    RiCoordSysTransform( (char*) shadingSpace.asChar() );
  }

  RiTransformBegin();
  // Rotate shader space to make the preview more interesting
  RiRotate( 60., 1., 0., 0. );
  RiRotate( 60., 0., 1., 0. );
  RtFloat scale( 1.f / ( RtFloat )options.objectScale );
  RiScale( scale, scale, scale );

  if ( shader_type_TempForRefactoring=="surface" || shader_type_TempForRefactoring=="shader"/*currentShader.shader_type == SHADER_TYPE_SURFACE || currentShader.shader_type == SHADER_TYPE_SHADER */ ) //  [2/14/2012 yaoyansi]
	{
		RiColor( currentShader.rmColor );
		RiOpacity( currentShader.rmOpacity );
		//cout << "Shader: " << shaderFileName << endl;
		if ( options.fullShaderPath ) 
				RiSurface( (RtToken)shaderFileName.c_str(), RI_NULL );
		else
		{
			liqShader liqAssignedShader( shaderObj );
			liqAssignedShader.forceAs = SHADER_TYPE_SURFACE;
			liqAssignedShader.write();
		}
  } 
	else if ( shader_type_TempForRefactoring=="displacement"/*currentShader.shader_type == SHADER_TYPE_DISPLACEMENT*/ ) //  [2/14/2012 yaoyansi]
	{
		RtToken Kd( "Kd" );
		RtFloat KdValue( 1. );
#ifdef GENERIC_RIBLIB    
    // !!! current ribLib has wrong interpretation of RiSurface parameters 
    RiSurface( "plastic", Kd, &KdValue, RI_NULL );
#else
		RiSurface( "plastic", &Kd, &KdValue, RI_NULL );
#endif    
		if ( options.fullShaderPath ) 
			RiDisplacement( (RtToken)shaderFileName.c_str(), RI_NULL );
		else 
		{
			liqShader liqAssignedShader( shaderObj );
			liqAssignedShader.forceAs = SHADER_TYPE_DISPLACEMENT;
			liqAssignedShader.write();
		}
  }
  RiTransformEnd();
  if ( shadingSpace != "" ) 
		RiTransformEnd();

 switch( options.primitiveType ) 
 {
    case CYLINDER: 
		{
      RiReverseOrientation();
      RiScale( 0.95, 0.95, 0.95 );
      RiRotate( 60., 1., 0., 0. );
      RiTranslate( 0., 0., -0.05 );
      RiCylinder( 0.5, -0.3, 0.3, 360., RI_NULL );
      RiTranslate( 0., 0., 0.3f );
      RiTorus( 0.485, 0.015, 0., 90., 360., RI_NULL );
      RiDisk( 0.015, 0.485, 360., RI_NULL );
      RiTranslate( 0., 0., -0.6 );
      RiTorus( 0.485, 0.015, 270., 360., 360., RI_NULL );
      RiReverseOrientation();
      RiDisk( -0.015, 0.485, 360., RI_NULL );
      break;
    }
    case TORUS: 
		{
      RiRotate( 45., 1., 0., 0. );
      RiTranslate( 0., 0., -0.05 );
      RiReverseOrientation();
      RiTorus( 0.3f, 0.2f, 0., 360., 360., RI_NULL );
      break;
    }
    case PLANE: 
		{
      RiScale( 0.5, 0.5, 0.5 );
      RiReverseOrientation();
      static RtPoint plane[4] = {
        { -1.,  1.,  0. },
        {  1.,  1.,  0. },
        { -1., -1.,  0. },
        {  1., -1.,  0. }
      };
      RiPatch( RI_BILINEAR, RI_P, (RtPointer) plane, RI_NULL );
      break;
    }
    case TEAPOT: 
		{
      RiTranslate( 0.06f, -0.18f, 0. );
      RiRotate( -120., 1., 0., 0. );
      RiRotate( 130., 0., 0., 1. );
      RiScale( 0.2f, 0.2f, 0.2f );
			RiArchiveRecord( RI_VERBATIM, "Geometry \"teapot\"" );
      break;
    }
    case CUBE: 
		{
      /* Lovely cube with rounded corners and edges */
      RiScale( 0.35f, 0.35f, 0.35f );
      RiRotate( 60., 1., 0., 0. );
      RiRotate( 60., 0., 0., 1. );

      RiTranslate( 0.11f, 0., -0.08f );

      RiReverseOrientation();

      static RtPoint top[ 4 ] = { { -0.95, 0.95, -1. }, { 0.95, 0.95, -1. }, { -0.95, -0.95, -1. },  { 0.95, -0.95, -1. } };
      RiPatch( RI_BILINEAR, RI_P, ( RtPointer ) top, RI_NULL );

      static RtPoint bottom[ 4 ] = { { 0.95, 0.95, 1. }, { -0.95, 0.95, 1. }, { 0.95, -0.95, 1. }, { -0.95, -0.95, 1. } };
      RiPatch( RI_BILINEAR, RI_P, ( RtPointer ) bottom, RI_NULL );

      static RtPoint right[ 4 ] = { { -0.95, -1., -0.95 }, { 0.95, -1., -0.95 }, { -0.95, -1., 0.95 }, { 0.95, -1., 0.95 } };
      RiPatch( RI_BILINEAR, RI_P, ( RtPointer ) right, RI_NULL );

      static RtPoint left[ 4 ] = { { 0.95, 1., -0.95 }, { -0.95, 1., -0.95 }, { 0.95, 1., 0.95 }, { -0.95, 1., 0.95 } };
      RiPatch( RI_BILINEAR, RI_P, ( RtPointer ) left, RI_NULL );

      static RtPoint front[ 4 ] = { {-1., 0.95, -0.95 }, { -1., -0.95, -0.95 }, { -1., 0.95, 0.95 }, { -1., -0.95, 0.95 } };
      RiPatch( RI_BILINEAR, RI_P, ( RtPointer ) front, RI_NULL );

      static RtPoint back[ 4 ] = { { 1., -0.95, -0.95 }, { 1., 0.95, -0.95 }, { 1., -0.95, 0.95 }, { 1., 0.95, 0.95 } };
      RiPatch( RI_BILINEAR, RI_P, ( RtPointer ) back, RI_NULL );

      RiTransformBegin();
      RiTranslate( 0.95, 0.95, 0. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( 0.95, -0.95, 0. );
      RiRotate( -90., 0., 0., 1. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( -0.95, 0.95, 0. );
      RiRotate( 90., 0., 0., 1. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( -0.95, -0.95, 0. );
      RiRotate( 180., 0., 0., 1. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( 0., 0., 0.95 );

      RiTransformBegin();

      RiTransformBegin();
      RiTranslate( 0.95, 0.95, 0. );
      RiSphere( 0.05, 0., 0.05, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( 0.95, -0.95, 0. );
      RiRotate( -90., 0., 0., 1. );
      RiSphere( 0.05, 0., 0.05, 90., RI_NULL );
      RiTransformEnd();

      RiRotate( 180., 0., 0., 1. );

      RiTransformBegin();
      RiTranslate( 0.95, 0.95, 0. );
      RiSphere( 0.05, 0., 0.05, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( 0.95, -0.95, 0. );
      RiRotate( -90., 0., 0., 1. );
      RiSphere( 0.05, 0., 0.05, 90., RI_NULL );
      RiTransformEnd();

      RiTransformEnd();

      RiRotate( 90., 1., 0., 0. );

      RiTransformBegin();
      RiTranslate( 0.95, 0., 0. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( -0.95, 0., 0. );
      RiRotate( 90., 0., 0., 1. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiRotate( 90., 0., 1., 0. );

      RiTransformBegin();
      RiTranslate( 0.95, 0.,  0. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( -0.95, 0., 0. );
      RiRotate( 90., 0., 0., 1. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( 0., 0., -0.95 );

      RiTransformBegin();

      RiTransformBegin();
      RiTranslate( 0.95, 0.95, 0. );
      RiSphere( 0.05, -0.05, 0., 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( 0.95, -0.95, 0. );
      RiRotate( -90., 0., 0., 1. );
      RiSphere( 0.05, -0.05, 0., 90., RI_NULL );
      RiTransformEnd();

      RiRotate( 180., 0., 0., 1. );

      RiTransformBegin();
      RiTranslate( 0.95, 0.95, 0. );
      RiSphere( 0.05, -0.05, 0., 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( 0.95, -0.95, 0. );
      RiRotate( -90., 0., 0., 1. );
      RiSphere( 0.05, -0.05, 0., 90., RI_NULL );
      RiTransformEnd();

      RiTransformEnd();

      RiRotate( 90., 1., 0., 0. );

      RiTransformBegin();
      RiTranslate( -0.95, 0.,  0. );
      RiRotate( 180., 0., 0., 1. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( 0.95, 0.,  0. );
      RiRotate( -90., 0., 0., 1. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiRotate( 90., 0., 1., 0. );

      RiTransformBegin();
      RiTranslate( 0.95, 0.,  0. );
      RiRotate( -90., 0., 0., 1. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformBegin();
      RiTranslate( -0.95, 0.,  0. );
      RiRotate( 180., 0., 0., 1. );
      RiCylinder( 0.05, -0.95, 0.95, 90., RI_NULL );
      RiTransformEnd();

      RiTransformEnd();

      break;
    }
    case CUSTOM: 
		{
      //cout <<"custom : "<<options.customRibFile<<endl;
      if ( fileExists( options.customRibFile.c_str() ) ) 
			{
        RiReadArchive( const_cast< RtToken >( options.customRibFile.c_str() ), NULL, RI_NULL );
      }
      break;
    }
    case SPHERE:
    default: 
		{
      RiRotate( 60., 1., 0., 0. );
      RiReverseOrientation();
      RiSphere( 0.5, -0.5, 0.5, 360., RI_NULL );
      break;
    }
  }

  RiAttributeEnd();
  /*
   * Backplane
   */
  if( options.backPlane ) 
	{
    if ( options.customBackplane.empty() ) 
		{
      RiAttributeBegin();
      RiScale( 0.91, 0.91, 0.91 );
      if( MString("displacement")==shader_type_TempForRefactoring/*SHADER_TYPE_DISPLACEMENT == currentShader.shader_type*/ ) //  [2/14/2012 yaoyansi]
			{
        RtColor bg = { 0.698, 0.698, 0. };
        RiColor( bg );
      } else 
        RiSurface( const_cast< RtToken >( options.backPlaneShader.c_str() ), RI_NULL );




      static RtPoint backplane[4] = {
        { -1.,  1.,  2. },
        {  1.,  1.,  2. },
        { -1., -1.,  2. },
        {  1., -1.,  2. }
      };
      RiPatch( RI_BILINEAR, RI_P, (RtPointer) backplane, RI_NULL );
      RiAttributeEnd();
    } 
		else 
		{
      if ( fileExists( options.customBackplane.c_str() ) ) 
			{
        RiAttributeBegin();
          RiScale( 1., 1., -1. );
          RiReadArchive( const_cast< RtString >( options.customBackplane.c_str() ), NULL, RI_NULL );
        RiAttributeEnd();
      }
    }
  }

  RiWorldEnd();

/* this caused maya to hang up under windoof - Alf
#ifdef _WIN32
//	Wait until the renderer is done
	while( !fileFullyAccessible( options.displayName.c_str() ) );
#endif
*/
  RiEnd();
  if(liqglo.m_logMsgFlush)
  {
	fflush( NULL );
  }
	}
void Visitor::visitFile(const char* node)
{
	CM_TRACE_FUNC("Visitor::visitFile("<<node<<")");

	OutputHelper o;

	//generate texture and construct texture node
	MString fileImageName(getFileNodeImageName(node));
	{
		//test "fileImageName" exist or not.
		if( access(fileImageName.asChar(), 0) != 0){
			liquidMessage2(messageError,"%s not exist!", fileImageName.asChar());
			assert(0&&"image not exist.");
		}

		bool isERTex;//whether fileImageName is ER texture
		{
			std::string fileImageName_(fileImageName.asChar());
			std::size_t i_last_dot = fileImageName_.find_last_of('.');
			if( i_last_dot == std::string::npos ){
				liquidMessage2(messageWarning,"%s has no extention!", fileImageName_.c_str());
				assert(0&&"warrning: texture name has not extention.");
			}
			std::string imgext(fileImageName_.substr(i_last_dot+1));//imgext=tex
			std::transform(imgext.begin(),imgext.end(),imgext.begin(),tolower);
		
			isERTex = (imgext == "tex");
		}

		MString fileTextureName = (isERTex)? fileImageName : (fileImageName+".tex");

		//generate texture
		if ( access(fileTextureName.asChar(), 0) != 0 )//not exist
		{
			ei_make_texture(fileImageName.asChar(), fileTextureName.asChar(),
				EI_TEX_WRAP_CLAMP, EI_TEX_WRAP_CLAMP, EI_FILTER_BOX, 1.0f, 1.0f);
		}
		//construct texture node
		//if (ei_file_exists(fileTextureName))
		{
			ei_texture(fileImageName.asChar());
				ei_file_texture(fileTextureName.asChar(), eiFALSE);
			ei_end_texture();
		}
	}


	o.beginRSL(node);

	ei_shader_param_string("desc", "maya_file");
	//input
	o.addRSLVariable("float",  "alphaGain",	"alphaGain",	node);
	o.addRSLVariable("bool",  "alphaIsLuminance",	"alphaIsLuminance",	node);
	o.addRSLVariable("float",  "alphaOffset",	"alphaOffset",	node);
	o.addRSLVariable("color",  "colorGain",	"colorGain",	node);
	o.addRSLVariable("color",  "colorOffset",	"colorOffset",	node);
	o.addRSLVariable("color",  "defaultColor",	"defaultColor",	node);
	o.addRSLVariable("vector",  "uvCoord",	"uvCoord",	node);
	ei_shader_param_texture("fileTextureName", fileImageName.asChar());
	o.addRSLVariable("index", "filterType",	"filterType",	node);
	o.addRSLVariable("float",  "filter",	"filter",	node);
	o.addRSLVariable("float",  "filterOffset",	"filterOffset",	node);
	o.addRSLVariable("bool",  "invert",	"invert",	node);
	o.addRSLVariable("bool",  "fileHasAlpha",	"fileHasAlpha",	node);
	//o.addRSLVariable("index", "num_channels",	"num_channels",	node);
	//output
	o.addRSLVariable("float", "outAlpha",	"outAlpha",	node);
	o.addRSLVariable("color", "outColor",	"outColor",	node);
	o.addRSLVariable("color", "outTransparency",	"outTransparency",	node);
	o.endRSL();
}
	void Helper4::endBSDF()
	{
		if(m_assembly->bsdfs().get_by_name(m_nodename.c_str()) == nullptr)
		{
			if("ashikhmin_brdf"==m_bsdf_model)
			{
				m_assembly->bsdfs().insert(
					asr::AshikhminBRDFFactory().create(
					m_nodename.c_str(),
					m_bsdf_params
					)
					);
			}
			else if("kelemen_brdf"==m_bsdf_model)
			{
				m_assembly->bsdfs().insert(
					asr::KelemenBRDFFactory().create(
					m_nodename.c_str(),
					m_bsdf_params
					)
				);
			}
			else if("lambertian_brdf"==m_bsdf_model)
			{
				m_assembly->bsdfs().insert(
					asr::LambertianBRDFFactory().create(
					m_nodename.c_str(),
					m_bsdf_params
					)
				);
			}
			else if("specular_brdf"==m_bsdf_model)
			{
				m_assembly->bsdfs().insert(
					asr::SpecularBRDFFactory().create(
					m_nodename.c_str(),
					m_bsdf_params
					)
				);
			}
			else if("bsdf_mix"==m_bsdf_model)
			{
				m_assembly->bsdfs().insert(
					asr::BSDFMixFactory().create(
					m_nodename.c_str(),
					m_bsdf_params
					)
				);
			}
			else if("specular_btdf"==m_bsdf_model)
			{
				m_assembly->bsdfs().insert(
					asr::SpecularBTDFFactory().create(
					m_nodename.c_str(),
					m_bsdf_params
					)
				);
			}
			else{
				liquidMessage2( messageError, "[%s] is not implemented yet.", m_bsdf_model.c_str() );

			}
		}
	}
	void Helper4::addVariableSS(const std::string& param_name_as, const std::string& param_type_as, const std::string& param_name_maya )
	{
		//std::string ss_name(getSurfaceShaderName(m_nodename,m_ss_model));

		asr::ParamArray ss_params;
		{
			std::string param_value;
			const std::string plugName(param_name_maya);

			MString fullPlugName((m_nodename+"."+plugName).c_str());
			int connected = liquidmaya::ShaderMgr::getSingletonPtr()->convertibleConnection(fullPlugName.asChar());
			if(connected ==0)
			{
				if( isType("color", param_type_as) )
				{
					MDoubleArray val; 
					val.setLength(3);
					IfMErrorWarn(MGlobal::executeCommand("getAttr (\""+fullPlugName+"\")", val));

					param_value = m_nodename+"_"+plugName;
					createColor3(m_assembly->colors(), param_value.c_str(), val[0], val[1], val[2]);
				}
				else if( isType("scalar", param_type_as) )
				{
					MDoubleArray val; 
					val.setLength(3);
					IfMErrorWarn(MGlobal::executeCommand("getAttr (\""+fullPlugName+"\")", val));

					//val contains (r,b,g) value, but I only use val[0] for 'scalar'
					MString strVal0;
					strVal0.set(val[0]);
					param_value = strVal0.asChar();
				}
				else if( isType("string", param_type_as))
				{
					MString val;
					IfMErrorWarn(MGlobal::executeCommand("getAttr (\""+fullPlugName+"\")", val));
					param_value = val.asChar();
				}
				else {
					liquidMessage2(messageWarning,"only [color],[scalar],[string] are handled for an unconnected plug in Surface Shader. "
						"the plug of %s is unhandled.", fullPlugName.asChar());
					param_value = "unhandled";
				}
			}
			else if(connected == 1)//the plug is linked in.
			{
				if( isType("texture_instance", param_type_as) )
				{
					MStringArray srcPlug;
					IfMErrorWarn(MGlobal::executeCommand("listConnections -source true -plugs true \""+fullPlugName+"\"", srcPlug));
					assert(srcPlug.length()==1);
					MStringArray src;
					srcPlug[0].split('.',src);
					MString srcNode(src[0]);

					if( is2DTexture(srcNode) || is3DTexture(srcNode) )
					{
						//visitFile(srcNode.asChar());
						param_value = getTextureInstanceName(srcNode.asChar());
					}else{
						liquidMessage2(messageWarning,"only [texture2D],[texture3D] are handled for a texture_instance connected-in plug in Surface Shader."
							"the plug of %s is unhandled.", fullPlugName.asChar());
						param_value = "unhandled";
					}
				}
				else{
					liquidMessage2(messageWarning,"only [texture_instance] is handled for a connected-in plug in Surface Shader."
						"the plug of %s is unhandled.", fullPlugName.asChar());
					param_value = "unhandled";
				}
			}else{
				liquidMessage2(messageWarning,"[%s] is connected out.", fullPlugName.asChar());
			}
			//
			addVariableSS(param_name_as, param_value);
		}
	}
	void Helper4::addVariableBSDF( const std::string& param_name_as, const std::string& param_type_as, const std::string& param_name_maya )
	{
		std::string param_value;
		const std::string plugName(param_name_maya);

		MString fullPlugName((m_nodename+"."+plugName).c_str());
		int connected = liquidmaya::ShaderMgr::getSingletonPtr()->convertibleConnection(fullPlugName.asChar());
		if( connected == 0 )
		{
			if( isType("color", param_type_as) )
			{
				MDoubleArray val; 
				val.setLength(3);
				IfMErrorWarn(MGlobal::executeCommand("getAttr (\""+fullPlugName+"\")", val));

				param_value = m_nodename+"_"+plugName;
				createColor3(m_assembly->colors(), param_value.c_str(), val[0], val[1], val[2]);
			}
			else if( isType("scalar", param_type_as) )
			{
				MDoubleArray val; 
				val.setLength(3);
				IfMErrorWarn(MGlobal::executeCommand("getAttr (\""+fullPlugName+"\")", val));

				//val contains (r,b,g) value, but I only use val[0] for 'scalar'
				MString strVal0;
				strVal0.set(val[0]);
				param_value = strVal0.asChar();
			}
			else {
				liquidMessage2(messageWarning,"only [color],[scalar] are handled for an unconnected plug in BSDF. "
					"the plug of %s is unhandled.", fullPlugName.asChar());
				param_value = "unhandled";
			}
		}
		else if(connected == 1)//the color plug is linked in.
		{
			if( isType("texture_instance", param_type_as) )
			{
				MStringArray srcPlug;
				IfMErrorWarn(MGlobal::executeCommand("listConnections -source true -plugs true \""+fullPlugName+"\"", srcPlug));
				assert(srcPlug.length()==1);
				MStringArray src;
				srcPlug[0].split('.',src);
				MString srcNode(src[0]);
				if( is2DTexture(srcNode) || is3DTexture(srcNode) )
				{
					//visitFile(srcNode.asChar());
					param_value = getTextureInstanceName(srcNode.asChar());
				}else{
					liquidMessage2(messageWarning,"type of [%s] is unhandled.(not 2Dtexture and 3Dtexture). [%s]", srcNode.asChar(), fullPlugName.asChar());
					param_value = "unhandled";
				}
			}
			else if( isType("bsdf", param_type_as) )
			{
				//bsdf0 value
				MString srcBSDFModel; 
				IfMErrorWarn(MGlobal::executeCommand("getAttr (\""+fullPlugName+"\")", srcBSDFModel));

				MStringArray srcPlug;
				IfMErrorWarn(MGlobal::executeCommand("listConnections -source true -plugs true \""+fullPlugName+"\"", srcPlug));
				assert(srcPlug.length()==1);
				MStringArray src;
				srcPlug[0].split('.',src);
				MString srcNode(src[0]);

				param_value = srcNode.asChar();
			}
			else{
				liquidMessage2(messageWarning,"only [texture_instance],[bsdf] are handled for a connected-in plug in BSDF."
					"the plug of %s is unhandled.", fullPlugName.asChar());
				param_value = "unhandled";
			}

		}else{// $(fullPlugName) is connected out
			// if $(fullPlugName) plug is connected out to "bsdf0"/"bsdf1" of a "bsdf_mix" node,
			// we also need to create this plug for appleseed

			// get destination node(s)
			MStringArray desNodePlug;
			IfMErrorWarn(MGlobal::executeCommand("listConnections -destination true -plugs true \""+fullPlugName+"\"", desNodePlug));
			
			// check whether $(fullPlugName) is connected to a BSDF node
			bool isConnectedToA_BSDFMixNode = false;
			MString desPlug;
			for(std::size_t i = 0; i< desNodePlug.length(); ++i)
			{
				MStringArray des;
				desNodePlug[i].split('.',des);
				MString desNode(des[0]);

				//destination node BSDF type
				MString desNodeBSDFType;
				IfMErrorWarn(MGlobal::executeCommand( "getAttr \""+desNode+".rmanShaderType\"", desNodeBSDFType));

				if(desNodeBSDFType == "bsdf_mix")
				{
					isConnectedToA_BSDFMixNode = true;
					desPlug = des[1];
				}
			}

			// if $(fullPlugName) is connected out to "bsdf0"/"bsdf1" of a "bsdf_mix" node
			// we also need to create this plug for appleseed
			if( isConnectedToA_BSDFMixNode && (desPlug=="bsdf0" ||desPlug=="bsdf1") )
			{
				if( isType("color", param_type_as) )
				{
					MDoubleArray val; 
					val.setLength(3);
					IfMErrorWarn(MGlobal::executeCommand("getAttr (\""+fullPlugName+"\")", val));

					param_value = m_nodename+"_"+plugName;
					createColor3(m_assembly->colors(), param_value.c_str(), val[0], val[1], val[2]);
				}
				else if( isType("scalar", param_type_as) )
				{
					MDoubleArray val; 
					val.setLength(3);
					IfMErrorWarn(MGlobal::executeCommand("getAttr (\""+fullPlugName+"\")", val));

					//val contains (r,b,g) value, but I only use val[0] for 'scalar'
					MString strVal0;
					strVal0.set(val[0]);
					param_value = strVal0.asChar();
				}
				else if( isType("texture_instance", param_type_as) )
				{
					MStringArray srcPlug;
					IfMErrorWarn(MGlobal::executeCommand("listConnections -source true -plugs true \""+fullPlugName+"\"", srcPlug));
					assert(srcPlug.length()==1);
					MStringArray src;
					srcPlug[0].split('.',src);
					MString srcNode(src[0]);
					if( is2DTexture(srcNode) || is3DTexture(srcNode) )
					{
						//visitFile(srcNode.asChar());
						param_value = getTextureInstanceName(srcNode.asChar());
					}else{
						liquidMessage2(messageWarning,"type of [%s] is unhandled.(not 2Dtexture and 3Dtexture). [%s]", srcNode.asChar(), fullPlugName.asChar());
						param_value = "unhandled";
					}
				}
				else {
					liquidMessage2(messageWarning,"only [color],[scalar],[texture_instance] are handled for an connected-out plug in BSDF. "
						"the plug of %s is unhandled.", fullPlugName.asChar());
					param_value = "unhandled";
				}
			}//if( nodetype=="bsdf_mix" && (desPlug=="bsdf0" ||desPlug=="bsdf1") )
			else {
				liquidMessage2(messageWarning,"[%s] is connected out. But not connected to brdf node, or not brdf0/brdf1 of a brdf node."
					" So I don't create the value for this plug.", fullPlugName.asChar());
			}
		}
		//
		addVariableBSDF(param_name_as, param_value);
	}
	void OutputESS::ei_triangle_list(const eiTag tab)
	{
		//CM_TRACE_FUNC("OutputESS::ei_triangle_list(tag)" );
		liquidMessage2(messageError,"OutputESS::ei_triangle_list(tab)");
		m_outputfile<<"triangle_list size=?"<<std::endl;
	}