/* ******************************************************************************
*  Function Name : instancePoint()
*
*  Description : Instance a point
*
*  Input Arguments : GU_Detail *inst_gdp, GU_Detail *mb_gdp
*
*  Return Value : int
*
***************************************************************************** */
int VRAY_clusterThis::instancePoint(GU_Detail * inst_gdp, GU_Detail * mb_gdp)
{

#ifdef DEBUG
   std::cout << "VRAY_clusterThis::instancePoint()" << std::endl;
#endif

   GEO_Point * ppt;

   ppt = inst_gdp->appendPointElement();
   ppt->setPos((float)myPointAttributes.myNewPos[0],
               (float)myPointAttributes.myNewPos[1],
               (float)myPointAttributes.myNewPos[2], 1.0);

   VRAY_clusterThis::setPointInstanceAttributes(inst_gdp, ppt);

   if(myDoMotionBlur == CLUSTER_MB_DEFORMATION) {
         ppt = mb_gdp->appendPointElement();
         ppt->setPos((float)myPointAttributes.myMBPos[0],
                     (float)myPointAttributes.myMBPos[1],
                     (float)myPointAttributes.myMBPos[2], 1.0);

         VRAY_clusterThis::setPointInstanceAttributes(mb_gdp, ppt);
      }

   if(myCVEX_Exec)
      VRAY_clusterThis::runCVEX(inst_gdp, mb_gdp, myCVEXFname, CLUSTER_CVEX_POINT);

   return 0;
}
/* ******************************************************************************
*  Function Name : instanceCube()
*
*  Description :
*
*  Input Arguments : GU_Detail *inst_gdp, GU_Detail *mb_gdp
*
*  Return Value : int
*
***************************************************************************** */
int VRAY_clusterThis::instanceCube(GU_Detail * inst_gdp, GU_Detail * mb_gdp)
{
#ifdef DEBUG
   std::cout << "VRAY_clusterThis::instanceCube()" << std::endl;
#endif

   GEO_Primitive * myCube;
   GEO_Point * ppt;
   UT_Matrix4 xform(1.0);
//   UT_XformOrder xformOrder(UT_XformOrder::TRS,  UT_XformOrder::XYZ);
   UT_Matrix3 rot_xform(1.0);
//   UT_Vector3 myDir = myPointAttributes.N;
   UT_Vector3 myUp = UT_Vector3(0,1,0);
   rot_xform.orient(myPointAttributes.N, myUp);
   xform = rot_xform;

   myCube = (GEO_Primitive *) inst_gdp->cube(
               myPointAttributes.myNewPos[0] - ((mySize[0] * myPointAttributes.pscale) / 2),
               myPointAttributes.myNewPos[0] + ((mySize[0] * myPointAttributes.pscale) / 2),
               myPointAttributes.myNewPos[1] - ((mySize[1] * myPointAttributes.pscale) / 2),
               myPointAttributes.myNewPos[1] + ((mySize[1] * myPointAttributes.pscale) / 2),
               myPointAttributes.myNewPos[2] - ((mySize[2] * myPointAttributes.pscale) / 2),
               myPointAttributes.myNewPos[2] + ((mySize[2] * myPointAttributes.pscale) / 2));

   for(int i=0; i < myCube->getVertexCount(); i++) {
         ppt = myCube->getVertexElement(i).getPt();
         UT_Vector4  P = ppt->getPos();
         P *= xform;
         ppt->setPos(P);
      }

   VRAY_clusterThis::setInstanceAttributes(myCube);

   if(myDoMotionBlur == CLUSTER_MB_DEFORMATION) {

         myCube = (GEO_Primitive *) mb_gdp->cube(myPointAttributes.myMBPos[0] - ((mySize[0] * myPointAttributes.pscale) / 2),
                                                 myPointAttributes.myMBPos[0] + ((mySize[0] * myPointAttributes.pscale) / 2),
                                                 myPointAttributes.myMBPos[1] - ((mySize[1] * myPointAttributes.pscale) / 2),
                                                 myPointAttributes.myMBPos[1] + ((mySize[1] * myPointAttributes.pscale) / 2),
                                                 myPointAttributes.myMBPos[2] - ((mySize[2] * myPointAttributes.pscale) / 2),
                                                 myPointAttributes.myMBPos[2] + ((mySize[2] * myPointAttributes.pscale) / 2));

         for(int i=0; i < myCube->getVertexCount(); i++) {
               ppt = myCube->getVertexElement(i).getPt();
               UT_Vector4  P = ppt->getPos();
               P *= xform;
               ppt->setPos(P);
            }

         VRAY_clusterThis::setInstanceAttributes(myCube);
      }

   if(myCVEX_Exec)
      VRAY_clusterThis::runCVEX(inst_gdp, mb_gdp, myCVEXFname, CLUSTER_CVEX_POINT);

   if(myCVEX_Exec_prim)
      VRAY_clusterThis::runCVEX(inst_gdp, mb_gdp, myCVEXFname_prim, CLUSTER_CVEX_PRIM);

   return 0;
}
/* ******************************************************************************
*  Function Name : instanceGrid()
*
*  Description : Instance a grid
*
*  Input Arguments : GU_Detail *inst_gdp, GU_Detail *mb_gdp
*
*  Return Value : int
*
***************************************************************************** */
int VRAY_clusterThis::instanceGrid(GU_Detail * inst_gdp, GU_Detail * mb_gdp)
{
#ifdef DEBUG
   std::cout << "VRAY_clusterThis::instanceGrid()" << std::endl;
#endif

   GEO_Primitive * myGrid;
   GU_GridParms grid_parms;
   UT_XformOrder xformOrder(UT_XformOrder::TRS,  UT_XformOrder::XYZ);
   UT_Matrix4 xform(1.0);

   xform.rotate(myPointAttributes.N[0], myPointAttributes.N[1], myPointAttributes.N[2], xformOrder);

   grid_parms.rows = 2;
   grid_parms.cols = 2;
   grid_parms.xsize = mySize[0] * myPointAttributes.pscale;
   grid_parms.ysize = mySize[1] * myPointAttributes.pscale;
   grid_parms.xcenter = myPointAttributes.myNewPos[0];
   grid_parms.ycenter = myPointAttributes.myNewPos[1];
   grid_parms.zcenter = myPointAttributes.myNewPos[2];
   grid_parms.plane = GU_PLANE_XY;
   myGrid = inst_gdp->buildGrid(grid_parms, GU_GRID_POLY);

   for(int i = 0; i < myGrid->getVertexCount(); i++) {
         GEO_Point * ppt = myGrid->getVertexElement(i).getPt();
         UT_Vector4  P = ppt->getPos();
         P *= xform;
         ppt->setPos(P);
      }

   VRAY_clusterThis::setInstanceAttributes(myGrid);

   if(myDoMotionBlur == CLUSTER_MB_DEFORMATION) {

         grid_parms.xcenter = myPointAttributes.myMBPos[0];
         grid_parms.ycenter = myPointAttributes.myMBPos[1];
         grid_parms.zcenter = myPointAttributes.myMBPos[2];
         myGrid = mb_gdp->buildGrid(grid_parms, GU_GRID_POLY);

         for(int i = 0; i < myGrid->getVertexCount(); i++) {
               GEO_Point * ppt = myGrid->getVertexElement(i).getPt();
               UT_Vector4  P = ppt->getPos();
               P *= xform;
               ppt->setPos(P);
            }

         VRAY_clusterThis::setInstanceAttributes(myGrid);
      }

   if(myCVEX_Exec)
      VRAY_clusterThis::runCVEX(inst_gdp, mb_gdp, myCVEXFname, CLUSTER_CVEX_POINT);

   if(myCVEX_Exec_prim)
      VRAY_clusterThis::runCVEX(inst_gdp, mb_gdp, myCVEXFname_prim, CLUSTER_CVEX_PRIM);

   return 0;
}
/* ******************************************************************************
*  Function Name : setFileAttributes()
*
*  Description :
*
*  Input Arguments : GEO_Point *ppt, GU_Detail *inst_gdp
*
*  Return Value : int
*
***************************************************************************** */
inline int VRAY_clusterThis::setFileAttributes(GU_Detail * file_gdp)
{

#ifdef DEBUG
   cout << "VRAY_clusterThis::setFileAttributes() " << endl;
#endif

   GEO_Point * ppt;

#ifdef DEBUG
   long int num_points = (long int) file_gdp->points().entries();
   cout << "VRAY_clusterThis::setFileAttributes() - num points :" << num_points << endl;
#endif

// NOTE: File instanced geo should have normals already, do not set the normals to the source point normals

   GA_FOR_ALL_GPOINTS(file_gdp, ppt) {

      ppt->setValue<UT_Vector3>(myFileAttrOffsets.Cd, (const UT_Vector3)myPointAttributes.Cd);
      ppt->setValue<float>(myFileAttrOffsets.Alpha, (const float)myPointAttributes.Alpha);
      ppt->setValue<UT_Vector3>(myFileAttrOffsets.pointV, (const UT_Vector3)myPointAttributes.v);
      ppt->setValue<int>(myFileAttrOffsets.pointId, (const int)myPointAttributes.id);
      ppt->setString(myFileAttrOffsets.material, myPointAttributes.material);
   }
/* ******************************************************************************
*  Function Name : setInstanceAttributes()
*
*  Description : Set the attributes of the instanced primitive
*
*  Input Arguments : GEO_Primitive *myGeoPrim
*
*  Return Value : void
*
***************************************************************************** */
inline void VRAY_clusterThis::setInstanceAttributes(GEO_Primitive * myGeoPrim)
{

#ifdef DEBUG
   cout << "VRAY_clusterThis::setInstanceAttributes() " << endl;
#endif
   GEO_Point * ppt;

   myGeoPrim->setValue<UT_Vector3>(myInstAttrRefs.Cd, (const UT_Vector3)myPointAttributes.Cd);
   myGeoPrim->setValue<fpreal>(myInstAttrRefs.Alpha, (const fpreal)myPointAttributes.Alpha);
   myGeoPrim->setValue<UT_Vector3>(myInstAttrRefs.v, (const UT_Vector3)myPointAttributes.v);
   myGeoPrim->setValue<UT_Vector3>(myInstAttrRefs.N, (const UT_Vector3)myPointAttributes.N);
//    myGeoPrim->setValue<UT_Vector4>(myInstAttrRefs.orient (const UT_Vector4)myPointAttributes.orient);
   myGeoPrim->setValue<fpreal>(myInstAttrRefs.pscale, (const fpreal)myPointAttributes.pscale);
   myGeoPrim->setValue<int>(myInstAttrRefs.id, (const int)myPointAttributes.id);
   myGeoPrim->setValue<int>(myInstAttrRefs.inst_id, (const int)myInstanceNum);
   myGeoPrim->setValue<fpreal>(myInstAttrRefs.weight, (const fpreal)myPointAttributes.weight);
   myGeoPrim->setValue<fpreal>(myInstAttrRefs.width, (const fpreal)myPointAttributes.width);
   myGeoPrim->setString(myInstAttrRefs.material, myPointAttributes.material);


   // apply attribues to each vertex
   for (int i=0; i < myGeoPrim->getVertexCount(); i++) {
      ppt = myGeoPrim->getVertexElement(i).getPt();
      ppt->setValue<UT_Vector3>(myInstAttrRefs.pointCd, (const UT_Vector3)myPointAttributes.Cd);
      ppt->setValue<float>(myInstAttrRefs.pointAlpha, (const float)myPointAttributes.Alpha);
      ppt->setValue<UT_Vector3>(myInstAttrRefs.pointV, (const UT_Vector3)myPointAttributes.v);
      ppt->setValue<UT_Vector3>(myInstAttrRefs.pointN, (const UT_Vector3)myPointAttributes.N);
      ppt->setValue<float>(myInstAttrRefs.pointPscale, (const float)myPointAttributes.pscale);
      ppt->setValue<int>(myInstAttrRefs.pointId, (const int)myPointAttributes.id);
      ppt->setValue<int>(myInstAttrRefs.pointInstId, (const int)myInstanceNum);
      ppt->setString(myInstAttrRefs.pointMaterial, myPointAttributes.material);

   }

}
/* ******************************************************************************
*  Function Name : runCVEX()
*
*  Description :  Run VEX code on the instanced geometry from an external .vex file
*
*  Input Arguments : GU_Detail *inst_gdp, GU_Detail *mb_gdp
*
*  Return Value : int
*
***************************************************************************** */
int VRAY_clusterThis::runCVEX(GU_Detail * inst_gdp, GU_Detail * mb_gdp, UT_String theCVEXFname, uint method)
{

   if (myVerbose == CLUSTER_MSG_DEBUG) {
      std::cout << "VRAY_clusterThis::runCVEX() - Processing CVEX arrays - points: " << inst_gdp->points().entries()
                << " primitives: " << inst_gdp->primitives().entries() << std::endl;
   }


   UT_Vector3 * P = NULL, *POut = NULL, *N = NULL, *NOut = NULL, *v = NULL, *vOut = NULL, *Cd = NULL, *CdOut = NULL;
   fpreal * weight = NULL, *weightOut = NULL, *Alpha = NULL, *AlphaOut = NULL, *pscale = NULL, *pscaleOut = NULL;
   int * id = NULL, *inst_id = NULL;

   // helper local class to clean up memory
   class cleanUpCVEXMem {
   public:
      void cleanUp(UT_Vector3 * P, UT_Vector3 * POut, UT_Vector3 * N, UT_Vector3 * NOut,
                   UT_Vector3 * v, UT_Vector3 * vOut, UT_Vector3 * Cd, UT_Vector3 * CdOut,
                   fpreal * weight, fpreal * weightOut, fpreal * Alpha, fpreal * AlphaOut,
                   fpreal * pscale, fpreal * pscaleOut,
                   int * id, int * inst_id) {

         if (P) delete []P;
         if (POut) delete []POut;
         if (Cd) delete []Cd;
         if (CdOut) delete []CdOut;
         if (Alpha) delete []Alpha;
         if (AlphaOut) delete []AlphaOut;
         if (N) delete []N;
         if (NOut) delete []NOut;
         if (v) delete []v;
         if (vOut) delete []vOut;
         if (pscale) delete []pscale;
         if (pscaleOut) delete []pscaleOut;
         if (weight) delete []weight;
         if (weightOut) delete []weightOut;
         if (id) delete []id;
         if (inst_id) delete []inst_id;

         return;
      };

   } memCleaner;


   try {
      uint32         num_inst = 0, num_points = 0, num_prim = 0;
      long int       num = 0;
      GEO_Point   *   ppt;
      GEO_Primitive * prim;
      UT_Vector4     pos;
      CVEX_Context   cvex;
      GU_Detail   *   cvex_gdp;
      uint32         num_passes = 1;
      uint32         mb_pass = 0;
      fpreal         time = myCurrentTime;

// std::cout << "VRAY_clusterThis::runCVEX() - time: " << time << endl;

      if (myDoMotionBlur == CLUSTER_MB_DEFORMATION)
         num_passes = 2;

      if (myPrimType == CLUSTER_POINT) {
         num_inst = myInstanceNum;
//            num_inst = inst_gdp->points().entries();
         num_points = inst_gdp->points().entries();
//           std::cout << "VRAY_clusterThis::runCVEX() - num_inst: " << num_inst << std::endl;
      } else {
         num_inst = myInstanceNum;
         num_prim = inst_gdp->primitives().entries();
         num_points = inst_gdp->points().entries();
         num_inst = num_points;
//           std::cout << "VRAY_clusterThis::runCVEX() - num_inst: " << num_inst << " num_points: " << num_points << " num_prim: " << num_prim << std::endl;
      }


      UT_Vector3 primAttr, ptAttr;

      GA_RWAttributeRef primN_ref, primV_ref, primCd_ref, primAlpha_ref, primPscale_ref, primId_ref, primWeight_ref;
      GA_RWAttributeRef ptN_ref, ptV_ref, ptCd_ref, ptAlpha_ref, ptPscale_ref, ptId_ref, ptInstId_ref;

      if (myPrimType == CLUSTER_POINT) {

         // Allocate the space for the point positions
         P = new UT_Vector3[num_points];
         POut = new UT_Vector3[num_points];

         if (myCVEXPointVars.cvex_Cd_pt) {
            Cd = new UT_Vector3[num_points];
            CdOut = new UT_Vector3[num_points];
         }

         if (myCVEXPointVars.cvex_Alpha_pt) {
            Alpha = new fpreal[num_points];
            AlphaOut = new fpreal[num_points];
         }

         if (myCVEXPointVars.cvex_N_pt) {
            N = new UT_Vector3[num_points];
            NOut = new UT_Vector3[num_points];
         }

         if (myCVEXPointVars.cvex_v_pt) {
            v = new UT_Vector3[num_points];
            vOut = new UT_Vector3[num_points];
         }

         if (myCVEXPointVars.cvex_pscale_pt) {
            pscale = new fpreal[num_points];
            pscaleOut = new fpreal[num_points];
         }

         id = new int[num_points];
         inst_id = new int[num_points];

      } else {
         // If we're processing the points of the prims, allocate the space
         if (method == CLUSTER_CVEX_POINT) {
            P = new UT_Vector3[num_points];
            POut = new UT_Vector3[num_points];
            // Allocate space for the id and inst_id attr's
            id = new int[num_points];
            inst_id = new int[num_points];
         }
         // Else we're working on primitives, so allocate sace for the attrs the user wants to CVEX!
         else {

            if (myCVEXPrimVars.cvex_Cd_prim) {
               Cd = new UT_Vector3[num_prim];
               CdOut = new UT_Vector3[num_prim];
            }

            if (myCVEXPrimVars.cvex_Alpha_prim) {
               Alpha = new fpreal[num_prim];
               AlphaOut = new fpreal[num_prim];
            }

            if (myCVEXPrimVars.cvex_N_prim) {
               N = new UT_Vector3[num_prim];
               NOut = new UT_Vector3[num_prim];
            }

            if (myCVEXPrimVars.cvex_v_prim) {
               v = new UT_Vector3[num_prim];
               vOut = new UT_Vector3[num_prim];
            }

            if (myCVEXPrimVars.cvex_pscale_prim) {
               pscale = new fpreal[num_prim];
               pscaleOut = new fpreal[num_prim];
            }

            if (myPrimType == VRAY_clusterThis::CLUSTER_PRIM_METABALL && myCVEXPrimVars.cvex_weight_prim) {
               weight = new fpreal[num_prim];
               weightOut = new fpreal[num_prim];
            }
            // Allocate space for the id and inst_id attr's
            id = new int[num_prim];
            inst_id = new int[num_prim];

         }

      }



      // Retrieve the attribute offsets
      for (uint32 pass = 0; pass < num_passes; pass++) {

         if (pass == 0) {
            cvex_gdp = inst_gdp;
            mb_pass = 0;
         } else {
            cvex_gdp = mb_gdp;
            mb_pass = 1;
         }

         if (myPrimType == CLUSTER_POINT) {

            if (myCVEXPointVars.cvex_Cd_pt) {
               ptCd_ref = cvex_gdp->findDiffuseAttribute(GEO_POINT_DICT);
            }

            if (myCVEXPointVars.cvex_Alpha_pt) {
               ptAlpha_ref = cvex_gdp->findFloatTuple(GA_ATTRIB_POINT, "Alpha", 1);
            }

            if (myCVEXPointVars.cvex_N_pt) {
               ptN_ref = cvex_gdp->findNormalAttribute(GEO_POINT_DICT);
            }

            if (myCVEXPointVars.cvex_v_pt) {
               ptV_ref = cvex_gdp->findVelocityAttribute(GEO_POINT_DICT);
            }

            if (myCVEXPointVars.cvex_pscale_pt) {
               ptPscale_ref = cvex_gdp->findFloatTuple(GA_ATTRIB_POINT, "pscale", 1);
            }

            ptId_ref = cvex_gdp->findIntTuple(GA_ATTRIB_POINT, "id", 1);
            ptInstId_ref = cvex_gdp->findIntTuple(GA_ATTRIB_POINT, "inst_id", 1);

         } else {
            // If we're not processing the points of the prims, get the attr's offset for the attrs the user wants to use
            if (method != CLUSTER_CVEX_POINT) {

               if (myCVEXPrimVars.cvex_Cd_prim) {
                  primCd_ref = cvex_gdp->findDiffuseAttribute(GEO_PRIMITIVE_DICT);
               }

               if (myCVEXPrimVars.cvex_Alpha_prim) {
                  primAlpha_ref = cvex_gdp->findFloatTuple(GA_ATTRIB_POINT, "Alpha", 1);
               }

               if (myCVEXPrimVars.cvex_N_prim) {
                  primN_ref = cvex_gdp->findFloatTuple(GA_ATTRIB_POINT, "N", 3);
                  //                  primN_ref = cvex_gdp->findNormalAttribute ( GEO_PRIMITIVE_DICT );
               }

               if (myCVEXPrimVars.cvex_v_prim) {
                  primV_ref = cvex_gdp->findVelocityAttribute(GEO_PRIMITIVE_DICT);
               }

               if (myCVEXPrimVars.cvex_pscale_prim) {
                  ptPscale_ref = cvex_gdp->findFloatTuple(GA_ATTRIB_POINT, "pscale", 1);
               }

               if (myPrimType == VRAY_clusterThis::CLUSTER_PRIM_METABALL && myCVEXPrimVars.cvex_weight_prim) {
                  primWeight_ref = cvex_gdp->findFloatTuple(GA_ATTRIB_POINT, "weight", 1);
               }

            }

            // Get the offset for id attr
            ptId_ref = cvex_gdp->findIntTuple(GA_ATTRIB_POINT, "id", 1);
            ptInstId_ref = cvex_gdp->findIntTuple(GA_ATTRIB_POINT, "inst_id", 1);
         }



#ifdef DEBUG
         std::cout << "VRAY_clusterThis::runCVEX() - Retrieved attribute offsets" << std::endl;
#endif

         // Set the values of the incoming arrays

         if (myPrimType == CLUSTER_POINT) {

            num = 0;
            GA_FOR_ALL_GPOINTS(cvex_gdp, ppt) {
               pos = ppt->getPos();
               P[num][0] = pos.x();
               P[num][1] = pos.y();
               P[num][2] = pos.z();
//                    P[num] = ppt->getPos();

               id[num] = static_cast<int>(ppt->getValue<int>(ptId_ref, 0));

               if (ptInstId_ref.isValid())
                  inst_id[num] = static_cast<int>(ppt->getValue<int>(ptInstId_ref, 0));
               else
                  inst_id[num] = id[num];

//                    cout << "IN - id : " << id[num] << "\tinst_id " << inst_id[num] << "\tnum " << num << endl;
               ++num;
            }

            if (myCVEXPointVars.cvex_Cd_pt) {
               num = 0;
               GA_FOR_ALL_GPOINTS(cvex_gdp, ppt) {
                  ptAttr = static_cast<UT_Vector3>(ppt->getValue<UT_Vector3>(ptCd_ref, 0));
                  Cd[num][0] = ptAttr.x();
                  Cd[num][1] = ptAttr.y();
                  Cd[num][2] = ptAttr.z();
//                              cout << "IN - Cd: " << Cd[num] << endl;
                  ++num;
               }
            }
Beispiel #7
0
Geo2Emp::ErrorCode Geo2Emp::loadParticleShape( const Nb::Body* pBody )
{
	if (!_gdp)
	{
		//If we don't have a GDP for writing data into Houdini, return error.
		return EC_NULL_WRITE_GDP;
	}

	const Nb::ParticleShape* pShape;

	LogInfo() << "=============== Loading particle shape ===============" << std::endl; 

	pShape = pBody->queryConstParticleShape();

	if (!pShape)
	{
		//std::cout << "Received NULL particle shape!" << std::endl;
		return EC_NO_PARTICLE_SHAPE;
	}

	//Attribute Lookup Tables
	std::vector< GEO_AttributeHandle > attribLut;
	std::vector<GeoAttributeInfo> attribInfo; //houdini types for the naiad channels.
	GeoAttributeInfo* pInfo;
	std::string attrName;

	//We have a valid particle shape. Start copying particle data over to the GDP
	int64_t size = pShape->size();
	int channelCount = pShape->channelCount();
	GEO_Point *ppt;
	GEO_AttributeHandle attr;
	GU_PrimParticle *pParticle;
	std::vector<std::string> houdiniNames; //houdini names that correspond to naiad channels.
	std::vector<GB_AttribType> houdiniTypes; //houdini types for the naiad channels.
	//Default values for attributes
	float zero3f[3] = {0,0,0};
	float zero1f = 0;
	//int zero3i[3] = {0,0,0};
	int zero1i = 0;
	const void* data;

	LogVerbose() << "Particle shape size: " << size << std::endl;
	LogVerbose() << "Particle shape channel count: " << channelCount << std::endl;

	LogVerbose() << "Building particle primitive...";
	pParticle = GU_PrimParticle::build(_gdp, 0);
	LogVerbose() << "done." << std::endl;

	attribLut.clear();
	attribInfo.clear();
	attribLut.resize( channelCount );
	attribInfo.resize( channelCount );

	//Prepare for a blind copy of Naiad channels to Houdini attributes.
	//Iterate over the channels and create the corresponding attributes in the GDP
	for (int i = 0; i < channelCount; i++)
	{
		//std::cout << "channel: " << i << std::endl;
		const Nb::ChannelCowPtr& chan = pShape->channel(i);

		if ( _empAttribMangle.find( chan->name() ) != _empAttribMangle.end() )
			attrName = _empAttribMangle[ chan->name() ];
		else
			attrName = chan->name();

		LogDebug() << "Processing EMP Channel: " << chan->name() << "; mangled: " << attrName << std::endl;

		//Determine the attribute type, and store it
		pInfo = &(attribInfo[ i ]);
		pInfo->supported = false;
		pInfo->size = 0;
		pInfo->use64 = false;

		if (attrName.compare("P") == 0)
			//Don't treat position as an attribute. This needs to be handled separately.
			continue;

		switch ( chan->type() )
		{
			case Nb::ValueBase::IntType:
				pInfo->type = GB_ATTRIB_INT;
				pInfo->entries = 1;
				pInfo->size = sizeof(int);
				pInfo->supported = true;
				data = &zero1i;
				break;			
			case Nb::ValueBase::Int64Type: //NOTE: This might need to be handled differently ... just remember this 'hack'
				pInfo->type = GB_ATTRIB_INT;
				pInfo->entries = 1;
				pInfo->size = sizeof(int);
				pInfo->supported = true;
				pInfo->use64 = true;
				data = &zero1i;
				break;
			case Nb::ValueBase::FloatType:
				pInfo->type = GB_ATTRIB_FLOAT;
				pInfo->size = sizeof(float);
				pInfo->entries = 1;
				pInfo->supported = true;
				data = &zero1f;
				break;
			case Nb::ValueBase::Vec3fType:
				pInfo->type = GB_ATTRIB_VECTOR;
				pInfo->size = sizeof(float);
				pInfo->entries = 3;
				pInfo->supported = true;
				data = &zero3f;
				break;
			default:
				pInfo->supported = false;
				break;
		}

		//If the attribute is not supported, then continue with the next one.
		if (!pInfo->supported)
		{
			LogVerbose() << "Unsupported attribute. Skipping:" << attrName << std::endl;
			continue;
		}

		//Check whether the attribute exists or not
		attr = _gdp->getPointAttribute( attrName.c_str() );
		if ( !attr.isAttributeValid() )
		{
			LogVerbose() << "Creating attribute in GDP:" << attrName << std::endl;
			LogDebug() << "Name: " << attrName << std::endl << "Entries: " << pInfo->entries << std::endl << "Size: " << pInfo->size << std::endl;
			_gdp->addPointAttrib( attrName.c_str(), pInfo->size * pInfo->entries, pInfo->type, data);
			attr = _gdp->getPointAttribute( attrName.c_str() );
		}

		//Put the attribute handle in a Lut for easy access later.
		attribLut[i] = attr;
	}	

	//The channel values for particle shapes are stored in blocks/tiles.
	unsigned int absPtNum = 0;

	//Get the block array for the positions channel
	const em::block3_array3f& positionBlocks( pShape->constBlocks3f("position") );	
	unsigned int numBlocks = positionBlocks.block_count();
	unsigned int bsize;
	float dec_accumulator = 0.0f;
	float dec = (1.0f - (_decimation)/100.0f);
	LogInfo() << "Keeping decimation value: " << dec << std::endl;

	for (int blockIndex = 0; blockIndex < numBlocks; blockIndex ++)
	{
		//if (ptNum % 100 == 0)
		//Get a single block from the position blocks
		const em::block3vec3f& posBlock = positionBlocks(blockIndex);

		if ( blockIndex % 100 == 0 )
			LogDebug() << "Block: " << blockIndex << "/" << numBlocks << std::endl;
		//Iterate over all the points/particles in the position block
		bsize = posBlock.size();

		//Only process the point if the decimation accumulator is greater than one.

		for (int ptNum = 0; ptNum < bsize; ptNum++, absPtNum++)
		{
			dec_accumulator += dec;
			if (dec_accumulator < 1.0f)
				//Skip this point
				continue;
			//Process this point, remove the dec_accumulator rollover.
			dec_accumulator -= (int) dec_accumulator;

			ppt = _gdp->appendPoint();
			pParticle->appendParticle(ppt);

			ppt->setPos( UT_Vector3( posBlock(ptNum)[0], posBlock(ptNum)[1], posBlock(ptNum)[2] ) );
			
			//Loop over the channels and add the attributes
			//This loop needs to be as fast as possible.
			for (int channelIndex = 0; channelIndex < channelCount; channelIndex++)
			{
				pInfo = &(attribInfo[ channelIndex ]);
				//If the attribute is not supported then skip it
				if (!pInfo->supported)
				{
					continue;
				}

				attribLut[ channelIndex ].setElement( ppt );

				switch ( pInfo->type )
				{
					case GB_ATTRIB_INT:
						{
							if (pInfo->use64)
							{
								const em::block3i64& channelData( pShape->constBlocks1i64(channelIndex)(blockIndex) );
								//Get the Houdini point attribute using the name list we built earlier.
								attribLut[channelIndex].setI( channelData(ptNum) );
							}
							else
							{
								const em::block3i& channelData( pShape->constBlocks1i(channelIndex)(blockIndex) );
								//Get the Houdini point attribute using the name list we built earlier.
								attribLut[channelIndex].setI( channelData(ptNum) );
							}
						}
						break;
					case GB_ATTRIB_FLOAT:
						{
							//TODO: Handle more that 1 entry here, if we ever get something like that ... although I doubt it would happen.
							const em::block3f& channelData( pShape->constBlocks1f(channelIndex)(blockIndex) );
							//Get the Houdini point attribute using the name list we built earlier.
							attribLut[channelIndex].setF( channelData(ptNum) );
						}
						break;
					case GB_ATTRIB_VECTOR:
						{
							const em::block3vec3f& channelData( pShape->constBlocks3f(channelIndex)(blockIndex) );
							//Get the Houdini point attribute using the name list we built earlier.
							attribLut[channelIndex].setV3( UT_Vector3( channelData(ptNum)[0], channelData(ptNum)[1], channelData(ptNum)[2]  ) );
						}
						break;
					default:
						//not yet implemented.
						continue;
						break;
				}

			}
		}	
	}

	//std::cout << "all done. " << std::endl;
	return EC_SUCCESS;
}
static void exportParticlesDetail( const GU_Detail* gdp,
                                  const std::string& filePath,
                                  const std::map<std::string,
                                  channel_type>& desiredChannels )
{
	prt_ofstream ostream;

	static std::map<std::string, std::string> s_reservedChannels;
	if( s_reservedChannels.empty() ) {
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_NORMAL ) ] = "Normal";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_TEXTURE ) ] = "TextureCoord";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_VELOCITY ) ] = "Velocity";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_DIFFUSE ) ] = "Color";
		//s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_ALPHA ) ] = "Density";
		//s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_MASS ) ] = "Density";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_LIFE ) ] = "";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_ID ) ] = "ID";
		s_reservedChannels[ gdp->getStdAttributeName( GEO_ATTRIBUTE_PSCALE ) ] = "Scale";
		s_reservedChannels[ "accel" ] = "Acceleration";
	}

	float posVal[3];
	float lifeVal[2];
	
	ostream.bind( "Position", posVal, 3 );

	//We handle the life channel in a special manner
	GA_ROAttributeRef lifeAttrib = gdp->findPointAttribute( gdp->getStdAttributeName( GEO_ATTRIBUTE_LIFE ) );
	if( lifeAttrib.isValid() ){
		std::map<std::string,channel_type>::const_iterator it;
		
		it = desiredChannels.find( "Age" );
		if( it != desiredChannels.end() && it->second.second == 1 )
			ostream.bind( "Age", &lifeVal[0], 1, it->second.first );
		else if( desiredChannels.empty() )
			ostream.bind( "Age", &lifeVal[0], 1, prtio::data_types::type_float16 );

		it = desiredChannels.find( "LifeSpan" );
		if( it != desiredChannels.end() && it->second.second == 1 )
			ostream.bind( "LifeSpan", &lifeVal[1], 1, it->second.first );
		else if( desiredChannels.empty() )
			ostream.bind( "LifeSpan", &lifeVal[1], 1, prtio::data_types::type_float16 );
	}
	
	//Using a deque to prevent the memory from moving around after adding the bound_attribute to the container.
	std::deque< bound_attribute<int> > m_intAttrs;
	std::deque< bound_attribute<float> > m_floatAttrs;
	std::deque< bound_attribute<float> > m_vectorAttrs;
	
	for ( GA_AttributeDict::iterator it = gdp->getAttributes().getDict(GA_ATTRIB_POINT).begin(GA_SCOPE_PUBLIC); !it.atEnd(); ++it) {
		
		GA_Attribute *node = it.attrib();

		std::string channelName = node->getName();

		//Translate special names
		std::map<std::string,std::string>::const_iterator itResChannel = s_reservedChannels.find( channelName );
		if( itResChannel != s_reservedChannels.end() ){
			//If its empty, that means we reserve some sort of special handling.
			if( itResChannel->second.empty() )
				continue;
			channelName = itResChannel->second;
		}
		
		//Skip channels that aren't on the list.
		std::map<std::string,channel_type>::const_iterator itChannel = desiredChannels.find( channelName );
		bool channelIsDesired = ( itChannel != desiredChannels.end() );
		
		if( !desiredChannels.empty() && !channelIsDesired )
			continue;
			
		prtio::data_types::enum_t type;
		
		//Only add valid channel names
		if( detail::is_valid_channel_name( channelName.c_str() ) ) {
			//I add the new item to the deque, THEN initialize it since a deque will not move the object around and this allows
			//me to allocate the float array and not have to worry about the object getting deleted too early.
			switch( node->getStorageClass() ){
			case GA_STORECLASS_FLOAT:
				if( node->getTupleSize()==3 ){
					m_vectorAttrs.push_back( bound_attribute<float>() );
					m_vectorAttrs.back().attr =	gdp->findPointAttribute(node->getName());
					m_vectorAttrs.back().count = node->getTupleSize();
					m_vectorAttrs.back().data = new float[m_vectorAttrs.back().count];

					type = prtio::data_types::type_float16;
					if( channelIsDesired ){
						type = itChannel->second.first;
						if( itChannel->second.second != m_vectorAttrs.back().count )
							continue;
					}

					ostream.bind( channelName, m_vectorAttrs.back().data, m_vectorAttrs.back().count, type );

				} else {
					m_floatAttrs.push_back( bound_attribute<float>() );
					m_floatAttrs.back().attr =	gdp->findPointAttribute( node->getName() );
					m_floatAttrs.back().count = node->getTupleSize();
					m_floatAttrs.back().data = new float[m_floatAttrs.back().count];

					type = prtio::data_types::type_float16;
					if( channelIsDesired ){
						type = itChannel->second.first;
						if( itChannel->second.second != m_floatAttrs.back().count )
							continue;
					}

					ostream.bind( channelName, m_floatAttrs.back().data, m_floatAttrs.back().count, type );
				}
				break;
			case GA_STORECLASS_INT:
				m_intAttrs.push_back( bound_attribute<int>() );
				m_intAttrs.back().attr = gdp->findPointAttribute( node->getName() );
				m_intAttrs.back().count = node->getTupleSize();
				m_intAttrs.back().data = new int[m_intAttrs.back().count];

				type = prtio::data_types::type_int32;
				if( channelIsDesired ){
					type = itChannel->second.first;
					if( itChannel->second.second != m_intAttrs.back().count )
						continue;
				}
			
				ostream.bind( channelName, m_intAttrs.back().data, m_intAttrs.back().count, type );
				break;
			default:
				break;
			}
		}
	}

	try{
		ostream.open( filePath );
	} catch( const std::ios::failure& e ) {
		std::cerr << e.what() << std::endl;
		throw HOM_OperationFailed( "Failed to open the file" );
	}
		
	GA_IndexMap map = gdp->getPointMap();
	UT_Vector3 p;
	GEO_Point* pt;
	GA_Index indexSize = map.indexSize();
	GA_Offset offset;

	for( int i = 0 ; i < indexSize; i++ ) {
		offset = map.offsetFromIndex( i );
		p = gdp->getPos3( offset );
		posVal[0] = p.x();
		posVal[1] = p.y();
		posVal[2] = -1 * p.z();
		
		//TODO: Remove the GEO_Point object that is now deprecated. 
		pt = ( GEO_Point* )gdp->getGBPoint( offset );
		
		//TODO: Convert this into appropriate time values. Is it seconds or frames or what?!
		if( lifeAttrib.isValid() ) 
			pt->get( lifeAttrib, lifeVal, 2 );

		for( std::deque< bound_attribute<float> >::iterator it = m_floatAttrs.begin(), itEnd = m_floatAttrs.end(); it != itEnd; ++it )
			pt->get( it->attr, it->data, it->count );

		for( std::deque< bound_attribute<float> >::iterator it = m_vectorAttrs.begin(), itEnd = m_vectorAttrs.end(); it != itEnd; ++it ) {
			pt->get( it->attr, it->data, it->count );
				
			//TODO: Optionally transform into some consistent world space for PRT files.
		}

		for( std::deque< bound_attribute<int> >::iterator it = m_intAttrs.begin(), itEnd = m_intAttrs.end(); it != itEnd; ++it )
			pt->get( it->attr, it->data, it->count );

		ostream.write_next_particle();
	}
	
	ostream.close();
}
Beispiel #9
0
void GR_rmanPtc::renderWire( GU_Detail *gdp,
    RE_Render &ren,
    const GR_AttribOffset &ptinfo,
    const GR_DisplayOption *dopt,
    float lod,
    const GU_PrimGroupClosure *hidden_geometry
    )
{
    int			 i, nprim;
    GEO_Primitive 	*prim;
    UT_Vector3		 v3;

    rmanPtcSop::rmanPtcDetail *detail = dynamic_cast<rmanPtcSop::rmanPtcDetail*>(gdp);
    if ( !detail )
        return;

    // rebuild our display list
    if ( detail->redraw )
    {
        srand(0);

        GEO_PointList &points = detail->points();
        int display_channel = detail->display_channel;
        // render as points
        GEO_Point *pt = 0;
        UT_Vector4 pos;
        float col[3] = {1.0,1.0,1.0};

        if ( !detail->use_disk )
        {
            ren.pushPointSize(detail->point_size);
            ren.beginPoint();
        }

        for ( unsigned int i=0; i<points.entries(); ++i )
        {
            if ( rand()/(float)RAND_MAX<=detail->display_probability )
            {
                // point position
                pt = points[i];
                pos = pt->getPos();

                // display colour
                
                float *ptr = NULL;
                if (detail->attributes.size() >0) {
                    ptr = pt->castAttribData<float>(
                            detail->attributes[display_channel] );
                    if (ptr) {
                        if ( detail->attribute_size[display_channel]==1)
                            col[0] = col[1] = col[2] = ptr[0];
                        else
                        {
                            col[0] = ptr[0];
                            col[1] = ptr[1];
                            col[2] = ptr[2];
                        }
                    }
                }
                // draw point
                if ( !detail->use_cull_bbox ||
                        detail->cull_bbox.isInside( pos ) )
                {
                    if ( !detail->use_disk )
                    {
                        // render as points
                        ren.setColor( col[0], col[1], col[2], 1 );
                        ren.vertex3DW( pos.x(), pos.y(), pos.z() );
                    }
                    else
                    {
                        // render as disks
                        UT_Vector3 n = *pt->castAttribData<UT_Vector3>(detail->N_attrib);
                        float r = *pt->castAttribData<float>(detail->R_attrib);
                        n.normalize();
                        UT_Vector3 ref(1,0,0);
                        UT_Vector3 up = ref;
                        up.cross(n);
                        up.normalize();
                        UT_Vector3 right = up;
                        right.cross(n);
                        right.normalize();
                        UT_DMatrix4 mat(
                                right.x(), right.y(), right.z(), 0,
                                up.x(), up.y(), up.z(), 0,
                                n.x(), n.y(), n.z(), 0,
                                pos.x(), pos.y(), pos.z(), 1 );
                        ren.pushMatrix();
                        ren.multiplyMatrix(mat);
                        ren.pushColor( UT_Color( UT_RGB, col[0], col[1], col[2] ) );
                        ren.circlefW( 0, 0, detail->point_size * r, 8 );
                        ren.popColor();
                        ren.popMatrix();
                    }
                }
            }
        }

        if ( !detail->use_disk )
        {
            ren.endPoint();
        }
    }
}
Beispiel #10
0
OP_ERROR SOP_CudaParticles::cookMySop(OP_Context &context) {

	oldf = f;
	f =	context.getFrame();
	GEO_ParticleVertex* pvtx;

	double t = context.getTime();

	particlesSystem->dt = 1/(OPgetDirector()->getChannelManager()->getSamplesPerSec() * SUBSTEPS(t));
	particlesSystem->preview = PREVIEW(t);

	particlesSystem->partsLife = LIFE(t);
	particlesSystem->partsLifeVar = LIFEVAR(t);


	particlesSystem->velDamp = VELDAMP(t);
	particlesSystem->gravityStrength = GRAVITYSTR(t);
	particlesSystem->gravityDir = cu::make_float3(GRAVITYX(t),GRAVITYY(t),GRAVITYZ(t));
	particlesSystem->fluidStrength = FLUIDSTR(t);

	particlesSystem->noiseAmp = cu::make_float3(NOISEAMP(t),NOISEAMP(t),NOISEAMP(t));
	particlesSystem->noiseOct = NOISEOCT(t);
	particlesSystem->noiseFreq = NOISEFREQ(t);
	particlesSystem->noiseLac = NOISELACUN(t);
	particlesSystem->noiseOffset = cu::make_float3(NOISEOFFSETX(t),NOISEOFFSETY(t),NOISEOFFSETZ(t));

	particlesSystem->pointSize = POINTSIZE(t);
	particlesSystem->opacity = OPACITY(t);
	particlesSystem->startColor = cu::make_float3(STARTCOLORX(t),STARTCOLORY(t),STARTCOLORZ(t));
	particlesSystem->endColor = cu::make_float3(ENDCOLORX(t),ENDCOLORY(t),ENDCOLORZ(t));


	UT_Interrupt	*boss;

	OP_Node::flags().timeDep = 1;

    if (error() < UT_ERROR_ABORT) {
		boss = UTgetInterrupt();	

		// Start the interrupt server
		if (boss->opStart("Building Particles")){

			//gdp->clearAndDestroy();

			static float		 zero = 0.0;
			GB_AttributeRef partsAtt = gdp->addAttrib("cudaParticlesPreview", sizeof(int), GB_ATTRIB_INT, &zero);
			gdp->attribs().getElement().setValue<int>(partsAtt, particlesSystem->preview);

			GB_AttributeRef systemIdAtt = gdp->addAttrib("systemId", sizeof(int), GB_ATTRIB_INT, &zero);
			gdp->attribs().getElement().setValue<int>(systemIdAtt, particlesSystem->id);

			if (f < STARTFRAME(t)) {

				gdp->clearAndDestroy();
				particlesSystem->resetParticles();

			} else if (f == STARTFRAME(t)) {

				gdp->clearAndDestroy();
				particlesSystem->resetParticles();

				int maxParts = MAXPARTS(t);
				if (particlesSystem->nParts!=maxParts)
					particlesSystem->changeMaxParts(maxParts);

				//hSystem = (GEO_PrimParticle *)gdp->appendPrimitive(GEOPRIMPART);
				//hSystem->clearAndDestroy();

				GB_AttributeRef hVelocity = gdp->addPointAttrib("v", sizeof(UT_Vector3),GB_ATTRIB_VECTOR, 0);
				GB_AttributeRef hLife = gdp->addPointAttrib("life", sizeof(float)*2,GB_ATTRIB_FLOAT, 0);

				if(particlesSystem->preview!=1) {

					UT_Vector4 orig = UT_Vector4(0,0,0,1);

					

					for (int i = 0; i<particlesSystem->nParts; i++) {

						GEO_Point* newPoint = gdp->appendPoint();
						newPoint->setPos(orig);

						/*pvtx = hSystem->giveBirth();
						GEO_Point* ppt = pvtx->getPt();
						//ppt->getPos().assign(0,0,0,1);*/
						hSystemInit = 1;

					}
				}

			} else {

				if(particlesSystem->nParts != -1) {

					if(lockInputs(context) >= UT_ERROR_ABORT)
						return error();

					if(getInput(0)){

						GU_Detail* emittersInput = (GU_Detail*)inputGeo(0, context);
						GEO_PointList emittersList = emittersInput->points();
						int numEmitters = emittersList.entries();

						if (numEmitters != particlesSystem->nEmit) {
							delete particlesSystem->emitters;
							particlesSystem->nEmit = numEmitters;
							particlesSystem->emitters = new ParticlesEmitter[numEmitters];
						}

						GEO_AttributeHandle radAh, amountAh;
						GEO_AttributeHandle initVelAh, radVelAmpAh, noiseVelAmpAh,
							noiseVelOffsetAh, noiseVelOctAh, noiseVelLacAh, noiseVelFreqAh;

						radAh = emittersInput->getPointAttribute("radius");
						amountAh = emittersInput->getPointAttribute("amount");
						initVelAh = emittersInput->getPointAttribute("initVel");
						radVelAmpAh = emittersInput->getPointAttribute("radVelAmp");
						noiseVelAmpAh = emittersInput->getPointAttribute("noiseVelAmp");
						noiseVelOffsetAh = emittersInput->getPointAttribute("noiseVelOffset");
						noiseVelOctAh = emittersInput->getPointAttribute("noiseVelOct");
						noiseVelLacAh = emittersInput->getPointAttribute("noiseVelLac");
						noiseVelFreqAh = emittersInput->getPointAttribute("noiseVelFreq");

						for (int i = 0; i < numEmitters; i++) {

							UT_Vector4 emitPos = emittersList[i]->getPos();
							UT_Vector3 emitPos3(emitPos);

							particlesSystem->emitters[i].posX = emitPos.x();
							particlesSystem->emitters[i].posY = emitPos.y();
							particlesSystem->emitters[i].posZ = emitPos.z();

							radAh.setElement(emittersList[i]);
							amountAh.setElement(emittersList[i]);
							initVelAh.setElement(emittersList[i]);
							radVelAmpAh.setElement(emittersList[i]);
							noiseVelAmpAh.setElement(emittersList[i]);
							noiseVelOffsetAh.setElement(emittersList[i]);
							noiseVelOctAh.setElement(emittersList[i]);
							noiseVelLacAh.setElement(emittersList[i]);
							noiseVelFreqAh.setElement(emittersList[i]);

							particlesSystem->emitters[i].radius = radAh.getF(0);
							particlesSystem->emitters[i].amount = amountAh.getF(0);

							particlesSystem->emitters[i].velX = initVelAh.getF(0);
							particlesSystem->emitters[i].velY = initVelAh.getF(1);
							particlesSystem->emitters[i].velZ = initVelAh.getF(2);

							particlesSystem->emitters[i].radVelAmp = radVelAmpAh.getF(0);

							particlesSystem->emitters[i].noiseVelAmpX = noiseVelAmpAh.getF(0);
							particlesSystem->emitters[i].noiseVelAmpY = noiseVelAmpAh.getF(1);
							particlesSystem->emitters[i].noiseVelAmpZ = noiseVelAmpAh.getF(2);

							particlesSystem->emitters[i].noiseVelOffsetX = noiseVelOffsetAh.getF(0);
							particlesSystem->emitters[i].noiseVelOffsetY = noiseVelOffsetAh.getF(1);
							particlesSystem->emitters[i].noiseVelOffsetZ = noiseVelOffsetAh.getF(2);

							particlesSystem->emitters[i].noiseVelOct = noiseVelOctAh.getF(0);
							particlesSystem->emitters[i].noiseVelLac = noiseVelLacAh.getF(0);
							particlesSystem->emitters[i].noiseVelFreq = noiseVelFreqAh.getF(0);

						}
					} else {

						particlesSystem->nEmit = 0;

					}

					if(getInput(1)){

						GU_Detail* fluidInput = (GU_Detail*)inputGeo(1, context);

						GEO_AttributeHandle fluidIdAh= fluidInput->getDetailAttribute("solverId");
						fluidIdAh.setElement(fluidInput);

						int sId = fluidIdAh.getI();

						VHFluidSolver3D* curr3DSolver = VHFluidSolver3D::solverList[sId];

						particlesSystem->fluidSolver = curr3DSolver;

					}

						

					unlockInputs();


					if (f!=oldf) {

						particlesSystem->emitParticles();
						particlesSystem->updateParticles();

					}


					if(particlesSystem->preview!=1 && hSystemInit == 1) {

						cu::cudaMemcpy( particlesSystem->host_pos, particlesSystem->dev_pos,
							particlesSystem->nParts*sizeof(cu::float3), cu::cudaMemcpyDeviceToHost );

						GEO_Point* ppt;
						int i = 0;
						 UT_Vector4		p;

						FOR_ALL_GPOINTS(gdp, ppt) {

							ppt->getPos() = UT_Vector4(particlesSystem->host_pos[i*3],
													particlesSystem->host_pos[i*3+1],
													particlesSystem->host_pos[i*3+2],
													1);
							i++;

						}

						/*pvtx = hSystem->iterateInit();

						for (int i =0; i<particlesSystem->nParts; i++){
							pvtx->getPos().assign(particlesSystem->host_pos[i*3],
													particlesSystem->host_pos[i*3+1],
													particlesSystem->host_pos[i*3+2],
													1);
							pvtx = hSystem->iterateFastNext(pvtx);

						}*/

					}
				}

			}
/* ******************************************************************************
*  Function Name : render()
*
*  Description :   Render VRAY_clusterThis object
*
*  Input Arguments : None
*
*  Return Value : None
*
***************************************************************************** */
void VRAY_clusterThis::render()
{
   GU_Detail * gdp, *inst_gdp, *mb_gdp, *file_gdp;
   GEO_Point * ppt;

//   GEO_AttributeHandle attrHandleVelocity, attrHandleForce, attrHandleVorticity, attrHandleNormal, attrHandleNumNeighbors,
//   attrHandleTextureUV, attrHandleMass, attrHandleAge, attrHandleTemperature, attrHandleID,
//   attrHandleDensity, attrHandleViscosity, attrHandlePressure, attrHandlePscale;

   long int point_num = 0;
   static bool rendered = false;

   if(myVerbose > CLUSTER_MSG_QUIET) {
         std::cout << "VRAY_clusterThis::render() - Version: " << DCA_VERSION << std::endl;
         std::cout << "VRAY_clusterThis::render() - Built for Houdini Version: " << UT_MAJOR_VERSION
                   << "." << UT_MINOR_VERSION << "." << UT_BUILD_VERSION_INT << std::endl;
         std::cout << "VRAY_clusterThis::render() - Instancing ..." <<  endl;
      }


   try {

//          cout << "VM_GEO_clusterThis OTL version: " <<  myOTLVersion << endl;

//       if(myOTLVersion != DCA_VERSION) {
//          cout << "VM_GEO_clusterThis OTL is wrong version: " <<  myOTLVersion << ", should be version: " << DCA_VERSION << ", please install correct version." << endl;
//          throw VRAY_clusterThis_Exception ( "VRAY_clusterThis::render() VM_GEO_clusterThis OTL is wrong version!", 1 );
//       }


         if(!rendered || !myUseTempFile) {

               void * handle = VRAY_Procedural::queryObject(0);
               gdp = VRAY_Procedural::allocateGeometry();

               if(myUseGeoFile) {
                     // If the file failed to load, throw an exception
                     if(!(gdp->load((const char *)mySrcGeoFname).success()))
                        throw VRAY_clusterThis_Exception("VRAY_clusterThis::render() - Failed to read source geometry file ", 1);

                     if(myVerbose > CLUSTER_MSG_INFO)
                        cout << "VRAY_clusterThis::render() - Successfully loaded source geo file: " << mySrcGeoFname << endl;
                  }
               else {
                     gdp->copy(*VRAY_Procedural::queryGeometry(handle, 0));
                     if(myVerbose > CLUSTER_MSG_INFO)
                        cout << "VRAY_clusterThis::render() - Copied incoming geometry" << endl;
                  }


               gdp->getBBox(&myBox);

//               std::cout << "VRAY_clusterThis::render() - gdp->getBBox(&myBox): " << myBox << std::endl;

               VRAY_Procedural::querySurfaceShader(handle, myMaterial);
               myMaterial.harden();
//         myPointAttributes.material = myMaterial;

//         const char **        getSParm (int token) const
//         cout << "VRAY_clusterThis::render() getSParm: " << *getSParm (0) << endl;


#ifdef DEBUG
               cout << "VRAY_clusterThis::render() myMaterial: " << myMaterial << endl;
#endif

               myLOD = getLevelOfDetail(myBox);
               if(myVerbose > CLUSTER_MSG_INFO)
                  cout << "VRAY_clusterThis::render() myLOD: " << myLOD << endl;


               // Get the number if points of the incoming geometery, calculate an interval for reporting the status of the instancing to the user
               long int num_points = (long int) gdp->points().entries();
               long int stat_interval = (long int)(num_points * 0.10) + 1;

               if(myVerbose > CLUSTER_MSG_QUIET)
                  cout << "VRAY_clusterThis::render() Number of points of incoming geometry: " << num_points << endl;

               myObjectName = VRAY_Procedural::queryObjectName(handle);

//      cout << "VRAY_clusterThis::render() Object Name: " << myObjectName << endl;
//      cout << "VRAY_clusterThis::render() Root Name: " << queryRootName() << endl;

// DEBUG stuff ...

//   changeSetting("object:geo_velocityblur", "on");

               UT_String      str;
               int     vblur = 0;
               import("object:velocityblur", &vblur, 0);

               if(vblur) {
                     str = 0;
                     import("velocity", str);
                     if(str.isstring()) {
//               const char  *  name;
//               name = queryObjectName(handle);
                           VRAYwarning("%s[%s] cannot get %s",
                                       VRAY_Procedural::getClassName(), (const char *)myObjectName, " motion blur attr");

                        }
                  }


               myXformInverse = queryTransform(handle, 0);
               myXformInverse.invert();




#ifdef DEBUG
               cout << "Geometry Samples: " << queryGeometrySamples(handle) << endl;
// cout << "scale: " << getFParm ( "scale" ) << endl;
#endif

               // Dump the user parameters to the console
               if(myVerbose == CLUSTER_MSG_DEBUG)
                  VRAY_clusterThis::dumpParameters();

               switch(myMethod) {
                     case CLUSTER_INSTANCE_NOW:
                        inst_gdp = VRAY_Procedural::allocateGeometry();
                        if(myDoMotionBlur == CLUSTER_MB_DEFORMATION)
                           mb_gdp = VRAY_Procedural::allocateGeometry();
                        if(myVerbose > CLUSTER_MSG_QUIET)
                           cout << "VRAY_clusterThis::render() - Using \"instance all the geometry at once\" method" << endl;
                        break;
                     case CLUSTER_INSTANCE_DEFERRED:
                        if(myVerbose > CLUSTER_MSG_QUIET)
                           cout << "VRAY_clusterThis::render() - Using \"addProcedural()\" method" << endl;
                        break;
                  }

               rendered = true;

               // Get the point's attribute offsets
               VRAY_clusterThis::getAttributeOffsets(gdp);

               // Check for required attributes
               VRAY_clusterThis::checkRequiredAttributes();

               // Check for weight attribute if the user wants metaballs
               if((myPrimType == CLUSTER_PRIM_METABALL) && (myPointAttrOffsets.weight.isInvalid())) {

                     cout << "Incoming points must have weight attribute if instancing metaballs! Throwing exception ..." << endl;
                     throw VRAY_clusterThis_Exception("VRAY_clusterThis::render() Incoming points must have weight attribute if instancing metaballs!", 1);
                  }


               if(myPrimType == CLUSTER_FILE) {
                     file_gdp = VRAY_Procedural::allocateGeometry();
                     int file_load_stat = VRAY_clusterThis::preLoadGeoFile(file_gdp);

                     if(!file_load_stat) {
//                           myFileGDP = file_gdp;
                           if(myVerbose > CLUSTER_MSG_INFO)
                              cout << "VRAY_clusterThis::render() Successfully loaded geometry file: " << myGeoFile << endl;
                        }
                     else {
                           throw VRAY_clusterThis_Exception("VRAY_clusterThis::render() Failed to load geometry file ", 1);
                        }
                  }

               // init some vars ...
               myPointAttributes.Cd = (UT_Vector3(1, 1, 1));
               myPointAttributes.v = (UT_Vector3(0, 0, 0));
               myPointAttributes.N = (UT_Vector3(0, 1, 0));
               myPointAttributes.Alpha = 1.0;
               myPointAttributes.pscale = 1.0;
               myPointAttributes.id = 0;

               myNoise.initialize(myNoiseSeed, myNoiseType);

               // Create the attribute "offsets" for the geometry to be instanced
               VRAY_clusterThis::createAttributeOffsets(inst_gdp, mb_gdp);

//changeSetting("surface", "constant Cd ( 1 0 0 )", "object");


               fpreal theta = (2.0 * M_PI) / myNumCopies;
               myInstanceNum = 0;

               if(myCVEX_Exec_pre) {
                     if(myVerbose > CLUSTER_MSG_INFO)
                        cout << "VRAY_clusterThis::render() Executing Pre Process CVEX code" << endl;
                     VRAY_clusterThis::runCVEX(gdp, gdp, myCVEXFname_pre, CLUSTER_CVEX_POINT);
                  }

               /// For each point of the incoming geometry
               GA_FOR_ALL_GPOINTS(gdp, ppt) {
                  myPointAttributes.myPos = ppt->getPos();

                  // get the point's attributes
                  VRAY_clusterThis::getAttributes(ppt, gdp);

#ifdef DEBUG
                  cout << "VRAY_clusterThis::render() " << "theta: " << theta << endl;
#endif

                  uint seed = 37;
                  fpreal dice;
                  bool skip = false;

                  if((myPrimType != CLUSTER_PRIM_CURVE) ||
                        ((myMethod == CLUSTER_INSTANCE_DEFERRED && (myPrimType == CLUSTER_PRIM_CURVE)))) {


                        // For each point, make a number of copies of and recurse a number of times for each copy ...
                        for(int copyNum = 0; copyNum < myNumCopies; copyNum++) {
                              for(int recursionNum = 0; recursionNum < myRecursion; recursionNum++) {

                                    // generate random number to determine to instance or not

                                    dice = SYSfastRandom(seed);
                                    (dice > myBirthProb)?skip = true:skip = false;
//                  cout << dice << " " << skip << endl;
                                    seed = uint(dice * 100);

                                    // Calculate the position for the next instanced object ...
                                    VRAY_clusterThis::calculateNewPosition(theta, copyNum, recursionNum);

                                    if(!skip) {

                                          // Instance an object ...
                                          switch(myMethod) {
                                                   // For the "create all geometry at once" method, instance the object now ...
                                                case CLUSTER_INSTANCE_NOW:
                                                   // Create a primitive based upon user's selection
                                                   // TODO: can later be driven by a point attribute
                                                   switch(myPrimType) {
                                                         case CLUSTER_POINT:
                                                            VRAY_clusterThis::instancePoint(inst_gdp, mb_gdp);
                                                            break;
                                                         case CLUSTER_PRIM_SPHERE:
                                                            VRAY_clusterThis::instanceSphere(inst_gdp, mb_gdp);
                                                            break;
                                                         case CLUSTER_PRIM_CUBE:
                                                            VRAY_clusterThis::instanceCube(inst_gdp, mb_gdp);
                                                            break;
                                                         case CLUSTER_PRIM_GRID:
                                                            VRAY_clusterThis::instanceGrid(inst_gdp, mb_gdp);
                                                            break;
                                                         case CLUSTER_PRIM_TUBE:
                                                            VRAY_clusterThis::instanceTube(inst_gdp, mb_gdp);
                                                            break;
                                                         case CLUSTER_PRIM_CIRCLE:
                                                            VRAY_clusterThis::instanceCircle(inst_gdp, mb_gdp);
                                                            break;
                                                         case CLUSTER_PRIM_METABALL:
                                                            VRAY_clusterThis::instanceMetaball(inst_gdp, mb_gdp);
                                                            break;
                                                         case CLUSTER_FILE:
                                                            VRAY_clusterThis::instanceFile(file_gdp, inst_gdp, mb_gdp);
                                                            break;
                                                            // In case a instance type comes through that's not "legal", throw exception
                                                         default:
                                                            throw VRAY_clusterThis_Exception("VRAY_clusterThis::render() Illegal instance type, exiting ...", 1);
                                                            break;
                                                      }
                                                   break;

                                                   // For the "deferred instance" method, add the procedural now ...
                                                case CLUSTER_INSTANCE_DEFERRED:
                                                   VRAY_Procedural::openProceduralObject();
                                                   VRAY_clusterThisChild * child = new VRAY_clusterThisChild::VRAY_clusterThisChild(this);
                                                   VRAY_Procedural::addProcedural(child);
                                                   VRAY_Procedural::changeSetting("object:geo_velocityblur", "on");
                                                   VRAY_Procedural::closeObject();
//changeSetting("surface", "constant Cd ( 1 0 0 )", "object");
//   changeSetting("object:geo_velocityblur", "on");

                                                   break;
                                             }

                                          myInstanceNum++;

#ifdef DEBUG
                                          cout << "VRAY_clusterThis::render() - myInstanceNum: " << myInstanceNum << std::endl;
#endif
                                       }

                                 } // for number of recursions ...
                           } // for number of copies ...

                     }

                  // User wants a curve instanced on this point
                  if((myPrimType == CLUSTER_PRIM_CURVE) && (myMethod == CLUSTER_INSTANCE_NOW) && (!skip))
                     VRAY_clusterThis::instanceCurve(inst_gdp, mb_gdp, theta, point_num);

                  // Increment our point counter
                  point_num++;

                  // Print out stats to the console
                  if(myVerbose > CLUSTER_MSG_INFO && (myPrimType != CLUSTER_PRIM_CURVE))
                     if((long int)(point_num % stat_interval) == 0)
                        cout << "VRAY_clusterThis::render() Number of points processed: " << point_num << " Number of instances: " << myInstanceNum << endl;

               } // for all points ...


               if(myVerbose > CLUSTER_MSG_QUIET)
                  if(myMethod == CLUSTER_INSTANCE_NOW)
                     if(myDoMotionBlur == CLUSTER_MB_DEFORMATION)
                        cout << "VRAY_clusterThis::render() - Memory usage(MB): " <<
                             (fpreal)(inst_gdp->getMemoryUsage() + mb_gdp->getMemoryUsage() / (1024.0 * 1024.0)) << endl;
                     else
                        cout << "VRAY_clusterThis::render() - Memory usage(MB): " <<
                             (fpreal)(inst_gdp->getMemoryUsage() / (1024.0 * 1024.0)) << endl;

               // If the "instance all the geo at once method" is used, add the the instanced geo for mantra to render ...
               switch(myMethod) {
                     case CLUSTER_INSTANCE_NOW:

                        if(myCVEX_Exec_post) {
                              if(myVerbose > CLUSTER_MSG_INFO)
                                 cout << "VRAY_clusterThis::render() Executing Post Process CVEX code" << endl;
                              VRAY_clusterThis::runCVEX(inst_gdp, mb_gdp, myCVEXFname_post, CLUSTER_CVEX_POINT);
                           }
                        VRAY_Procedural::openGeometryObject();
                        VRAY_Procedural::addGeometry(inst_gdp, 0.0);

                        if(myDoMotionBlur == CLUSTER_MB_VELOCITY)
                           VRAY_Procedural::addVelocityBlurGeometry(inst_gdp, myShutter, myShutter2);

// float    addVelocityBlurGeometry (GU_Detail *gdp, fpreal pre_blur, fpreal post_blur, const char *velocity_attribute="v")

                        if(myDoMotionBlur == CLUSTER_MB_DEFORMATION)
                           VRAY_Procedural::addGeometry(mb_gdp, myShutter);

                        VRAY_Procedural::setComputeN(1);
//                        setSurface(myMaterial);
                        VRAY_Procedural::closeObject();

                        break;
                     case CLUSTER_INSTANCE_DEFERRED:
                        break;
                  }

               if(myVerbose > CLUSTER_MSG_QUIET && (myPrimType != CLUSTER_PRIM_CURVE))
                  cout << "VRAY_clusterThis::render() Total number of instances: " << myInstanceNum << endl;

               // Save the geo to temp location so it doesn't have to be regenerated for a deep shadow pass, etc.
               if(myMethod == CLUSTER_INSTANCE_NOW && myUseTempFile) {
                     ofstream myGeoStream;
                     // myGeoStream.open("/tmp/thisGeo.bgeo");
                     myGeoStream.open((const char *)myTempFname, ios_base::binary);
                     UT_Options myOptions;
                     inst_gdp->save(myGeoStream, 1, &myOptions);
                     myGeoStream.flush();
                     myGeoStream.close();
                     if(myVerbose > CLUSTER_MSG_QUIET)
                        cout << "VRAY_clusterThis::render() - Saved geometry to temp file: " << myTempFname << endl;
                  }

               if(myPrimType == CLUSTER_FILE)
                  VRAY_Procedural::freeGeometry(file_gdp);

               // We're done, free the original geometry
               VRAY_Procedural::freeGeometry(gdp);

            } /// if (rendered) ...
void VRAY_clusterThis::preProcess(GU_Detail * gdp)

{

   GEO_Point * ppt;

   long int num_points = (long int) gdp->points().entries();
   long int stat_interval = (long int)(num_points * 0.10) + 1;


   for(uint32 i = gdp->points().entries(); i-- > 0;) {
         ppt = gdp->points()(i);

         myPointList.append(i);

      }



   // If the user wants to build grids for pre processing
   // TODO: Should this be an option?  There may be functions/features that will depend on this ... discuss!
   if(!myPreProcess)
      return;

   if(myVerbose > CLUSTER_MSG_INFO)
      cout << "VRAY_clusterThis::preProcess() Pre Processing Voxels" << std::endl;

//                     openvdb::ScalarGrid::Accessor accessor;
//                     openvdb::FloatTree myTree;
   openvdb::FloatTree::ConstPtr myGeoTreePtr;
   openvdb::VectorTree::ConstPtr myGeoGradTreePtr;

   ParticleList paGeoList(gdp, myPreVDBRadiusMult, myPreVDBVelocityMult);
   openvdb::tools::PointSampler myGeoSampler, geoGradSampler;
//                     openvdb::tools::GridSampling<openvdb::FloatTree>  myGridSampler;

   if(myVerbose == CLUSTER_MSG_DEBUG)
      std::cout << "VRAY_clusterThis::preProcess() paGeoList.size() ... "  << paGeoList.size() << std::endl;

   if(paGeoList.size() != 0) {

         hvdb::Interrupter boss("VRAY_clusterThis::preProcess() Converting particles to level set");

         Settings settings;
         settings.mRadiusMin = myPreRadiusMin;
         settings.mRasterizeTrails = myPreRasterType;
         settings.mDx = myPreDx;  // only used for rasterizeTrails()
         settings.mFogVolume = myPreFogVolume;
         settings.mGradientWidth = myPreGradientWidth;  // only used for fog volume

         float background;

         // background in WS units
         if(myPreWSUnits)
            background = myPreBandWidth;
         // background NOT in WS units
         else
            background = myPreVoxelSize * myPreBandWidth;

         // Construct a new scalar grid with the specified background value.
         openvdb::math::Transform::Ptr transform =
            openvdb::math::Transform::createLinearTransform(myPreVoxelSize);

//         openvdb::ScalarGrid::Ptr myGeoGrid = openvdb::ScalarGrid::create(background);

         myGeoGrid = openvdb::ScalarGrid::create(background);

         myGeoGrid->setTransform(transform);
         myGeoGrid->setGridClass(openvdb::GRID_LEVEL_SET);

         // Perform the particle conversion.
         this->convert(myGeoGrid, paGeoList, settings, boss);

         if(myVerbose == CLUSTER_MSG_DEBUG) {
               std::cout << "VRAY_clusterThis::preProcess() - activeVoxelCount(): "
                         << myGeoGrid->activeVoxelCount() << std::endl;
               std::cout << "VRAY_clusterThis::preProcess() - background: "
                         << myGeoGrid->background() << std::endl;
            }

         // Insert the new grid into the ouput detail.
         UT_String gridNameStr = "ClusterGrid";
         myGeoGrid->insertMeta("float type", openvdb::StringMetadata("averaged_velocity"));
         myGeoGrid->insertMeta("name", openvdb::StringMetadata((const char *)gridNameStr));
         myGeoGrid->insertMeta("VoxelSize", openvdb::FloatMetadata(myPreVoxelSize));
         myGeoGrid->insertMeta("background", openvdb::FloatMetadata(background));


         UT_Vector3 pos, seed_pos, currVel;
//         const GA_PointGroup * sourceGroup = NULL;
         long int pt_counter = 0;
         float radius = 5.0f;

         if(myVerbose > CLUSTER_MSG_INFO)
            std::cout << "VRAY_clusterThis::preProcess() - Massaging data ... " << std::endl;

         long int pointsFound = 0;
         GEO_AttributeHandle inst_vel_gah = gdp->getPointAttribute("v");
         GEO_AttributeHandle source_vel_gah = gdp->getPointAttribute("v");
         GEO_AttributeHandle inst_N_gah = gdp->getPointAttribute("N");
         GEO_AttributeHandle source_N_gah = gdp->getPointAttribute("N");
         GEO_AttributeHandle inst_Cd_gah = gdp->getPointAttribute("Cd");
         GEO_AttributeHandle source_Cd_gah = gdp->getPointAttribute("Cd");
         GEO_AttributeHandle inst_Alpha_gah = gdp->getPointAttribute("Alpha");
         GEO_AttributeHandle source_Alpha_gah = gdp->getPointAttribute("Alpha");

         if(!inst_vel_gah.isAttributeValid())
            throw VRAY_clusterThis_Exception("VRAY_clusterThis::preProcess() Instance velocity handle invalid, exiting ...", 1);
         if(!source_vel_gah.isAttributeValid())
            throw VRAY_clusterThis_Exception("VRAY_clusterThis::preProcess() Source velocity handle invalid, exiting ...", 1);
         if(!inst_N_gah.isAttributeValid())
            throw VRAY_clusterThis_Exception("VRAY_clusterThis::preProcess() Instance normal handle invalid, exiting ...", 1);
         if(!source_N_gah.isAttributeValid())
            throw VRAY_clusterThis_Exception("VRAY_clusterThis::preProcess() Source normal handle invalid, exiting ...", 1);
         if(!inst_Cd_gah.isAttributeValid())
            throw VRAY_clusterThis_Exception("VRAY_clusterThis::preProcess() Instance color handle invalid, exiting ...", 1);
         if(!source_Cd_gah.isAttributeValid())
            throw VRAY_clusterThis_Exception("VRAY_clusterThis::preProcess() Source color handle invalid, exiting ...", 1);
         if(!inst_Alpha_gah.isAttributeValid())
            throw VRAY_clusterThis_Exception("VRAY_clusterThis::preProcess() Instance alpha handle invalid, exiting ...", 1);
         if(!source_Alpha_gah.isAttributeValid())
            throw VRAY_clusterThis_Exception("VRAY_clusterThis::preProcess() Source alpha handle invalid, exiting ...", 1);

         openvdb::FloatTree::ValueType sampleResult;
         openvdb::VectorGrid::ValueType gradResult;
         const openvdb::FloatTree aTree;
         openvdb::FloatTree& myGeoTree = myGeoGrid->treeRW();

         openvdb::tools::Filter<openvdb::FloatGrid> preProcessFilter(*myGeoGrid);
//                           openvdb::tools::Filter<openvdb::FloatGrid> barFilter(myGeoGrid);

         if(myPreVDBMedianFilter)
            preProcessFilter.median();

         if(myPreVDBMeanFilter)
            preProcessFilter.mean();

         if(myPreVDBMeanCurvatureFilter)
            preProcessFilter.meanCurvature();

         if(myPreVDBLaplacianFilter)
            preProcessFilter.laplacian();

//                           if(myVDBReNormalizeFilter)
//                              float r = barFilter.renormalize(3, 0.1);

         if(myPreVDBOffsetFilter)
            preProcessFilter.offset(myPreVDBOffsetFilterAmount);


         myGradientGrid = openvdb::VectorGrid::create();
//         openvdb::VectorGrid::Ptr myGradientGrid = openvdb::VectorGrid::create();
         myGradientGrid->setTransform(transform);
//               myGradientGrid->setGridClass(openvdb::GRID_FOG_VOLUME );
         myGradientGrid->setGridClass(openvdb::GRID_LEVEL_SET);

         openvdb::tools::Gradient<openvdb::ScalarGrid> myGradient(*myGeoGrid);
         myGradientGrid = myGradient.process();
         openvdb::VectorTree& myGeoGradTree = myGradientGrid->treeRW();

         gridNameStr = "ClusterGradientGrid";
         myGradientGrid->insertMeta("vector type", openvdb::StringMetadata("covariant (gradient)"));
         myGradientGrid->insertMeta("name", openvdb::StringMetadata((const char *)gridNameStr));
         myGradientGrid->insertMeta("VoxelSize", openvdb::FloatMetadata(myPreVoxelSize));
         myGradientGrid->insertMeta("background", openvdb::FloatMetadata(background));


         GA_FOR_ALL_GPOINTS(gdp, ppt) {
//                              myCurrPtOff = ppt->getMapOffset();
//                              std::cout << "myCurrPtOff: " << myCurrPtOff << std::endl;

            pos = ppt->getPos();

// Vec3d worldToIndex   (  const Vec3d &     xyz    )    const

//                              openvdb::Vec3R theIndex =
//                                 (openvdb::Vec3R(pos[0], pos[1], pos[2]));
            openvdb::Vec3R theIndex =
               myGeoGrid->worldToIndex(openvdb::Vec3R(pos[0], pos[1], pos[2]));

            radius = static_cast<fpreal>(ppt->getValue<fpreal>(myInstAttrRefs.pointVDBRadius, 0));
//                                    std::cout << "radius: " << radius << std::endl;

// static bool    sample (const TreeT &inTree, const Vec3R &inCoord, typename TreeT::ValueType &sampleResult)
            const openvdb::Vec3R  inst_sample_pos(theIndex[0], theIndex[1], theIndex[2]);

            bool success = myGeoSampler.sample(myGeoTree, inst_sample_pos, sampleResult);

            geoGradSampler.sample(myGeoGradTree, inst_sample_pos, gradResult);
//
//                              std::cout << "success: " << success << "\tpos: " << pos
//                                        << "\tinst_sample_pos: " << inst_sample_pos
//                                        << "\tsampleResult: " << sampleResult << std::endl;

//ValueType    sampleWorld (const Vec3R &pt) const
//ValueType    sampleWorld (Real x, Real y, Real z) const

            // if the instanced point is within the vdb volume
            if(success) {
//                                    std::cout << "pos: " << pos << " inst_sample_pos: "
//                                              << inst_sample_pos << " sampleResult: " << sampleResult
//                                              << " gradResult: " << gradResult << std::endl;
//                                    float weight;
                  pointsFound++;

                  inst_vel_gah.setElement(ppt);
                  currVel = inst_vel_gah.getV3();

                  UT_Vector3 gradVect = UT_Vector3(gradResult[0], gradResult[1], gradResult[2]);

                  ppt->setPos(pos + (myPrePosInfluence *(sampleResult * gradVect)));
//                                    ppt->setPos(pos + (sampleResult * myPosInfluence *(currVel / myFPS)));

//                                    inst_vel_gah.setV3(currVel * ((1 / sampleResult) * radius));
                  inst_vel_gah.setV3(currVel + (myPreVelInfluence *(sampleResult * gradVect)));

//                                    std::cout << "currVel: " << currVel << " sampleResult " << sampleResult
//                                              << " new vel: " <<  currVel * sampleResult << std::endl;

                  inst_N_gah.setV3(inst_N_gah.getV3() + (myPreNormalInfluence *(sampleResult * gradVect)));

//                        inst_Cd_gah.setElement(ppt);
//                        inst_Cd_gah.setV3(inst_Cd_gah.getV3() * abs(sampleResult));
//
//
//                        inst_Alpha_gah.setElement(ppt);
//                        inst_Alpha_gah.setF(inst_Alpha_gah.getF() * abs(sampleResult));

               } // if the instanced point is within the vdb volume

            if(myVerbose == CLUSTER_MSG_DEBUG) {
                  pt_counter++;
                  if((long int)(pt_counter % (stat_interval * myNumCopies * myRecursion)) == 0) {
                        cout << "VRAY_clusterThis::preProcess() Number of points pre processed: " << pt_counter
                             << "\t - Number of points found in vdb grid: " << pointsFound << std::endl;
                     }
               }

         }
Beispiel #13
0
OP_ERROR
SOP_IntersectRay::cookMySop(OP_Context &context)
{
    double t;
    float  edgelength, primarea, generatepoints;
    int    verbose;

    // We optionally add points in self-penetration places:
    GB_PointGroup          *hitPointsGroup;
    UT_RefArray<UT_Vector3> hitPoints;

    if (lockInputs(context) >= UT_ERROR_ABORT)
	    return error();

    t = context.getTime();
    duplicatePointSource(0, context);

    edgelength     = EDGELENGTH(t);
    primarea       = PRIMAREA(t);
    verbose        = VERBOSE(t);
    generatepoints = GENERATEPOINTS(t);

    // Normals:
    GEO_AttributeHandle  nH;
    GEO_AttributeHandle  cdH;
    nH   = gdp->getAttribute(GEO_POINT_DICT, "N");
    cdH  = gdp->getAttribute(GEO_POINT_DICT, "Cd");
   

    // RayInfo parms:
    //float max = 1E18f; // Max specified by edge length...
    float min = 0.0f;
    float tol = 1e-1F;

    // Rayhit objects:
    GU_RayFindType  itype     = GU_FIND_ALL;   
    GU_RayIntersect intersect = GU_RayIntersect(gdp);

    // Profile:
    //Timer timer = Timer();
    //float rayhit_time = 0;
    //float vertex_time = 0;

    // Here we determine which groups we have to work on. 
    if (error() < UT_ERROR_ABORT && cookInputGroups(context) < UT_ERROR_ABORT)
    {
        UT_AutoInterrupt progress("Checking for self-intersections...");
        const GEO_Primitive   *ppr;
        FOR_ALL_GROUP_PRIMITIVES(gdp, myGroup, ppr)
	    {
             // Check if user requested abort
             if (progress.wasInterrupted())
                break;

            // Get rid of primitives smaller than primarea:
            if ( ppr->calcArea() < primarea )
                continue;

            for (int j = 0; j < ppr->getVertexCount() - 1; j++)
            {
                // Get data;
                // TODO: This is extremally inefficent.
                // TODO: Why do we crash with uv vetrex attributes!? 
                const GEO_Vertex ppv1 = ppr->getVertex(j);
                const GEO_Vertex ppv2 = ppr->getVertex(j+1);
                const GEO_Point *ppt1 = ppv1.getPt();
                const GEO_Point *ppt2 = ppv2.getPt();
               
                // Vertices positions:
                UT_Vector3 p1 = ppt1->getPos();
                UT_Vector3 p2 = ppt2->getPos();

                // Ray direction:
                p2   = p2 - p1;
                // Get rid of edges shorter than edgelength:
                if (p2.length() < edgelength)
                    continue;
                // hit info with max distance equal edge length:
                GU_RayInfo  hitinfo = GU_RayInfo(p2.length(), min, itype, tol); 
                p2.normalize();

                // Send ray:
                if (intersect.sendRay(p1, p2, hitinfo))
                {  
                    UT_RefArray<GU_RayInfoHit> hits = *(hitinfo.myHitList);
                    for(int j = 0; j < hits.entries(); j++)
                    {
                        const GEO_Primitive *prim = hits[j].prim;
                        const GEO_PrimPoly  *poly = (const GEO_PrimPoly *) prim; //TODO: Prims only?
                        // We are interested only ff points are not part of prims...:
                        if (poly->find(*ppt1) == -1 && poly->find(*ppt2)== -1)
                        {
                            if (verbose)
                                printf("Edge: %i-%i intersects with prim:%d \n",ppt1->getNum(), ppt2->getNum(), prim->getNum());

                            // Save hit position as points:
                            if (generatepoints)
                            {
                                UT_Vector4 pos;
                                float u = hits[j].u; 
                                float v = hits[j].v;
                                if (!prim->evaluateInteriorPoint(pos, u, v))
                                    hitPoints.append(pos);
                            }

                            // TODO: Should I indicate penetration with red color on both ends of edge?:
                            cdH.setElement(ppt1);
                            cdH.setV3(UT_Vector3(1.0, 0.0, 0.0));
                            cdH.setElement(ppt2);
                            cdH.setV3(UT_Vector3(1.0, 0.0, 0.0));
                        }
                        
                    }
                }
            }
	    } 
     
   
    if (generatepoints)
    {
        hitPointsGroup = gdp->newPointGroup("__self_penetrate", false);
        for (int i = 0; i < hitPoints.entries(); i++)
        {
            GEO_Point *point;
            point = gdp->appendPoint();
            hitPointsGroup->add(point);
            point->setPos(hitPoints(i));
        }
    }
    
    }
Beispiel #14
0
OP_ERROR SOP_Scallop::cookMySop(OP_Context &context)
{
        //OP_Node::flags().timeDep = 1;

        bool clip = (lockInputs(context) < UT_ERROR_ABORT);

        UT_BoundingBox bbox;

        if(clip)
        {
                const GU_Detail* input = inputGeo(0,context);
                if(input != NULL)
                {
                        //UT_Matrix4 bm;
                        int res = input->getBBox(&bbox);
                        if(res == 0) clip = false;
                }
                else clip = false;
                unlockInputs();
        };

        float now = context.getTime();

        Daemon::now=now;
        Daemon::caller=this;

        Daemon::bias = evalFloat("bias",0,now);

        UT_Ramp ramp;
        float   rampout[4];

        bool useRamp = (evalInt("parmcolor",0,now)!=0);

        if(useRamp)
        {
                //PRM_Template *rampTemplate = PRMgetRampTemplate ("ramp", PRM_MULTITYPE_RAMP_RGB, NULL, NULL);
                if (ramp.getNodeCount () < 2)
                {
                        ramp.addNode (0, UT_FRGBA (0, 0, 0, 1));
                        ramp.addNode (1, UT_FRGBA (1, 1, 1, 1));
                };
                updateRampFromMultiParm(now, getParm("ramp"), ramp);
        };

        gdp->clearAndDestroy();

        bool showPts = (evalInt("showpts",0,now)!=0);

		/*
        if(showPts)
        {
                float sz = evalInt("ptssz",0,now);
                if(sz > 0)
                {
                        float one = 1.0f;

                        gdp->addAttribute("showpoints",4,GA_ATTRIB_FLOAT_&one);
                        gdp->addAttribute("revealsize",4,GB_ATTRIB_FLOAT,&sz);
                };
        };
		*/

        int cnt = evalInt("daemons", 0, now);

        Daemon* daemons=new Daemon[cnt];

        float weights = 0;

        int totd=0;

        for(int i=1;i<=cnt;i++)
        {
                bool skip = (evalIntInst("enabled#",&i,0,now)==0);
                if(skip) continue;

                Daemon& d = daemons[totd];

                UT_String path = "";
                evalStringInst("obj#", &i, path, 0, now);

                if(path == "") continue;

                SOP_Node* node = getSOPNode(path);

                OBJ_Node* obj = dynamic_cast<OBJ_Node*>(node->getParent());

                if(obj == NULL) continue;

                addExtraInput(obj, OP_INTEREST_DATA);

                //d.xform  = obj->getWorldTransform(context); // 10.0
                obj->getWorldTransform(d.xform, context);

                d.weight = evalFloatInst("weight#",&i,0,now);

                if(!useRamp)
                {
                        d.c[0] = evalFloatInst("color#",&i,0,now);
                        d.c[1] = evalFloatInst("color#",&i,1,now);
                        d.c[2] = evalFloatInst("color#",&i,2,now);
                };

                int mth = evalIntInst("model#",&i,0,now);

                switch(mth)
                {
                case 1:
                        d.method = Methods::Spherical;
                        break;
                case 2:
                        d.method = Methods::Polar;
                        break;
                case 3:
                        d.method = Methods::Swirl;
                        break;
                case 4:
                        d.method = Methods::Trigonometric;
                        break;
                case 5:
                        {
                                UT_String script;
                                evalStringInst("vexcode#", &i, script, 0, now);
                                d.SetupCVEX(script);
                                if(d.useVex)
                                {
                                        OP_Node* shop = (OP_Node*)findSHOPNode(script);
                                        addExtraInput(shop, OP_INTEREST_DATA);
                                }
                                break;
                        }
                case 0:
                default:
                        d.method = Methods::Linear;
                };

                d.power = evalFloatInst("power#",&i,0,now);
                d.radius = evalFloatInst("radius#",&i,0,now);
                d.parameter = evalFloatInst("parameter#",&i,0,now);

                weights+=d.weight;
                totd++;
        };

        if(totd == 0)
        {
                delete [] daemons;
                return error();
        }

        float base = 0.0;
        for(int i=0;i<totd;i++)
        {
                Daemon& d = daemons[i];
                d.range[0]=base;
                d.range[1] = base+d.weight/weights;
                base=d.range[1];
        };

        int total = evalInt("count",0,now);
        int degr = evalInt("degr",0,now);

        total >>= degr;

		GA_RWHandleI cntt(gdp->addIntTuple(GA_ATTRIB_POINT, "count", 4, GA_Defaults(1.0)));


        GB_AttributeRef dt(gdp->addDiffuseAttribute(GEO_POINT_DICT));
        gdp->addVariableName("Cd","Cd");

        UT_Vector3 current(0,0,0);
        float C[3] = { 0,0,0 };

        float R=1.0f;
        bool trackRadii = (evalInt("trackradii",0,now)!=0);
        float rScale = evalFloat("radiiscale",0,now);
        GB_AttributeRef rt;
        if(trackRadii)
        {
                float one=1.0f;
                rt = gdp->addPointAttrib("width",4,GB_ATTRIB_FLOAT,&one);
                if(!GBisAttributeRefValid(rt)) trackRadii=false;
                else gdp->addVariableName("width","WIDTH");
        };

        float zero=0.0f;
        GB_AttributeRef pt = gdp->addPointAttrib("parameter",4,GB_ATTRIB_FLOAT,&zero);
        if(GBisAttributeRefValid(pt)) gdp->addVariableName("parameter","PARAMETER");
        float param=0.0f;

        srand(0);

        UT_Interrupt* boss = UTgetInterrupt();
        boss->opStart("Computing...");

        for(int i=-50;i<total;i++)
        {
                bool ok = false;

                if (boss->opInterrupt()) break;

                float w = double(rand())/double(RAND_MAX);

                for(int j=0;j<totd;j++)
                {
                        ok = daemons[j].Transform(w,current,C,R,param);
                        if(ok) break;
                };

                if(i<0) continue;

                if(clip)
                {
                        if(!bbox.isInside(current)) continue;
                };

                if(ok)
                {
                        GEO_Point* p = gdp->appendPoint();
                        p->setPos(current);

                        float* Cd=p->castAttribData<float>(dt);
                        if(useRamp)
                        {
                                ramp.rampLookup(param,C);
                        }
                        memcpy(Cd,C,12);

                        if(trackRadii)
                        {
                                float* _R = p->castAttribData<float>(rt);
                                *_R=rScale*R;
                        };

                        if(GBisAttributeRefValid(pt))
                        {
                                float* _p = p->castAttribData<float>(pt);
                                *_p=param;
                        }
                };
        };

        boss->opEnd();

        delete [] daemons;

        return error();
};
Beispiel #15
0
OP_ERROR
SOP_Ocean::cookMySop(OP_Context &context)
{
    float now = context.getTime();

    //std::cout << "cook ocean, t = " << now << std::endl;

    // lock inputs
    if (lockInputs(context) >= UT_ERROR_ABORT )
    {
        return error();
    }


    GEO_Point		*ppt;
    UT_Interrupt	*boss;

    // Check to see that there hasn't been a critical error in cooking the SOP.
    if (error() < UT_ERROR_ABORT)
    {
        boss = UTgetInterrupt();

        // Start the interrupt server
        boss->opStart("Updating Ocean");

        duplicatePointSource(0,context);

        int   gridres  = 1 << int(GRID_RES(now));
        float stepsize = GRID_SIZE(now) / (float)gridres;

        bool do_chop     = CHOP(now);
        bool do_jacobian = JACOBIAN(now);
        bool do_normals  = NORMALS(now) && !do_chop;

        if (!_ocean || _ocean_needs_rebuild)
        {
            if (_ocean)
            {
                delete _ocean;
            }

            if (_ocean_context)
            {
                delete _ocean_context;
            }

            _ocean = new drw::Ocean(gridres,gridres,stepsize,stepsize,
                                    V(0),L(0),1.0,W(0),1-DAMP(0),ALIGN(0),
                                    DEPTH(0),SEED(0));
            _ocean_scale   = _ocean->get_height_normalize_factor();

            _ocean_context = _ocean->new_context(true,do_chop,do_normals,do_jacobian);

            _ocean_needs_rebuild = false;
//             std::cout << "######### SOP, rebuilt ocean, norm_factor = " << _ocean_scale 
//                       << " chop = " << do_chop 
//                       << " norm = " << do_normals
//                       << " jacobian = " << do_jacobian
//                       << std::endl;
        }

        float chop_amount = CHOPAMOUNT(now);

        // sum up the waves at this timestep
        _ocean->update(TIME(now),*_ocean_context,true,do_chop,do_normals,do_jacobian,
                       _ocean_scale * SCALE(now),chop_amount);

        bool linterp = ! INTERP(now);


        // get our attribute indices
        GA_RWAttributeRef normal_index;
        GA_RWAttributeRef jminus_index;
        GA_RWAttributeRef eminus_index;

        if (do_normals)
        {
            normal_index = gdp->addNormalAttribute(GEO_POINT_DICT);
        }
        if (do_jacobian)
        {
            // jminus_index = gdp->addPointAttrib("mineigval",sizeof(float),GB_ATTRIB_FLOAT,0);
            // eminus_index = gdp->addPointAttrib("mineigvec",sizeof(UT_Vector3),GB_ATTRIB_VECTOR,0);
            jminus_index = gdp->addTuple(GA_STORE_REAL32,GA_ATTRIB_POINT,"mineigval",1,GA_Defaults(0));
            eminus_index = gdp->addFloatTuple(GA_ATTRIB_POINT,"mineigvec",1,GA_Defaults(0));
        }

        // this is not that fast, can it be done quicker ???
        GA_FOR_ALL_GPOINTS(gdp, ppt)
            {
                UT_Vector4 p = ppt->getPos();

                
                if (linterp)
                {
                    _ocean_context->eval_xz(p(0),p(2));
                }
                else
                {
                    _ocean_context->eval2_xz(p(0),p(2));
                }

                if (do_chop) 
                {
                    p.assign( p(0) + _ocean_context->disp[0],
                              p(1) + _ocean_context->disp[1],
                              p(2) + _ocean_context->disp[2] );
                }
                else
                {
                    // ppt->getPos()(1) += _ocean_context->disp[1];
                	UT_Vector4 tmp_p = ppt->getPos();
                	tmp_p(1) += _ocean_context->disp[1];
                	ppt->setPos(tmp_p);
                }

                if (do_normals)
                {
                	/*
					  UT_Vector3* normal = (UT_Vector3*) ppt->castAttribData<UT_Vector3>(normal_index);
					  normal->assign(_ocean_context->normal[0],
					                 _ocean_context->normal[1],
					                 _ocean_context->normal[2]);
					  normal->normalize();
                    */
                	ppt->getValue<UT_Vector3>(normal_index).assign(_ocean_context->normal[0],
																   _ocean_context->normal[1],
																   _ocean_context->normal[2]);
                	ppt->getValue<UT_Vector3>(normal_index).normalize();
                }

                if (do_jacobian)
                {/*
                    float *js = (float*)ppt->castAttribData<float>(jminus_index);
                    *js = _ocean_context->Jminus;
                    UT_Vector3* eminus = (UT_Vector3*)ppt->castAttribData<UT_Vector3>(eminus_index);
                    eminus->assign(_ocean_context->Eminus[0],0,_ocean_context->Eminus[1]);
                    */
                    ppt->setValue<float>(jminus_index,_ocean_context->Jminus);
                    ppt->getValue<UT_Vector3>(eminus_index).assign(_ocean_context->Eminus[0],0,_ocean_context->Eminus[1]);
                }
				ppt->setPos(p);
            }
Beispiel #16
0
// the bit that does all the work
OP_ERROR SOP_rmanPtc::cookMySop(OP_Context &context)
{
    // get some useful bits & bobs
    UT_Interrupt *boss;
    float now = context.myTime;
    UT_String ptcFile = getPtcFile(now);
    int loadPercentage = getLoadPercentage(now);
    int displayPercentage = getDisplayPercentage(now);
    float pointSize = getPointSize(now);
    int useDisk = getUseDisk(now);
    int boundOnLoad = getBoundOnLoad(now);
    int displayChannel = getDisplayChannel(now);
    int onlyOutputDisplayChannel = getOnlyOutputDisplayChannel(now);
    /*
      float nearDensity = getNearDensity(now);
      float farDensity = getFarDensity(now);
      UT_String cullCamera = getCullCamera(now);
    */

    // lock out inputs
    if ( lockInputs(context) >= UT_ERROR_ABORT)
        error();

    // Check to see that there hasn't been a critical error in cooking the SOP.
    if (error() < UT_ERROR_ABORT)
    {
        boss = UTgetInterrupt();

        // here we make sure our detail is an instance of rmanPtcDetail
        rmanPtcDetail *ptc_gdp = dynamic_cast<rmanPtcSop::rmanPtcDetail *>(gdp);
        if ( !ptc_gdp )
            ptc_gdp = allocateNewDetail();

        // clear our gdp
        ptc_gdp->clearAndDestroy();

        // start our work
        boss->opStart("Loading point cloud");

        // get our bbox
        bool has_bbox = false;
        const GU_Detail *input_geo = inputGeo( 0, context );
        updateBBox( input_geo );

        // pass information to our detail
        ptc_gdp->point_size = pointSize;
        ptc_gdp->use_disk = useDisk;
        ptc_gdp->cull_bbox = mBBox;
        ptc_gdp->use_cull_bbox = (mHasBBox&&(!mBoundOnLoad))?true:false;
        ptc_gdp->display_probability = displayPercentage/100.f;
        ptc_gdp->display_channel = displayChannel;
        if ( onlyOutputDisplayChannel )
            ptc_gdp->display_channel = 0;

        // here we load our ptc
        if ( mReload )
        {            
            // clear everything
            mChannelNames.clear();
            cachePoints.clear();
            cacheNormals.clear();
            cacheRadius.clear();
            cacheData.clear();
            mRedraw = true;
            
            // open the point cloud
            PtcPointCloud ptc = PtcSafeOpenPointCloudFile(
                    const_cast<char*>(ptcFile.buffer()) );
            if ( !ptc )
            {
                UT_String msg( "Unable to open input file: " );
                msg += ptcFile;
                addError( SOP_MESSAGE, msg);
                boss->opEnd();
                return error();
            }

            // get some information from the ptc
            ptc_gdp->path = std::string(ptcFile.fileName());
            char **vartypes, **varnames;
            PtcGetPointCloudInfo( ptc, const_cast<char*>("npoints"),
                    &ptc_gdp->nPoints );
            PtcGetPointCloudInfo( ptc, const_cast<char*>("npointvars"),
                    &ptc_gdp->nChannels );
            PtcGetPointCloudInfo( ptc, const_cast<char*>("pointvartypes"),
                    &vartypes );
            PtcGetPointCloudInfo( ptc, const_cast<char*>("pointvarnames"),
                    &varnames );
            PtcGetPointCloudInfo( ptc, const_cast<char*>("datasize"),
                    &ptc_gdp->datasize );
            PtcGetPointCloudInfo( ptc, const_cast<char*>("bbox"),
                    ptc_gdp->bbox );

            // process our channel names
            ptc_gdp->types.clear();
            ptc_gdp->names.clear();
            for ( unsigned int i=0; i<ptc_gdp->nChannels; ++i )
            {
                ptc_gdp->types.push_back( std::string(vartypes[i]) );
                ptc_gdp->names.push_back( std::string(varnames[i]) );
                std::string name = ptc_gdp->types[i] + " " + ptc_gdp->names[i];
                mChannelNames.push_back( name );
            }

            // what percentage of points should we load?
            float load_probability = loadPercentage/100.f;

            // load points into memory
            float point[3], normal[3];
            float radius;
            float data[ptc_gdp->datasize];
            srand(0);
            for ( unsigned int i=0; i<ptc_gdp->nPoints; ++i )
            {
                PtcReadDataPoint( ptc, point, normal, &radius, data );

                // bound on load
                if ( boundOnLoad )
                {
                    UT_Vector3 pt( point[0], point[1], point[2] );
                    if ( !mBBox.isInside(pt) )
                        continue;
                }

                // discard a percentage of our points
                if ( rand()/(float)RAND_MAX>load_probability )
                    continue;

                // put points into our cache
                cachePoints.push_back( point );
                cacheNormals.push_back( normal );
                cacheRadius.push_back( radius );
                for ( unsigned int j=0; j<ptc_gdp->datasize; ++j )
                    cacheData.push_back( data[j] );

                // break for the interrupt handler (i.e. press ESC)
                if ( boss->opInterrupt() )
                    break;
            }
            ptc_gdp->nLoaded = cachePoints.size();

            // mark our detail as valid and close our ptc
            PtcClosePointCloudFile( ptc );
            mReload = false;

            // force update on channel parameter
            getParm("chan").revertToDefaults(now);
        }

        // build a new primitive
        GU_PrimParticle::build( ptc_gdp, cachePoints.size(), 0 );

        // create our output geometry using the output % parameter
        // this is the same variable as GR_ uses to preview
        std::vector<UT_Vector3>::const_iterator pos_it = cachePoints.begin();
        std::vector<UT_Vector3>::const_iterator norm_it = cacheNormals.begin();
        std::vector<float>::const_iterator rad_it = cacheRadius.begin();
        std::vector<float>::const_iterator data_it = cacheData.begin();

        // add some standard attributes
        GB_AttributeRef n_attrib = ptc_gdp->addPointAttrib( "N", sizeof(UT_Vector3),
                GB_ATTRIB_VECTOR, 0 );
        GB_AttributeRef r_attrib = ptc_gdp->addPointAttrib( "radius", sizeof(float),
                GB_ATTRIB_FLOAT, 0 );
        ptc_gdp->N_attrib = n_attrib;
        ptc_gdp->R_attrib = r_attrib;

        // process the rest of our data attributes
        std::vector<GB_AttribType> data_types;
        std::vector<GB_AttributeRef> data_attribs;
        std::vector<int> data_size, data_offset;
        int offset_total = 0;
        ptc_gdp->attributes.clear();
        ptc_gdp->attribute_size.clear();
        for ( unsigned int i=0; i<ptc_gdp->nChannels; ++i )
        {
            GB_AttribType type = GB_ATTRIB_FLOAT; // float, vector
            int size = 1;
            if ( ptc_gdp->types[i] == "point" ||
                    ptc_gdp->types[i] == "vector" ||
                    ptc_gdp->types[i] == "normal" )
            {
                type = GB_ATTRIB_VECTOR;
                size = 3;
            }
            if ( ptc_gdp->types[i] == "color" )
            {
                size=3;
            }
            if ( ptc_gdp->types[i] == "matrix" )
            {
                size=16;
            }
            offset_total += size;

            data_types.push_back( type );
            data_size.push_back( size );
            data_offset.push_back( offset_total );

            if ( onlyOutputDisplayChannel )
            {
                if ( displayChannel==i )
                {
                    GB_AttributeRef attrib = ptc_gdp->addPointAttrib(
                            ptc_gdp->names[i].c_str(), sizeof(float)*size,
                            type, 0 );
                    ptc_gdp->attributes.push_back( attrib );
                    ptc_gdp->attribute_size.push_back( size );
                    data_attribs.push_back( attrib );
                }
            }
            else
            {
                GB_AttributeRef attrib = ptc_gdp->addPointAttrib( ptc_gdp->names[i].c_str(),
                        sizeof(float)*size, type, 0 );
                ptc_gdp->attributes.push_back( attrib );
                ptc_gdp->attribute_size.push_back( size );
                data_attribs.push_back( attrib );
            }
        }
        cacheDataOffsets = data_offset;

/*
        // cull camera
        bool use_cull_cam = false;
        UT_Vector3 cam_pos(0,0,0);
        float cam_near=0.0, cam_far=0.0;

        if ( cullCamera!="" )
        {
            OBJ_Node *cam_node = OPgetDirector()->findOBJNode( cullCamera );
            if ( cam_node )
            {
                OBJ_Camera *cam = cam_node->castToOBJCamera();
                if ( cam )
                {
                    UT_DMatrix4 mtx;
                    cam->getWorldTransform( mtx, context );
                    std::cerr << "mtx: " << mtx << std::endl;
                    cam_pos *= mtx;
                    std::cerr << "pos: " << cam_pos << std::endl;
                    use_cull_cam = true;
                    cam_near = cam->getNEAR(now);
                    cam_far = cam->getFAR(now);
                    std::cerr << "near: " << cam_near << std::endl;
                    std::cerr << "far: " << cam_far << std::endl;

                    mRedraw = true;
                }
            }
            std::cerr << "cull camera: " << cullCamera << std::endl;
            std::cerr << nearDensity << ", " << farDensity << std::endl;
        }
*/
        // add data from our cached points to geometry
        // based on display/output probability
        srand(0);
        float density_mult = 1.f;
        while( pos_it!=cachePoints.end() )
        {

/*            
            if ( use_cull_cam )
            {
                float dist = ((*pos_it)-cam_pos).length();
                if ( dist<cam_near )
                    density_mult = nearDensity;
                else if ( dist>cam_far )
                    density_mult = farDensity;
                else
                {
                    float normalize_dist =( dist - cam_near ) / ( cam_far - cam_near );
                    density_mult = 1.f - normalize_dist;
                }
            }
*/

            if ( rand()/(float)RAND_MAX <
                    ptc_gdp->display_probability*density_mult )
            {
                if ( (!ptc_gdp->use_cull_bbox) ||
                        (ptc_gdp->use_cull_bbox &&
                                ptc_gdp->cull_bbox.isInside( *pos_it ) ) )
                {
                    // add to our SOP geometry
                    GEO_Point *pt = ptc_gdp->appendPoint();
                    pt->setPos( *pos_it );
                    (*pt->castAttribData<UT_Vector3>(n_attrib)) = *norm_it;
                    (*pt->castAttribData<float>(r_attrib)) = *rad_it;
                    const float *data = &*data_it;
                    for ( unsigned int i=0; i<data_types.size(); ++i )
                    {
                        if ( onlyOutputDisplayChannel )
                        {
                            if ( i==displayChannel )
                            {
                                pt->set( data_attribs[0], data, data_size[i] );
                            }
                            data += data_size[i];
                        }
                        else
                        {
                            pt->set( data_attribs[i], data, data_size[i] );
                            data += data_size[i];
                        }
                    }
                }
            }

            // increment our interators
            pos_it++;
            norm_it++;
            rad_it++;
            data_it+=ptc_gdp->datasize;
        }

        // delete our particle primitive
        ptc_gdp->deletePrimitive(0,0);
        
        // info in sop's message area
        std::stringstream ss;
        ss << "Name: " << ptc_gdp->path << std::endl;
        ss << "Points: " << ptc_gdp->nPoints << " - [ " <<
                ptc_gdp->nLoaded << " loaded ]" << std::endl;
        ss << "Channels: " << ptc_gdp->nChannels << std::endl;
        for ( unsigned int i=0; i<ptc_gdp->nChannels; ++i )
            ss << "  " << i << ": " << mChannelNames[i] << std::endl;
        addMessage( SOP_MESSAGE, ss.str().c_str() );

        // Tell the interrupt server that we've completed
        boss->opEnd();

        // force update?
        ptc_gdp->redraw = mRedraw;
        mRedraw = false;
    }

    // tidy up & go home
    unlockInputs();
    return error();
}
/* ******************************************************************************
*  Function Name : instanceCurve()
*
*  Description : Instance a curve
*
*  Input Arguments : GU_Detail *inst_gdp, GU_Detail *mb_gdp
*
*  Return Value : int
*
***************************************************************************** */
int VRAY_clusterThis::instanceCurve(GU_Detail * inst_gdp, GU_Detail * mb_gdp, fpreal theta, long int point_num)
{
#ifdef DEBUG
   std::cout << "VRAY_clusterThis::instanceCurve()" << std::endl;
#endif

   GEO_Point * ppt;
   GU_PrimNURBCurve * myCurve, * myMBCurve;
   uint32 num_vtx;
   int myCurvePointNum = 0;
   UT_Vector4 pt_pos;
   GU_Detail * curve_gdp, * curve_mb_gdp;

   curve_gdp = allocateGeometry();

   GA_RWAttributeRef prim_Cd = curve_gdp->addDiffuseAttribute(GEO_PRIMITIVE_DICT);
   GA_RWAttributeRef prim_Alpha = curve_gdp->addAlphaAttribute(GEO_PRIMITIVE_DICT);
   GA_RWAttributeRef prim_v = curve_gdp->addVelocityAttribute(GEO_PRIMITIVE_DICT);
   GA_RWAttributeRef prim_N = curve_gdp->addNormalAttribute(GEO_PRIMITIVE_DICT);
   GA_RWAttributeRef prim_material = curve_gdp->addStringTuple(GEO_PRIMITIVE_DICT, "shop_materialpath", 1);

   GA_RWAttributeRef pt_Cd = curve_gdp->addDiffuseAttribute(GEO_POINT_DICT);
   GA_RWAttributeRef pt_Alpha = curve_gdp->addAlphaAttribute(GEO_POINT_DICT);
   GA_RWAttributeRef pt_v = curve_gdp->addVelocityAttribute(GEO_POINT_DICT);
   GA_RWAttributeRef pt_N = curve_gdp->addNormalAttribute(GEO_POINT_DICT);
   GA_RWAttributeRef pt_pscale = curve_gdp->addFloatTuple(GA_ATTRIB_POINT, "pscale", 1);
   GA_RWAttributeRef pt_width = curve_gdp->addFloatTuple(GA_ATTRIB_POINT, "width", 1);
   GA_RWAttributeRef pt_id = curve_gdp->addIntTuple(GA_ATTRIB_POINT, "id", 1);
   GA_RWAttributeRef pt_instId = curve_gdp->addIntTuple(GA_ATTRIB_POINT, "inst_id", 1);
   GA_RWAttributeRef pt_material = curve_gdp->addStringTuple(GA_ATTRIB_POINT, "shop_materialpath", 1);

   GA_RWAttributeRef pt_mb_Cd;
   GA_RWAttributeRef pt_mb_Alpha;
   GA_RWAttributeRef pt_mb_v;
   GA_RWAttributeRef pt_mb_N;
   GA_RWAttributeRef pt_mb_pscale;
   GA_RWAttributeRef pt_mb_width;
   GA_RWAttributeRef pt_mb_id;
   GA_RWAttributeRef pt_mb_instId;
   GA_RWAttributeRef pt_mb_material;

   num_vtx = ((myNumCopies * myRecursion) > 4) ? (myNumCopies * myRecursion) : 4;
   myCurve = (GU_PrimNURBCurve *)GU_PrimNURBCurve::build((GU_Detail *)curve_gdp, num_vtx, 4, 0, 1, 1);

   myCurve->setValue<UT_Vector3>(prim_Cd, (const UT_Vector3)myPointAttributes.Cd);
   myCurve->setValue<fpreal>(prim_Alpha, (const fpreal)myPointAttributes.Alpha);
   myCurve->setString(prim_material, myPointAttributes.material);

//   cout << "VRAY_clusterThis::instanceCurve() - num vertices: " << myCurve->getVertexCount() << endl;;
//   cout << "id: "  << myCurve->getPrimitiveId() << endl;
//   cout << "breakCount: "  << myCurve->breakCount() << endl;

   if(myDoMotionBlur == CLUSTER_MB_DEFORMATION) {
         curve_mb_gdp = allocateGeometry();
         myMBCurve = (GU_PrimNURBCurve *)GU_PrimNURBCurve::build((GU_Detail *)curve_mb_gdp, num_vtx, 4, 0, 1, 1);
         pt_mb_Cd = curve_gdp->addDiffuseAttribute(GEO_POINT_DICT);
         pt_mb_Alpha = curve_gdp->addAlphaAttribute(GEO_POINT_DICT);
         pt_mb_v = curve_gdp->addVelocityAttribute(GEO_POINT_DICT);
         pt_mb_N = curve_gdp->addNormalAttribute(GEO_POINT_DICT);
         pt_mb_pscale = curve_gdp->addFloatTuple(GA_ATTRIB_POINT, "pscale", 1);
         pt_mb_width = curve_gdp->addFloatTuple(GA_ATTRIB_POINT, "width", 1);
         pt_mb_id = curve_gdp->addIntTuple(GA_ATTRIB_POINT, "id", 1);
         pt_mb_instId = curve_gdp->addIntTuple(GA_ATTRIB_POINT, "inst_id", 1);
         pt_mb_material = curve_gdp->addStringTuple(GA_ATTRIB_POINT, "shop_materialpath", 1);
      }


   for(int copyNum = 0; copyNum < myNumCopies; copyNum++)
      for(int recursionNum = 0; recursionNum < myRecursion; recursionNum++) {

            VRAY_clusterThis::calculateNewPosition(theta, copyNum, recursionNum);
            ppt = myCurve->getVertexElement(myCurvePointNum).getPt();
            ppt->setPos((float)myPointAttributes.myNewPos[0],
                        (float)myPointAttributes.myNewPos[1],
                        (float)myPointAttributes.myNewPos[2], 1.0);

            // Assign attributes to each point
            ppt->setValue<UT_Vector3>(pt_Cd, (const UT_Vector3)myPointAttributes.Cd);
            ppt->setValue<fpreal>(pt_Alpha, (const fpreal)myPointAttributes.Alpha);
            ppt->setValue<UT_Vector3>(pt_v, (const UT_Vector3)myPointAttributes.v);
            ppt->setValue<UT_Vector3>(pt_N, (const UT_Vector3)myPointAttributes.N);
            ppt->setValue<fpreal>(pt_pscale, (const fpreal)myPointAttributes.pscale);
            ppt->setValue<fpreal>(pt_width, (const fpreal)myPointAttributes.width);
            ppt->setValue<int>(pt_id, (const int)myPointAttributes.id);
            ppt->setValue<int>(pt_instId, (const int)myCurvePointNum);
            ppt->setString(pt_material, myPointAttributes.material);

            if(myDoMotionBlur == CLUSTER_MB_DEFORMATION) {
                  ppt = myMBCurve->getVertexElement(myCurvePointNum).getPt();
                  ppt->setPos((float)myPointAttributes.myNewPos[0],
                              (float)myPointAttributes.myMBPos[1],
                              (float)myPointAttributes.myMBPos[2], 1.0);

                  // Assign attributes to each point
                  ppt->setValue<UT_Vector3>(pt_mb_Cd, (const UT_Vector3)myPointAttributes.Cd);
                  ppt->setValue<fpreal>(pt_mb_Alpha, (const fpreal)myPointAttributes.Alpha);
                  ppt->setValue<UT_Vector3>(pt_mb_v, (const UT_Vector3)myPointAttributes.v);
                  ppt->setValue<UT_Vector3>(pt_mb_N, (const UT_Vector3)myPointAttributes.N);
                  ppt->setValue<fpreal>(pt_mb_pscale, (const fpreal)myPointAttributes.pscale);
                  ppt->setValue<fpreal>(pt_mb_width, (const fpreal)myPointAttributes.width);
                  ppt->setValue<int>(pt_mb_id, (const int)myPointAttributes.id);
                  ppt->setValue<int>(pt_mb_instId, (const int)myInstanceNum);
                  ppt->setString(pt_mb_material, myPointAttributes.material);
               }
//            std::cout << "VRAY_clusterThis::instanceCurve() myCurvePointNum: " << myCurvePointNum << std::endl;
            myCurvePointNum++;
         }

//   myCurve->close();
//   myMBCurve->close ();

   if(myCVEX_Exec)
      VRAY_clusterThis::runCVEX(curve_gdp, curve_mb_gdp, myCVEXFname, CLUSTER_CVEX_POINT);

   if(myCVEX_Exec_prim)
      VRAY_clusterThis::runCVEX(curve_gdp, curve_mb_gdp, myCVEXFname_prim, CLUSTER_CVEX_PRIM);

   inst_gdp->merge(*curve_gdp);
   VRAY_Procedural::freeGeometry(curve_gdp);
   if(myDoMotionBlur == CLUSTER_MB_DEFORMATION) {
         mb_gdp->merge(*curve_mb_gdp);
         VRAY_Procedural::freeGeometry(curve_mb_gdp);
      }

   return 0;
}
void add_simple_mesh(GU_Detail& gdp,
	const dgal::simple_mesh<Imath::V3f>& smesh,
	const std::string& pointIDAttrib, const std::vector<int>* pointIDs,
	const std::string& polyIDAttrib, const std::vector<int>* polyIDs,
	const std::string& cellTypeAttrib, unsigned int cellType,
	const std::string& cellIDAttrib, unsigned int cellID)
{
	unsigned int first_point = gdp.points().entries();
	unsigned int first_prim = gdp.primitives().entries();

	// create dest points
	for(std::vector<Imath::V3f>::const_iterator it=smesh.m_points.begin();
		it!=smesh.m_points.end(); ++it)
	{
		GEO_Point* pt = gdp.appendPoint();
		pt->setPos(it->x, it->y, it->z);
	}

	GEO_PointList& points = gdp.points();
	GEO_PrimList& prims = gdp.primitives();

	// create dest polys
	for(unsigned int i=0; i<smesh.m_polys.size(); ++i)
	{
		const std::vector<unsigned int>& cpoly = smesh.m_polys[i];

		GEO_PrimPoly* poly = GU_PrimPoly::build(&gdp, cpoly.size(), GU_POLY_CLOSED, 0);
		for(unsigned int j=0; j<cpoly.size(); ++j)
			poly->getVertex(j).setPt(points[cpoly[j] + first_point]);
	}

	// create cell-type attribute
	if(!cellTypeAttrib.empty())
	{
		int defaultv = -1;
		GB_AttributeRef aref = gdp.addAttribute(cellTypeAttrib.c_str(), sizeof(int),
			GB_ATTRIB_INT, &defaultv, GEO_PRIMITIVE_DICT);

		if(aref.isValid())
		{
			unsigned int npolys = prims.entries();
			for(unsigned int i=first_prim; i<npolys; ++i)
				prims[i]->setValue<int32>(aref, static_cast<int>(cellType));
		}
	}

	// create cell-id attribute
	if(!cellIDAttrib.empty())
	{
		int defaultv = -1;
		GB_AttributeRef aref = gdp.addAttribute(cellIDAttrib.c_str(), sizeof(int),
			GB_ATTRIB_INT, &defaultv, GEO_PRIMITIVE_DICT);

		if(aref.isValid())
		{
			unsigned int npolys = prims.entries();
			for(unsigned int i=first_prim; i<npolys; ++i)
				prims[i]->setValue<int32>(aref, static_cast<int>(cellID));
		}
	}

	// create point-id attribute
	if(!pointIDAttrib.empty())
	{
		int defaultv = -1;
		GB_AttributeRef aref = gdp.addAttribute(pointIDAttrib.c_str(), sizeof(int),
			GB_ATTRIB_INT, &defaultv, GEO_POINT_DICT);

		if(aref.isValid() && pointIDs)
		{
			unsigned int sz = std::min(points.entries()-first_point,
				static_cast<unsigned int>(pointIDs->size()));

			for(unsigned int i=0; i<sz; ++i)
				points[i + first_point]->setValue<int32>(aref, (*pointIDs)[i]);
		}
	}

	// create poly-id attribute
	if(!polyIDAttrib.empty())
	{
		int defaultv = 0;
		GB_AttributeRef aref = gdp.addAttribute(polyIDAttrib.c_str(), sizeof(int),
			GB_ATTRIB_INT, &defaultv, GEO_PRIMITIVE_DICT);

		if(aref.isValid() && polyIDs)
		{
			unsigned int sz = std::min(prims.entries()-first_prim,
				static_cast<unsigned int>(polyIDs->size()));

			for(unsigned int i=0; i<sz; ++i)
				prims[i + first_prim]->setValue<int32>(aref, (*polyIDs)[i]);
		}
	}
}