hsBool plMaxNodeBase::CanConvert(bool recalculate) { // Try and find a cached return value plMaxNodeData *md = GetMaxNodeData(); if (md && !recalculate) return md->CanConvert(); if (UserPropExists("IGNORE")) return false; Object *obj = EvalWorldState(0/*hsConverterUtils::Instance().GetTime(GetInterface())*/).obj; if (obj) { if ( obj->CanConvertToType(triObjectClassID) // MeshObjs are accepted here || obj->ClassID() == Class_ID(DUMMY_CLASS_ID,0) // Dummy boxes are accepted here || obj->SuperClassID() == CAMERA_CLASS_ID // All Camera types are accepted here || obj->ClassID() == Class_ID(UTILITY_CLASS_ID, 0) // All Camera targets are accepted here || ( obj->ClassID() == RTOMNI_LIGHT_CLASSID || obj->ClassID() == RTSPOT_LIGHT_CLASSID || obj->ClassID() == RTDIR_LIGHT_CLASSID || obj->ClassID() == RTPDIR_LIGHT_CLASSID ) || ( obj->SuperClassID() == LIGHT_CLASS_ID // All run time lights are accepted here && UserPropExists("RunTimeLight")) || IsGroupMember() // Group objects are accepted here ) return true; } return false; }
hsBool plMaxNodeBase::Contains(const Point3& worldPt) { TimeValue currTime = 0;//hsConverterUtils::Instance().GetTime(GetInterface()); Object *obj = EvalWorldState(currTime).obj; if( !obj ) return false; Matrix3 l2w = GetObjectTM(currTime); Matrix3 w2l = Inverse(l2w); Point3 pt = w2l * worldPt; if( obj->ClassID() == Class_ID(DUMMY_CLASS_ID,0) ) { DummyObject* dummy = (DummyObject*)obj; Box3 bnd = dummy->GetBox(); return bnd.Contains(pt); } if( obj->CanConvertToType(triObjectClassID) ) { TriObject *meshObj = (TriObject *)obj->ConvertToType(currTime, triObjectClassID); if( !meshObj ) return false; Mesh& mesh = meshObj->mesh; Box3 bnd = mesh.getBoundingBox(); if( !bnd.Contains(pt) ) { if( meshObj != obj ) meshObj->DeleteThis(); return false; } hsBool retVal = true; int i; for( i = 0; i < mesh.getNumFaces(); i++ ) { Face& face = mesh.faces[i]; Point3 p0 = mesh.verts[face.v[0]]; Point3 p1 = mesh.verts[face.v[1]]; Point3 p2 = mesh.verts[face.v[2]]; Point3 n = CrossProd(p1 - p0, p2 - p0); if( DotProd(pt, n) > DotProd(p0, n) ) { retVal = false; break; } } if( meshObj != obj ) meshObj->DeleteThis(); return retVal; } // If we can't figure out what it is, the point isn't inside it. return false; }
// only show these in the dialog int SelectObjectsInMAX::filter(INode *node) { Object *obj = node->GetObjectRef(); if (obj->ClassID()!=DELEG_CLASSID) return FALSE; return TRUE; }
TriObject* MaxExportPlugin::GetTriObjFromNode(INode* node, BOOL &deleteIt) { if (node->IsObjectHidden()) return 0; deleteIt = FALSE; Object *obj; //obj = node->GetObjectRef(); obj = node->EvalWorldState(IP->GetTime()).obj; if (obj->ClassID() == BONE_OBJ_CLASSID) return 0; //file << "OBJCLASS: " << std::to_wstring(obj->ClassID().PartA()) << " " << std::to_wstring(obj->ClassID().PartB()) << "\n"; if (obj->CanConvertToType(Class_ID(TRIOBJ_CLASS_ID, 0))) { TriObject *tri = (TriObject *)obj->ConvertToType(IP->GetTime(), Class_ID(TRIOBJ_CLASS_ID, 0)); // Note that the TriObject should only be deleted // if the pointer to it is not equal to the object // pointer that called ConvertToType() if (obj != tri) deleteIt = TRUE; return tri; } else { return NULL; } }
bool plAnimComponentBase::IAddLightToAnim(plMaxNode *node, plAGAnim *anim, plErrorMsg *pErrMsg) { if (!node->IsAnimatedLight()) return false; Object *obj = node->GetObjectRef(); Class_ID cid = obj->ClassID(); IParamBlock2 *pb = nil; if (cid == RTSPOT_LIGHT_CLASSID) pb = obj->GetParamBlockByID(plRTLightBase::kBlkSpotLight); else if (cid == RTOMNI_LIGHT_CLASSID) pb = obj->GetParamBlockByID(plRTLightBase::kBlkOmniLight); else if (cid == RTDIR_LIGHT_CLASSID) pb = obj->GetParamBlockByID(plRTLightBase::kBlkTSpotLight); else if (cid == RTPDIR_LIGHT_CLASSID) pb = obj->GetParamBlockByID(plRTLightBase::kBlkMain); node->GetRTLightColAnim(pb, anim); if (cid == RTSPOT_LIGHT_CLASSID || cid == RTOMNI_LIGHT_CLASSID) node->GetRTLightAttenAnim(pb, anim); if (cid == RTSPOT_LIGHT_CLASSID) node->GetRTConeAnim(pb, anim); return true; }
float plMaxNodeBase::RegionPriority() { TimeValue currTime = 0;//hsConverterUtils::Instance().GetTime(GetInterface()); Object *obj = EvalWorldState(currTime).obj; if( !obj ) return 0; Matrix3 l2w = GetObjectTM(currTime); if( obj->ClassID() == Class_ID(DUMMY_CLASS_ID,0) ) { DummyObject* dummy = (DummyObject*)obj; Box3 bnd = dummy->GetBox(); return BoxVolume(bnd, l2w); } if( obj->CanConvertToType(triObjectClassID) ) { TriObject *meshObj = (TriObject *)obj->ConvertToType(currTime, triObjectClassID); if( !meshObj ) return 0; Mesh& mesh = meshObj->mesh; Box3 bnd = mesh.getBoundingBox(); if( meshObj != obj ) meshObj->DeleteThis(); return BoxVolume(bnd, l2w); } // Don't know how to interpret other, it's not contained. return 0; }
Abc::C4f AlembicPoints::GetColor(IParticleObjectExt *pExt, int particleId, TimeValue ticks) { Abc::C4f color(0.5, 0.5, 0.5, 1.0); // Go into the particle's action list INode *particleGroupNode = pExt->GetParticleGroup(particleId); Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL; if (!particleGroupObj) { return color; } IParticleGroup *particleGroup = GetParticleGroupInterface(particleGroupObj); INode *particleActionListNode = particleGroup->GetActionList(); Object *particleActionObj = (particleActionListNode != NULL ? particleActionListNode->EvalWorldState(ticks).obj : NULL); if (!particleActionObj) { return color; } PFSimpleOperator *pSimpleOperator = NULL; // In the case of multiple shape operators in an action list, the one furthest // down the list seems to be the one that applies IPFActionList *particleActionList = GetPFActionListInterface(particleActionObj); for (int p = particleActionList->NumActions() - 1; p >= 0; p -= 1) { INode *pActionNode = particleActionList->GetAction(p); Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL); if (pActionObj == NULL) { continue; } if (pActionObj->ClassID() == PFOperatorDisplay_Class_ID) { pSimpleOperator = static_cast<PFSimpleOperator *>(pActionObj); break; } } if (pSimpleOperator) { IParamBlock2 *pblock = pSimpleOperator->GetParamBlockByID(0); Point3 c = pblock->GetPoint3(kDisplay_color); color.r = c.x; color.g = c.y; color.b = c.z; color.a = 1.0; } return color; }
BOOL Validate(PB2Value &v) { INode *node = (INode*) v.r; Object *obj = node->GetObjectRef(); if (obj->ClassID() != DELEG_CLASSID) return FALSE; return TRUE; };
BOOL XsiExp::nodeEnumAnim(INode* node, int & animHit) { if(exportSelected && node->Selected() == FALSE) { return TREE_CONTINUE; } nCurNode++; ip->ProgressUpdate( (int)((float)nCurNode/nTotalNodeCount*100.0f) ); // Stop recursing if the user pressed Cancel if (ip->GetCancel()) { return FALSE; } // Only export if exporting everything or it's selected if(!exportSelected || node->Selected()) { // The ObjectState is a 'thing' that flows down the pipeline containing // all information about the object. By calling EvalWorldState() we tell // max to eveluate the object at end of the pipeline. ObjectState os = node->EvalWorldState(0); // The obj member of ObjectState is the actual object we will export. if (os.obj) { // We look at the super class ID to determine the type of the object. switch(os.obj->SuperClassID()) { case HELPER_CLASS_ID: { Object * obj = node->EvalWorldState(0).obj; if (!obj && obj->ClassID() != Class_ID(BONE_CLASS_ID, 0)) { return FALSE; } } // fall through case GEOMOBJECT_CLASS_ID: ExportAnimKeys( node, animHit); break; } } } // For each child of this node, we recurse into ourselves // until no more children are found. for (int c = 0; c < node->NumberOfChildren(); c++) { if (!nodeEnumAnim(node->GetChildNode(c), animHit)) { return FALSE; } } return TRUE; }
BOOL Cal3DObjPick::HitTest(IObjParam *ip, HWND hWnd, ViewExp *vpt, IPoint2 m, int flags) { INode *node = ip->PickNode(hWnd, m); if (node == NULL) return FALSE; Object *obj = node->EvalWorldState(0).obj; return obj->ClassID() == AudioClipClassID; }
hsBool plStrongSpringConstraintComponent::Convert(plMaxNode *node, plErrorMsg *pErrMsg) { plStrongSpringConstraintMod* HMod = new plStrongSpringConstraintMod; HMod->SetDamp(fCompPB->GetFloat(kStrength)); HMod->SetRR(fCompPB->GetFloat(kRebound)); //No MaximumTorque here, might as well use that field for the Pinned state for the Parent... HMod->SetParentPin(fCompPB->GetInt(kParentPinnedBool)); Object *obj = fCompPB->GetINode(kParent)->EvalWorldState(0/*hsConverterUtils::Instance().GetTime(GetInterface())*/).obj; plKey ParentKey = nil; if(fCompPB->GetINode(kParent)) if(((plMaxNode*)fCompPB->GetINode(kParent))->CanConvert() && (obj->ClassID() == Class_ID(DUMMY_CLASS_ID,0) || obj->SuperClassID() == GEOMOBJECT_CLASS_ID )) { plMaxNode* ParentNode = (plMaxNode*)fCompPB->GetINode(kParent); ParentKey = ParentNode->GetKey(); } else { pErrMsg->Set(true, "Ignored Parent Node", "Parent Node %s was set to be Ignored. Bad! Bad!.", (fCompPB->GetINode(kParent)->GetName())); pErrMsg->Set(false); return false; } else { // pErrMsg->Set(true, "Bad Parent Node", " Parent Node %s wasn't selected. Strong Spring Constraint failed.", (fCompPB->GetINode(kParent)->GetName())); // pErrMsg->Set(false); // return false; } //No motor Angle here, might as well use the field for Length Storage... HMod->SetFixedLength(fCompPB->GetFloat(kLength)); node->AddModifier(HMod, IGetUniqueName(node)); hsgResMgr::ResMgr()->AddViaNotify( ParentKey, new plGenRefMsg( HMod->GetKey(), plRefMsg::kOnCreate, plHavokConstraintsMod::kParentIdx, 0 ), plRefFlags::kPassiveRef ); hsgResMgr::ResMgr()->AddViaNotify( node->GetKey(), new plGenRefMsg( HMod->GetKey(), plRefMsg::kOnCreate, plHavokConstraintsMod::kChildIdx, 0 ), plRefFlags::kPassiveRef ); return true; }
BOOL TriggerPick::HitTest(IObjParam *ip, HWND hWnd, ViewExp *vpt, IPoint2 m, int flags) { INode *node = ip->PickNode(hWnd, m); if (node == NULL) return FALSE; Object *obj = node->EvalWorldState(0).obj; if ((obj->SuperClassID() == HELPER_CLASS_ID && obj->ClassID() == Class_ID(Anchor_CLASS_ID1, Anchor_CLASS_ID2))) return FALSE; return TRUE; }
//Get the current position for the purpose of computing the next frame //This function checks to see whether or not the node is a delegate, in which //case the GetTM function is called. static Matrix3 GetCurrentMatrix(INode *node, TimeValue t) { Object *o = node->GetObjectRef(); if (o->ClassID() == DELEG_CLASSID) { IDelegate *cd = (IDelegate *) o->GetInterface(I_DELEGINTERFACE); if (cd->IsComputing()) return cd->GetTM(node,t); } return node->GetNodeTM(t); }
void XsiExp::ExportMeshObject( INode * node, int indentLevel) { Object * obj = node->EvalWorldState(GetStaticFrame()).obj; if (!obj || obj->ClassID() == Class_ID(TARGET_CLASS_ID, 0)) { return; } TSTR indent = GetIndent(indentLevel); ExportNodeHeader(node, "Frame", indentLevel); ExportNodeTM(node, indentLevel); ExportMesh(node, GetStaticFrame(), indentLevel); }
void XsiExp::ExportNodeTM( INode * node, int indentLevel) { // dump the full matrix Matrix3 matrix = node->GetNodeTM(GetStaticFrame()); TSTR indent = GetIndent(indentLevel); fprintf(pStream,"%s\t%s {\n\n", indent.data(), "FrameTransformMatrix"); Object * obj = node->EvalWorldState(0).obj; BOOL isBone = obj && obj->ClassID() == Class_ID(BONE_CLASS_ID, 0) ? TRUE : FALSE; if (node->GetParentNode() && node->GetParentNode()->IsRootNode()) { // bone chains get grafted into the hierarchy tree // if (!isBone) { // root mesh oTopMatrix = matrix; AffineParts ap; decomp_affine( matrix, &ap); topMatrix.Set( Point3( ap.k.x,0.0f,0.0f), Point3( 0.0f,ap.k.z,0.0f), Point3(0.0f,0.0f,ap.k.y), Point3(0,0,0)); // root transform is controlled by the engine matrix.IdentityMatrix(); } } else { matrix = matrix * Inverse(node->GetParentTM(GetStaticFrame())); if (!isBone) { matrix.SetRow( 3, topMatrix * matrix.GetRow(3)); } } // write the matrix values DumpMatrix3( &matrix, indentLevel+2); // transform close brace fprintf(pStream,"%s\t}\n", indent.data()); }
BOOL ProxSensorObjPick::HitTest(IObjParam *ip, HWND hWnd, ViewExp *vpt, IPoint2 m, int flags) { if ( ! vpt || ! vpt->IsAlive() ) { // why are we here? DbgAssert(!"Doing HitTest() on invalid view port!"); return FALSE; } INode *node = ip->PickNode(hWnd, m); if (node == NULL) return FALSE; Object* obj = node->EvalWorldState(0).obj; if ((obj->SuperClassID() == HELPER_CLASS_ID && obj->ClassID() == Class_ID(ProxSensor_CLASS_ID1, ProxSensor_CLASS_ID2))) return FALSE; return TRUE; }
bool plMaxNodeBase::IsXRef() { // Is this an XRef'd object? Object *obj = GetObjectRef(); if (obj->SuperClassID() == SYSTEM_CLASS_ID && obj->ClassID() == XREFOBJ_CLASS_ID) return true; // // Is this part of an XRef'd scene? // // Walk up to our root node INode *root = GetParentNode(); while (!root->IsRootNode()) root = root->GetParentNode(); // If our root isn't the main root, we're in an XRef'd scene. if (root != GetCOREInterface()->GetRootNode()) return true; return false; }
void XsiExp::ExportBoneObject( INode * node, int indentLevel) { Object * obj = node->EvalWorldState(GetStaticFrame()).obj; if (!obj || obj->ClassID() != Class_ID(BONE_CLASS_ID, 0)) { // reject non-bones return; } if (!node->GetParentNode() || node->GetParentNode()->IsRootNode()) { // bone matrices get passed to children // drop root bone return; } TSTR indent = GetIndent(indentLevel); ExportNodeHeader(node, "Frame", indentLevel); // export parent as this bone ExportNodeTM(node->GetParentNode(), indentLevel); }
bool XRefObjFinder::Proc(INode * pNode) { TSTR workstring; // NOTE: We dump all info into one big string // Not super realistic, and probably won't work with // a scene with lots of XRef objects, but in a real exporter // situation, you'd be dumping out to a file pointer anyway if (!pNode || !m_buffer) return false; Object *obj = pNode->GetObjectRef(); if (obj && obj->SuperClassID()==SYSTEM_CLASS_ID && obj->ClassID()==XREFOBJ_CLASS_ID) { IXRefObject *ix = (IXRefObject *)obj; // if pNode refs an XRef object, let's pull some info out of it workstring.printf(_T("Node <%s> XREF <%s> filename:<%s> proxy:<%s> anim-off:<%s> update-mats:<%s> \x0D\x0A"), pNode->GetName(), ix->GetCurObjName(), ix->GetCurFile().GetFileName(), (ix->GetUseProxy()) ? _T("T") : _T("F"), (ix->GetIgnoreAnim()) ? _T("T") : _T("F"), (ix->GetUpdateMats()) ? _T("T") : _T("F")); m_buffer->append(workstring); } return true; }
//------------------------------ bool MorphControllerCreator::createMorphController( const COLLADAFW::MorphController* morphController, INode* referencingINode ) { Object* sourceObject = getObjectByUniqueId( morphController->getSource() ); if ( !sourceObject ) { // TODO handle error // morph source object not present return true; } mMorphModifier = (MorphR3*) createMaxObject(OSM_CLASS_ID, MORPHER_CLASS_ID); if ( !mMorphModifier ) { // TODO handle error // morph controller could not be created return true; } if ( (sourceObject->ClassID() == derivObjClassID) || (sourceObject->ClassID() == WSMDerivObjClassID) ) { // Object is a derived object, just attach ourselves to it mDerivedObject = (IDerivedObject*) sourceObject; } else { // Create the derived object for the target and the modifier mDerivedObject = CreateDerivedObject(sourceObject); } mDerivedObject->AddModifier(mMorphModifier); mMorphModifier->cache.MakeCache(sourceObject); const COLLADAFW::FloatOrDoubleArray& morphWeights = morphController->getMorphWeights(); const COLLADAFW::UniqueIdArray& morphTargets = morphController->getMorphTargets(); // There is a maximum number of channels supported by the 3dsMax morpher: // Calculate the number of channels to process size_t colladaTargetCount = morphTargets.getCount(); int channelCount = (int) min(colladaTargetCount, mMorphModifier->chanBank.size()); const COLLADAFW::UniqueId& morphWeightsAnimationListId = morphWeights.getAnimationList(); const COLLADAFW::AnimationList* morphWeightsAnimationList = getAnimationListByUniqueId( morphWeightsAnimationListId ); for (int i = 0; i < channelCount; ++i) { const COLLADAFW::UniqueId& targetUniqueId = morphTargets[i]; Object* targetObject = getObjectByUniqueId( targetUniqueId ); if ( !targetObject ) { // TODO handle error // the target has not been created, might be missing in dae file return true; } INodeList targetINodes; getObjectINodesByUniqueId( targetUniqueId, targetINodes ); INode* targetINode = 0; if ( !targetINodes.empty() ) { // it does not seem to make a difference which INode we use, as long as it references the correct geometry targetINode = targetINodes[0]; } morphChannel* channel = &mMorphModifier->chanBank[i]; if ( targetINode ) { channel->buildFromNode(targetINode); channel->mConnection = targetINode; } else { // Manually initializes this channel initializeChannelGeometry(channel, targetObject); } if ( !morphWeightsAnimationList ) { float weight = 0; if ( morphWeights.getType() == COLLADAFW::FloatOrDoubleArray::DATA_TYPE_FLOAT ) { weight = (*morphWeights.getFloatValues())[i]; } else if ( morphWeights.getType() == COLLADAFW::FloatOrDoubleArray::DATA_TYPE_DOUBLE ) { weight = (float)(*morphWeights.getDoubleValues())[i]; } channel->cblock->SetValue(0, 0, weight * 100); } } if ( morphWeightsAnimationList ) { const COLLADAFW::AnimationList::AnimationBindings& animationBindings = morphWeightsAnimationList->getAnimationBindings(); for ( size_t i = 0, count = animationBindings.getCount(); i < count; ++i) { const COLLADAFW::AnimationList::AnimationBinding& animationBinding = animationBindings[i]; if ( animationBinding.animationClass != COLLADAFW::AnimationList::ARRAY_ELEMENT_1D) { // this animation does not animate one element of a one dimensional array continue; } const DocumentImporter::MaxControllerList& maxControllerList = getMaxControllerListByAnimationUniqueId( animationBinding.animation ); assert(maxControllerList.size()==1); if ( maxControllerList.size() < 1 ) { // this animation does not animate one element of a one dimensional array continue; } Control* weightController = maxControllerList[0]; size_t channelNumber = animationBinding.firstIndex; if ( (int)channelNumber >= channelCount ) { // invalid channel continue; } morphChannel* channel = &mMorphModifier->chanBank[channelNumber]; if ( !channel ) { continue; } Control* scaledWeightController = cloneController( weightController, &ConversionFunctors::toPercent); //Control* scaledWeightController = cloneController( weightController); //channel->cblock->SetController(0, weightController); channel->cblock->SetController(0, scaledWeightController); } } //assign the morph controller to all INodes referencing it INodeList referencingINodes; getObjectINodesByUniqueId( morphController->getUniqueId(), referencingINodes ); for ( size_t i = 0, count = referencingINodes.size(); i < count; ++i) { INode* referencingINode = referencingINodes[i]; referencingINode->SetObjectRef(mDerivedObject); } addUniqueIdObjectPair( morphController->getUniqueId(), mDerivedObject ); return true; }
void XsiExp::DumpScaleKeys( INode * node, int indentLevel) { Control * cont = node->GetTMController()->GetScaleController(); IKeyControl * ikc = GetKeyControlInterface(cont); INode * parent = node->GetParentNode(); if (!cont || !parent || (parent && parent->IsRootNode()) || !ikc) { // no controller or root node return; } int numKeys = ikc->GetNumKeys(); if (numKeys <= 1) { return; } Object * obj = node->EvalWorldState(0).obj; BOOL isBone = obj && obj->ClassID() == Class_ID(BONE_CLASS_ID, 0) ? TRUE : FALSE; // anim keys header TSTR indent = GetIndent(indentLevel); fprintf(pStream,"%s\tSI_AnimationKey {\n", indent.data()); fprintf(pStream,"%s\t\t1;\n", indent.data()); // 1 means scale keys fprintf(pStream,"%s\t\t%d;\n", indent.data(), numKeys); int t, delta = GetTicksPerFrame(); Matrix3 matrix; AffineParts ap; for (int i = 0; i < numKeys; i++) { // get the key's time if (cont->ClassID() == Class_ID(TCBINTERP_SCALE_CLASS_ID, 0)) { ITCBRotKey key; ikc->GetKey(i, &key); t = key.time; } else if (cont->ClassID() == Class_ID(HYBRIDINTERP_SCALE_CLASS_ID, 0)) { IBezQuatKey key; ikc->GetKey(i, &key); t = key.time; } else if (cont->ClassID() == Class_ID(LININTERP_SCALE_CLASS_ID, 0)) { ILinRotKey key; ikc->GetKey(i, &key); t = key.time; } // sample the node's matrix matrix = node->GetNodeTM(t) * Inverse(node->GetParentTM(t)); if (!isBone) { matrix = matrix * topMatrix; } decomp_affine(matrix, &ap); fprintf(pStream, "%s\t\t%d; 3; %.6f, %.6f, %.6f;;%s\n", indent.data(), t / delta, ap.k.x, ap.k.z, ap.k.y, i == numKeys - 1 ? ";\n" : ","); } // anim keys close fprintf(pStream,"%s\t}\n\n", indent.data()); }
int FormationBhvr::Perform(INode *node, TimeValue t, int numsubsamples, BOOL DisplayHelpers, float BhvrWeight, PerformOut &out) { Object *o = node->GetObjectRef(); if (o->ClassID() != DELEG_CLASSID) return FALSE; // this should never happen IDelegate *IDeleg = (IDelegate *) o->GetInterface(I_DELEGINTERFACE); Point3 vel= IDeleg->GetCurrentVelocity(); Point3 pos = IDeleg->GetCurrentPosition(); INode *leader = GetLeader(t); if(leader==NULL) return 0; Matrix3 formationMat; //Get the local formation matrix and check if(FindFollowerMatrix(t,node,formationMat)==FALSE) return 0; //that node doesn't exist in the formation so exit. //returned values. Point3 frc,goal; float speedwt, speedAtGoalwt; //Find the Formation Position Target in World Space. Matrix3 currentLeaderMat = GetCurrentMatrix(leader,t); currentLeaderMat.NoScale(); Matrix3 worldSpace = formationMat*currentLeaderMat; Point3 target = worldSpace.GetTrans(); //set the goal as the target goal = target; //set the force as the direction to move towards the target frc = goal - pos; float length = frc.FLength(); if(length!=0.0f) //we are not at the goal { frc /=length; //set up the leader Vector Point3 leaderVec = leaderVel*leaderSpeed; //If the target is behind you but moving towards you don't turn around to //go toward it. Instead move in the direction of the leader. if(frc%vel<0.0f && //if you are behind it length/IDeleg->GetAverageSpeed(t)<10 && //AND less than 20 frames vel%leaderVel>0.0f) //AND it is going toward you. { //set frc as leader's Velocity. frc = leaderVel; //move at half the leaderSpeed. Leader will still catch //up to you and you'll have some speed when it does. //set the speewt speedwt = (leaderSpeed*0.5f)/IDeleg->GetAverageSpeed(t); } else //we should just move towards the target. { //We need to find the speed to be it. We do this by //finding the time we will intersect our target based //upon the leader's velocity and our own velocity. vel -= leaderVec; //find time to intersect.. float newSpeed = vel.FLength(); float timeToIntersect = length/newSpeed; //from that time.. figure out what it speed should be.. newSpeed = timeToIntersect * IDeleg->GetMaxAccel(t); if(newSpeed>IDeleg->GetAverageSpeed(t)) newSpeed = IDeleg->GetAverageSpeed(t); //check to see if we will move past the goal.. if so //move the goal along the leader vec. This reduces overshooting //the goal and decreases wobbling. if((newSpeed+leaderSpeed)>length) { goal += leaderVel*(leaderSpeed); frc = goal -pos; float newLength = frc.FLength(); if(newLength!=0.0f) //check for if zero to avoid divide by zero.. { frc /= newLength; speedwt = (newSpeed+leaderSpeed)/IDeleg->GetAverageSpeed(t); } else { speedwt = 0.0f; } } else //far enough away.. leave the ole frc value.. speedwt = (newSpeed+leaderSpeed)/IDeleg->GetAverageSpeed(t); } } else //we are at the goal { frc.x = frc.y = frc.z = 0.0f; //set the speedwt to be the leaderSpeed speedwt = leaderSpeed/IDeleg->GetAverageSpeed(t); } frc *= BhvrWeight *IDeleg->GetAverageSpeed(t); //scale by weight and average speed.. //set the speedWtAtGoal.. We want it to be the speed of the leader speedAtGoalwt = leaderSpeed/IDeleg->GetAverageSpeed(t); //Display Any Helpers. if (DisplayHelpers && IDeleg->OkToDisplayMyForces()) { if (DisplayTarget(t)) IDeleg->SphereDisplay(goal,pblock->GetFloat(target_scale),GetTargetColor(t)); if (DisplayForce(t)) IDeleg->LineDisplay(IDeleg->GetCurrentPosition(),IDeleg->GetCurrentPosition()+frc,GetForceColor(t),TRUE); } //set up the out structure.. out.frc = frc; out.goal = goal; out.speedwt = speedwt; out.speedAtGoalwt = speedAtGoalwt; return BHVR_SETS_FORCE | BHVR_SETS_GOAL | BHVR_SETS_SPEED; }
int SceneEnumProc::callback(INode *node) { char line[1024]; Object *obj = node->EvalWorldState(time).obj; strcpy(line, node->GetName()); //if(strstr(line, "Bip") != NULL) { sprintf(line, "%08X %08X", obj->SuperClassID(), obj->ClassID()); // MessageBox(NULL, line, node->GetName(), MB_OK); } if( (obj->SuperClassID() == GEOMOBJECT_CLASS_ID) && (obj->ClassID() == Class_ID(BIP_BONE_CLASS_ID, 0)) ) { Append(node, obj, OBTYPE_BONE); return TREE_CONTINUE; } if (obj->CanConvertToType(triObjectClassID)) { Append(node, obj, OBTYPE_MESH); return TREE_CONTINUE; } if (node->IsTarget()) { INode* ln = node->GetLookatNode(); if (ln) { Object *lobj = ln->EvalWorldState(time).obj; switch(lobj->SuperClassID()) { case LIGHT_CLASS_ID: Append(node, obj, OBTYPE_LTARGET); break; case CAMERA_CLASS_ID: Append(node, obj, OBTYPE_CTARGET); break; } } return TREE_CONTINUE; } switch (obj->SuperClassID()) { case HELPER_CLASS_ID: if ( obj->ClassID()==Class_ID(DUMMY_CLASS_ID,0)) Append(node, obj, OBTYPE_DUMMY); if(obj->ClassID() == Class_ID(BONE_CLASS_ID,0)) Append(node, obj, OBTYPE_BONE); break; case LIGHT_CLASS_ID: if (obj->ClassID()==Class_ID(OMNI_LIGHT_CLASS_ID,0)) Append(node, obj, OBTYPE_OMNILIGHT); else if (obj->ClassID()==Class_ID(SPOT_LIGHT_CLASS_ID,0)) Append(node, obj, OBTYPE_SPOTLIGHT); //export DIR_LIGHT and FSPOT_LIGHT???? break; case CAMERA_CLASS_ID: if (obj->ClassID()==Class_ID(LOOKAT_CAM_CLASS_ID,0)) Append(node, obj, OBTYPE_CAMERA); break; } return TREE_CONTINUE; // Keep on enumeratin'! }
void AlembicPoints::GetShapeType(IParticleObjectExt *pExt, int particleId, TimeValue ticks, ShapeType &type, Abc::uint16_t &instanceId, float &animationTime) { // Set up initial values type = ShapeType_Point; instanceId = 0; animationTime = 0.0f; // Go into the particle's action list INode *particleGroupNode = pExt->GetParticleGroup(particleId); Object *particleGroupObj = (particleGroupNode != NULL) ? particleGroupNode->EvalWorldState(ticks).obj : NULL; if (!particleGroupObj){ return; } IParticleGroup *particleGroup = GetParticleGroupInterface(particleGroupObj); INode *particleActionListNode = particleGroup->GetActionList(); Object *particleActionObj = (particleActionListNode != NULL ? particleActionListNode->EvalWorldState(ticks).obj : NULL); if (!particleActionObj){ return; } PFSimpleOperator *pSimpleOperator = NULL; //In the case of multiple shape operators in an action list, the one furthest down the list seems to be the one that applies IPFActionList *particleActionList = GetPFActionListInterface(particleActionObj); for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1) { INode *pActionNode = particleActionList->GetAction(p); Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL); if (pActionObj == NULL){ continue; } if (pActionObj->ClassID() == PFOperatorSimpleShape_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; }else if(pActionObj->ClassID() == PFOperatorShapeLib_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; }else if(pActionObj->ClassID() == PFOperatorInstanceShape_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; }else if(pActionObj->ClassID() == PFOperatorMarkShape_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; }else if(pActionObj->ClassID() == PFOperatorFacingShape_Class_ID){ pSimpleOperator = static_cast<PFSimpleOperator*>(pActionObj); break; } } for (int p = particleActionList->NumActions()-1; p >= 0; p -= 1) { INode *pActionNode = particleActionList->GetAction(p); Object *pActionObj = (pActionNode != NULL ? pActionNode->EvalWorldState(ticks).obj : NULL); if (pActionObj == NULL){ continue; } IPFTest* pTestAction = GetPFTestInterface(pActionObj); if (pTestAction){ INode* childActionListNode = pTestAction->GetNextActionList(pActionNode, NULL); if(childActionListNode){ AlembicPoints::perActionListShapeMap_it actionListIt = mPerActionListShapeMap.find(childActionListNode); //create a cache entry if necessary if(actionListIt == mPerActionListShapeMap.end()){ mPerActionListShapeMap[childActionListNode] = AlembicPoints::shapeInfo(); } AlembicPoints::shapeInfo& sInfo = mPerActionListShapeMap[childActionListNode]; if(!sInfo.pParentActionList){ sInfo.pParentActionList = particleActionListNode; } } } } ReadShapeFromOperator(particleGroup, pSimpleOperator, particleId, ticks, type, instanceId, animationTime); if(type != ShapeType_NbElements){//write the shape to the cache // create cache entry for the current action list node, and then fill in the shape info // we will fill in the parent later AlembicPoints::perActionListShapeMap_it actionListIt = mPerActionListShapeMap.find(particleActionListNode); //create a cache entry if necessary if(actionListIt == mPerActionListShapeMap.end()){ mPerActionListShapeMap[particleActionListNode] = AlembicPoints::shapeInfo(); } AlembicPoints::shapeInfo& sInfo = mPerActionListShapeMap[particleActionListNode]; //if(sInfo.type == ShapeType_NbElements){ // sInfo.type = type; // sInfo.animationTime = animationTime; // if(sInfo.type == ShapeType_Instance){ // sInfo.instanceName = mInstanceNames[instanceId]; // } //} } else{ //read the shape from the cache AlembicPoints::shapeInfo sInfo; INode* currActionNode = particleActionListNode; //search for shape along path from this node to the root node const int MAX_DEPTH = 10; //just in case there is an infinite loop due a bug int i = 0; while(currActionNode && sInfo.type == ShapeType_NbElements && i<MAX_DEPTH){ AlembicPoints::perActionListShapeMap_it actionListIt = mPerActionListShapeMap.find(currActionNode); if(actionListIt != mPerActionListShapeMap.end()){ sInfo = actionListIt->second; } currActionNode = sInfo.pParentActionList; i++; } if(sInfo.type != ShapeType_NbElements){//We have found shape, so add it to the list if necessary // Find if the name is alerady registered, otherwise add it to the list //instanceId = FindInstanceName(sInfo.instanceName); //if (instanceId == USHRT_MAX) //{ // mInstanceNames.push_back(sInfo.instanceName); // instanceId = (Abc::uint16_t)mInstanceNames.size()-1; //} //type = sInfo.type; } else{ int nBornIndex = pExt->GetParticleBornIndex(particleId); ESS_LOG_INFO("Could not determine shape type for particle with born index: "<<nBornIndex<<". Defaulting to point."); type = ShapeType_Point; } } }
CInstanceGroup* CExportNel::buildInstanceGroup(const vector<INode*>& vectNode, vector<INode*>& resultInstanceNode, TimeValue tvTime) { // Extract from the node the name, the transformations and the parent CInstanceGroup::TInstanceArray aIGArray; uint32 i, nNumIG; uint32 j,k,m; aIGArray.empty (); resultInstanceNode.empty (); aIGArray.resize (vectNode.size()); resultInstanceNode.resize (vectNode.size()); int nNbInstance = 0; for (i = 0; i < vectNode.size(); ++i) { INode *pNode = vectNode[i]; int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32); if ((nAccelType&3) == 0) // If not an accelerator if (!RPO::isZone (*pNode, tvTime)) if (CExportNel::isMesh (*pNode, tvTime) || CExportNel::isDummy(*pNode, tvTime)) { ++nNbInstance; } } // Check integrity of the hierarchy and set the parents std::vector<INode*>::const_iterator it = vectNode.begin(); nNumIG = 0; for (i = 0; i < (sint)vectNode.size(); ++i, ++it) { INode *pNode = *it; int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32); if ((nAccelType&3) == 0) // If not an accelerator if (!RPO::isZone( *pNode, tvTime )) if (CExportNel::isMesh( *pNode, tvTime ) || CExportNel::isDummy(*pNode, tvTime)) { aIGArray[nNumIG].DontAddToScene = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_DONT_ADD_TO_SCENE, 0)?true:false; aIGArray[nNumIG].InstanceName = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_INSTANCE_NAME, ""); resultInstanceNode[nNumIG] = pNode; if (aIGArray[nNumIG].InstanceName == "") // no instance name was set, takes the node name instead { aIGArray[nNumIG].InstanceName = pNode->GetName(); } // Visible? always true, but if special flag for camera collision sint appDataCameraCol= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_CAMERA_COLLISION_MESH_GENERATION, 0); aIGArray[nNumIG].Visible= appDataCameraCol!=3; INode *pParent = pNode->GetParentNode(); // Set the DontCastShadow flag. aIGArray[nNumIG].DontCastShadow= pNode->CastShadows()==0; // Set the Special DontCastShadow flag. aIGArray[nNumIG].DontCastShadowForInterior= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_LIGHT_DONT_CAST_SHADOW_INTERIOR, BST_UNCHECKED)?true:false; aIGArray[nNumIG].DontCastShadowForExterior= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_LIGHT_DONT_CAST_SHADOW_EXTERIOR, BST_UNCHECKED)?true:false; // Is the pNode has the root node for parent ? if( pParent->IsRootNode() == 0 ) { // Look if the parent is in the selection int nNumIG2 = 0; for (j = 0; j < vectNode.size(); ++j) { INode *pNode2 = vectNode[j]; int nAccelType2 = CExportNel::getScriptAppData (pNode2, NEL3D_APPDATA_ACCEL, 32); if ((nAccelType2&3) == 0) // If not an accelerator if (!RPO::isZone( *pNode2, tvTime )) if (CExportNel::isMesh( *pNode2, tvTime )) { if (pNode2 == pParent) break; ++nNumIG2; } } if (nNumIG2 == nNbInstance) { // The parent is not selected ! link to root aIGArray[nNumIG].nParent = -1; } else { aIGArray[nNumIG].nParent = nNumIG2; } } else { aIGArray[nNumIG].nParent = -1; } ++nNumIG; } } aIGArray.resize( nNumIG ); resultInstanceNode.resize( nNumIG ); // Build the array of node vGlobalPos = CVector(0,0,0); nNumIG = 0; it = vectNode.begin(); for (i = 0; i < (sint)vectNode.size(); ++i, ++it) { INode *pNode = *it; int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32); if ((nAccelType&3) == 0) // If not an accelerator if (!RPO::isZone (*pNode, tvTime)) if (CExportNel::isMesh (*pNode, tvTime) || CExportNel::isDummy(*pNode, tvTime)) { CVector vScaleTemp; CQuat qRotTemp; CVector vPosTemp; // Get Nel Name for the object. aIGArray[nNumIG].Name= CExportNel::getNelObjectName(*pNode); //Get the local transformation matrix Matrix3 nodeTM = pNode->GetNodeTM(0); INode *pParent = pNode->GetParentNode(); Matrix3 parentTM = pParent->GetNodeTM(0); Matrix3 localTM = nodeTM*Inverse(parentTM); // Extract transformations CExportNel::decompMatrix (vScaleTemp, qRotTemp, vPosTemp, localTM); aIGArray[nNumIG].Rot = qRotTemp; aIGArray[nNumIG].Pos = vPosTemp; aIGArray[nNumIG].Scale = vScaleTemp; vGlobalPos += vPosTemp; ++nNumIG; } } // todo Make this work (precision): /* vGlobalPos = vGlobalPos / nNumIG; for (i = 0; i < nNumIG; ++i) aIGArray[i].Pos -= vGlobalPos; */ vGlobalPos = CVector(0,0,0); // Temporary !!! // Accelerator Portal/Cluster part //================= // Creation of all the clusters vector<CCluster> vClusters; it = vectNode.begin(); for (i = 0; i < (sint)vectNode.size(); ++i, ++it) { INode *pNode = *it; int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, NEL3D_APPDATA_ACCEL_DEFAULT); bool bFatherVisible = nAccelType&NEL3D_APPDATA_ACCEL_FATHER_VISIBLE?true:false; bool bVisibleFromFather = nAccelType&NEL3D_APPDATA_ACCEL_VISIBLE_FROM_FATHER?true:false; bool bAudibleLikeVisible = (nAccelType&NEL3D_APPDATA_ACCEL_AUDIBLE_NOT_LIKE_VISIBLE)?false:true; bool bFatherAudible = bAudibleLikeVisible ? bFatherVisible : nAccelType&NEL3D_APPDATA_ACCEL_FATHER_AUDIBLE?true:false; bool bAudibleFromFather = bAudibleLikeVisible ? bVisibleFromFather : nAccelType&NEL3D_APPDATA_ACCEL_AUDIBLE_FROM_FATHER?true:false; if ((nAccelType&NEL3D_APPDATA_ACCEL_TYPE) == NEL3D_APPDATA_ACCEL_CLUSTER) // If cluster if (!RPO::isZone (*pNode, tvTime)) if (CExportNel::isMesh(*pNode, tvTime)) { CCluster clusterTemp; std::string temp; temp = CExportNel::getScriptAppData(pNode, NEL3D_APPDATA_SOUND_GROUP, "no sound"); clusterTemp.setSoundGroup(temp != "no sound" ? temp : ""); temp = CExportNel::getScriptAppData(pNode, NEL3D_APPDATA_ENV_FX, "no fx"); clusterTemp.setEnvironmentFx(temp != "no fx" ? temp : ""); CMesh::CMeshBuild *pMB; CMeshBase::CMeshBaseBuild *pMBB; pMB = createMeshBuild (*pNode, tvTime, pMBB); convertToWorldCoordinate( pMB, pMBB ); for (j = 0; j < pMB->Faces.size(); ++j) { if (!clusterTemp.makeVolume (pMB->Vertices[pMB->Faces[j].Corner[0].Vertex], pMB->Vertices[pMB->Faces[j].Corner[1].Vertex], pMB->Vertices[pMB->Faces[j].Corner[2].Vertex]) ) { // ERROR : The volume is not convex !!! char tam[256]; sprintf(tam,"ERROR: The cluster %s is not convex.",vectNode[i]->GetName()); //MessageBox(NULL,tam,"Error",MB_OK|MB_ICONERROR); nlwarning(tam); } } clusterTemp.FatherVisible = bFatherVisible; clusterTemp.VisibleFromFather = bVisibleFromFather; clusterTemp.FatherAudible = bFatherAudible; clusterTemp.AudibleFromFather = bAudibleFromFather; clusterTemp.Name = pNode->GetName(); vClusters.push_back (clusterTemp); delete pMB; delete pMBB; } } // Creation of all the portals vector<CPortal> vPortals; it = vectNode.begin(); for (i = 0; i < (sint)vectNode.size(); ++i, ++it) { INode *pNode = *it; int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32); if ((nAccelType&3) == 1) // If Portal if (!RPO::isZone (*pNode, tvTime)) if (CExportNel::isMesh(*pNode, tvTime)) { CPortal portalTemp; std::string temp; temp = CExportNel::getScriptAppData(pNode, NEL3D_APPDATA_OCC_MODEL, "no occlusion"); portalTemp.setOcclusionModel(temp != "no occlusion" ? temp : ""); temp = CExportNel::getScriptAppData(pNode, NEL3D_APPDATA_OPEN_OCC_MODEL, "no occlusion"); portalTemp.setOpenOcclusionModel(temp != "no occlusion" ? temp : ""); CMesh::CMeshBuild *pMB; CMeshBase::CMeshBaseBuild *pMBB; pMB = createMeshBuild (*pNode, tvTime, pMBB); convertToWorldCoordinate( pMB, pMBB ); vector<sint32> poly; vector<bool> facechecked; facechecked.resize (pMB->Faces.size()); for (j = 0; j < pMB->Faces.size(); ++j) facechecked[j] = false; poly.push_back(pMB->Faces[0].Corner[0].Vertex); poly.push_back(pMB->Faces[0].Corner[1].Vertex); poly.push_back(pMB->Faces[0].Corner[2].Vertex); facechecked[0] = true; for (j = 0; j < pMB->Faces.size(); ++j) if (!facechecked[j]) { bool found = false; for(k = 0; k < 3; ++k) { for(m = 0; m < poly.size(); ++m) { if ((pMB->Faces[j].Corner[k].Vertex == poly[m]) && (pMB->Faces[j].Corner[(k+1)%3].Vertex == poly[(m+1)%poly.size()])) { found = true; break; } if ((pMB->Faces[j].Corner[(k+1)%3].Vertex == poly[m]) && (pMB->Faces[j].Corner[k].Vertex == poly[(m+1)%poly.size()])) { found = true; break; } } if (found) break; } if (found) { // insert an empty space in poly between m and m+1 poly.resize (poly.size()+1); for (uint32 a = poly.size()-2; a > m; --a) poly[a+1] = poly[a]; poly[m+1] = pMB->Faces[j].Corner[(k+2)%3].Vertex; facechecked[j] = true; j = 0; } } vector<CVector> polyv; polyv.resize (poly.size()); for (j = 0; j < poly.size(); ++j) polyv[j] = pMB->Vertices[poly[j]]; if (!portalTemp.setPoly (polyv)) { // ERROR : Poly not convex, or set of vertices not plane char tam[256]; sprintf(tam,"ERROR: The portal %s is not convex.",vectNode[i]->GetName()); //MessageBox(NULL,tam,"Error",MB_OK|MB_ICONERROR); nlwarning(tam); } if (nAccelType&16) // is dynamic portal ? { string InstanceName = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_INSTANCE_NAME, ""); if (!InstanceName.empty()) portalTemp.setName (InstanceName); else portalTemp.setName (string(pNode->GetName())); } // Check if portal has 2 cluster int nNbCluster = 0; for (j = 0; j < vClusters.size(); ++j) { bool bPortalInCluster = true; for (k = 0; k < polyv.size(); ++k) if (!vClusters[j].isIn (polyv[k]) ) { bPortalInCluster = false; break; } if (bPortalInCluster) ++nNbCluster; } if (nNbCluster != 2) { // ERROR char tam[256]; sprintf(tam,"ERROR: The portal %s has not 2 clusters but %d",vectNode[i]->GetName(), nNbCluster); //MessageBox(NULL,tam,"Error",MB_OK|MB_ICONERROR); nlwarning(tam); } vPortals.push_back (portalTemp); delete pMB; delete pMBB; } } // Link instance to clusters (an instance has a list of clusters) nNumIG = 0; it = vectNode.begin(); for (i = 0; i < (sint)vectNode.size(); ++i, ++it) { INode *pNode = *it; int nAccelType = CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_ACCEL, 32); if ((nAccelType&3) == 0) // If not an accelerator if (!RPO::isZone (*pNode, tvTime)) if (CExportNel::isMesh (*pNode, tvTime) || CExportNel::isDummy(*pNode, tvTime)) { if (nAccelType&32) // Is the flag clusterize set ? { // Test against all clusters // The list of vertices used to test against cluster std::vector<NLMISC::CVector> *testVertices; std::vector<NLMISC::CVector> FXVertices; // Used only if the obj is a fx. It contains the corners of the bbox. bool buildMeshBBox = true; /** If it is a mesh, we build its bbox and transform in world * If it is a FX, we read its bbox from its shape * If we can't read it, we use the bbox of the fx helper in max */ Object *obj = pNode->EvalWorldState(tvTime).obj; // Check if there is an object if (obj) { Class_ID clid = obj->ClassID(); // is the object a particle system ? if (clid.PartA() == NEL_PARTICLE_SYSTEM_CLASS_ID) { // build the shape from the file name std::string objName = CExportNel::getNelObjectName(*pNode); if (!objName.empty()) { NL3D::CShapeStream ss; NLMISC::CIFile iF; if (iF.open(objName.c_str())) { try { iF.serial(ss); NL3D::CParticleSystemShape *pss = dynamic_cast<NL3D::CParticleSystemShape *>(ss.getShapePointer()); if (!pss) { nlwarning("ERROR: Node %s shape is not a FX", CExportNel::getName(*pNode).c_str()); } else { NLMISC::CAABBox bbox; pss->getAABBox(bbox); // transform in world Matrix3 xForm = pNode->GetNodeTM(tvTime); NLMISC::CMatrix nelXForm; CExportNel::convertMatrix(nelXForm, xForm); bbox = NLMISC::CAABBox::transformAABBox(nelXForm, bbox); // store vertices of the bbox in the list FXVertices.reserve(8); for(uint k = 0; k < 8; ++k) { FXVertices.push_back(CVector(((k & 1) ? 1 : -1) * bbox.getHalfSize().x + bbox.getCenter().x, ((k & 2) ? 1 : -1) * bbox.getHalfSize().y + bbox.getCenter().y, ((k & 4) ? 1 : -1) * bbox.getHalfSize().z + bbox.getCenter().z)); } // testVertices = &FXVertices; buildMeshBBox = false; } delete ss.getShapePointer(); } catch (NLMISC::Exception &e) { nlwarning(e.what()); } } if (buildMeshBBox) { nlwarning("ERROR: Can't get bbox of a particle system from its shape, using helper bbox instead"); } } } } CMesh::CMeshBuild *pMB = NULL; CMeshBase::CMeshBaseBuild *pMBB = NULL; if (buildMeshBBox) { pMB = createMeshBuild (*pNode, tvTime, pMBB); convertToWorldCoordinate( pMB, pMBB ); testVertices = &pMB->Vertices; } for(k = 0; k < vClusters.size(); ++k) { bool bMeshInCluster = false; for(j = 0; j < testVertices->size(); ++j) { if (vClusters[k].isIn ((*testVertices)[j])) { bMeshInCluster = true; break; } } if (bMeshInCluster) { aIGArray[nNumIG].Clusters.push_back (k); } } // debug purpose : to remove if (vClusters.size() > 0) if (aIGArray[nNumIG].Clusters.size() == 0) { char tam[256]; sprintf(tam,"ERROR: Object %s is not attached to any cluster\nbut his flag clusterize is set", pNode->GetName()); //MessageBox(NULL, tam, "Warning", MB_OK); nlwarning(tam); } // debug purpose : to remove delete pMB; delete pMBB; } ++nNumIG; } // debug purpose : to remove /* if ((nAccelType&3) == 0) // If not an accelerator if (!(nAccelType&32)) { char tam[256]; sprintf(tam,"Object %s is not clusterized", pNode->GetName()); MessageBox(NULL, tam, "Info", MB_OK); } */ // debug purpose : to remove } // PointLight part //================= bool sunLightEnabled= false; sint nNumPointLight = 0; vector<CPointLightNamed> pointLights; pointLights.resize(vectNode.size()); // For all nodes for (i = 0; i < (sint)vectNode.size(); ++i) { INode *pNode = vectNode[i]; SLightBuild sLightBuild; // If it is a Max Light. if ( sLightBuild.canConvertFromMaxLight(pNode, tvTime) ) { // And if this light is checked to realtime export int nRTExport= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_EXPORT_REALTIME_LIGHT, BST_CHECKED); if(nRTExport == BST_CHECKED) { // get Max Light info. sLightBuild.convertFromMaxLight(pNode, tvTime); // Skip if LightDir if(sLightBuild.Type != SLightBuild::LightDir) { // Fill PointLight Info. NL3D::CPointLightNamed &plNamed= pointLights[nNumPointLight]; // Position plNamed.setPosition(sLightBuild.Position); // Attenuation plNamed.setupAttenuation(sLightBuild.rRadiusMin, sLightBuild.rRadiusMax); // Colors // Ensure A=255 for localAmbient to work. NLMISC::CRGBA ambient= sLightBuild.Ambient; ambient.A= 255; plNamed.setDefaultAmbient(ambient); plNamed.setAmbient(ambient); plNamed.setDefaultDiffuse(sLightBuild.Diffuse); plNamed.setDiffuse(sLightBuild.Diffuse); plNamed.setDefaultSpecular(sLightBuild.Specular); plNamed.setSpecular(sLightBuild.Specular); // GroupName. plNamed.AnimatedLight = sLightBuild.AnimatedLight; plNamed.LightGroup = sLightBuild.LightGroup; // Which light type?? if(sLightBuild.bAmbientOnly || sLightBuild.Type== SLightBuild::LightAmbient) { plNamed.setType(CPointLight::AmbientLight); // Special ambient info int nRTAmbAdd= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_REALTIME_AMBIENT_ADD_SUN, BST_UNCHECKED); plNamed.setAddAmbientWithSun(nRTAmbAdd==BST_CHECKED); } else if(sLightBuild.Type== SLightBuild::LightPoint) { plNamed.setType(CPointLight::PointLight); } else if(sLightBuild.Type== SLightBuild::LightSpot) { plNamed.setType(CPointLight::SpotLight); // Export Spot infos. plNamed.setupSpotDirection(sLightBuild.Direction); plNamed.setupSpotAngle(sLightBuild.rHotspot, sLightBuild.rFallof); } else { // What??? nlstop; } // inc Size ++nNumPointLight; } } // if this light is a directionnal and checked to export as Sun Light int nExportSun= CExportNel::getScriptAppData (pNode, NEL3D_APPDATA_EXPORT_AS_SUN_LIGHT, BST_UNCHECKED); if(nExportSun== BST_CHECKED) { // get Max Light info. sLightBuild.convertFromMaxLight(pNode, tvTime); // Skip if not dirLight. if(sLightBuild.Type == SLightBuild::LightDir) sunLightEnabled= true; } } } // Good size pointLights.resize(nNumPointLight); // Build the ig //================= CInstanceGroup* pIG = new CInstanceGroup; // Link portals and clusters and create meta cluster if one pIG->build (vGlobalPos, aIGArray, vClusters, vPortals, pointLights); // IG touched by sun ?? pIG->enableRealTimeSunContribution(sunLightEnabled); return pIG; }
bool AlembicCurves::Save(double time, bool bLastFrame) { ESS_PROFILE_FUNC(); //TimeValue ticks = GET_MAX_INTERFACE()->GetTime(); TimeValue ticks = GetTimeValueFromFrame(time); Object *obj = mMaxNode->EvalWorldState(ticks).obj; if(mNumSamples == 0){ bForever = CheckIfObjIsValidForever(obj, ticks); } else{ bool bNewForever = CheckIfObjIsValidForever(obj, ticks); if(bForever && bNewForever != bForever){ ESS_LOG_INFO( "bForever has changed" ); } } SaveMetaData(mMaxNode, this); // check if the spline is animated if(mNumSamples > 0) { if(bForever) { return true; } } AbcG::OCurvesSchema::Sample curvesSample; std::vector<AbcA::int32_t> nbVertices; std::vector<Point3> vertices; std::vector<float> knotVector; std::vector<Abc::uint16_t> orders; if(obj->ClassID() == EDITABLE_SURF_CLASS_ID){ NURBSSet nurbsSet; BOOL success = GetNURBSSet(obj, ticks, nurbsSet, TRUE); AbcG::CurvePeriodicity cPeriod = AbcG::kNonPeriodic; AbcG::CurveType cType = AbcG::kCubic; AbcG::BasisType cBasis = AbcG::kNoBasis; int n = nurbsSet.GetNumObjects(); for(int i=0; i<n; i++){ NURBSObject* pObject = nurbsSet.GetNURBSObject((int)i); //NURBSType type = pObject->GetType(); if(!pObject){ continue; } if( pObject->GetKind() == kNURBSCurve ){ NURBSCurve* pNurbsCurve = (NURBSCurve*)pObject; int degree; int numCVs; NURBSCVTab cvs; int numKnots; NURBSKnotTab knots; pNurbsCurve->GetNURBSData(ticks, degree, numCVs, cvs, numKnots, knots); orders.push_back(degree+1); const int cvsCount = cvs.Count(); const int knotCount = knots.Count(); for(int j=0; j<cvs.Count(); j++){ NURBSControlVertex cv = cvs[j]; double x, y, z; cv.GetPosition(ticks, x, y, z); vertices.push_back( Point3((float)x, (float)y, (float)z) ); } nbVertices.push_back(cvsCount); //skip the first and last entry because Maya and XSI use this format for(int j=1; j<knots.Count()-1; j++){ knotVector.push_back((float)knots[j]); } if(i == 0){ if(pNurbsCurve->IsClosed()){ cPeriod = AbcG::kPeriodic; } } else{ if(pNurbsCurve->IsClosed()){ if(cPeriod != AbcG::kPeriodic){ ESS_LOG_WARNING("Mixed curve wrap types not supported."); } } else{ if(cPeriod != AbcG::kNonPeriodic){ ESS_LOG_WARNING("Mixed curve wrap types not supported."); } } } } } curvesSample.setType(cType); curvesSample.setWrap(cPeriod); curvesSample.setBasis(cBasis); } else { BezierShape beziershape; PolyShape polyShape; bool bBezier = false; // Get a pointer to the spline shpae ShapeObject *pShapeObject = NULL; if (obj->IsShapeObject()) { pShapeObject = reinterpret_cast<ShapeObject *>(obj); } else { return false; } // Determine if we are a bezier shape if (pShapeObject->CanMakeBezier()) { pShapeObject->MakeBezier(ticks, beziershape); bBezier = true; } else { pShapeObject->MakePolyShape(ticks, polyShape); bBezier = false; } // Get the control points //std::vector<Point3> inTangents; //std::vector<Point3> outTangents; if (bBezier) { int oldVerticesCount = (int)vertices.size(); for (int i = 0; i < beziershape.SplineCount(); i += 1) { Spline3D *pSpline = beziershape.GetSpline(i); int knots = pSpline->KnotCount(); for(int ix = 0; ix < knots; ++ix) { Point3 in = pSpline->GetInVec(ix); Point3 p = pSpline->GetKnotPoint(ix); Point3 out = pSpline->GetOutVec(ix); vertices.push_back( p ); //inTangents.push_back( in ); //outTangents.push_back( out ); } int nNumVerticesAdded = (int)vertices.size() - oldVerticesCount; nbVertices.push_back( nNumVerticesAdded ); oldVerticesCount = (int)vertices.size(); } } else { for (int i = 0; i < polyShape.numLines; i += 1) { PolyLine &refLine = polyShape.lines[i]; nbVertices.push_back(refLine.numPts); for (int j = 0; j < refLine.numPts; j += 1) { Point3 p = refLine.pts[j].p; vertices.push_back(p); } } } // set the type + wrapping curvesSample.setType(bBezier ? AbcG::kCubic : AbcG::kLinear); curvesSample.setWrap(pShapeObject->CurveClosed(ticks, 0) ? AbcG::kPeriodic : AbcG::kNonPeriodic); curvesSample.setBasis(AbcG::kNoBasis); } if(nbVertices.size() == 0 || vertices.size() == 0){ ESS_LOG_WARNING("No curve data to export."); return false; } const int vertCount = (int)vertices.size(); // prepare the bounding box Abc::Box3d bbox; // allocate the points and normals std::vector<Abc::V3f> posVec(vertCount); Matrix3 wm = mMaxNode->GetObjTMAfterWSM(ticks); for(int i=0;i<vertCount;i++) { posVec[i] = ConvertMaxPointToAlembicPoint(vertices[i] ); bbox.extendBy(posVec[i]); // Set the archive bounding box if (mJob) { Point3 worldMaxPoint = wm * vertices[i]; Abc::V3f alembicWorldPoint = ConvertMaxPointToAlembicPoint(worldMaxPoint); mJob->GetArchiveBBox().extendBy(alembicWorldPoint); } } if(knotVector.size() > 0 && orders.size() > 0){ if(!mKnotVectorProperty.valid()){ mKnotVectorProperty = Abc::OFloatArrayProperty(mCurvesSchema.getArbGeomParams(), ".knot_vector", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() ); } mKnotVectorProperty.set(Abc::FloatArraySample(knotVector)); if(!mOrdersProperty.valid()){ mOrdersProperty = Abc::OUInt16ArrayProperty(mCurvesSchema.getArbGeomParams(), ".orders", mCurvesSchema.getMetaData(), mJob->GetAnimatedTs() ); } mOrdersProperty.set(Abc::UInt16ArraySample(orders)); } // store the bbox curvesSample.setSelfBounds(bbox); mCurvesSchema.getChildBoundsProperty().set(bbox); Abc::Int32ArraySample nbVerticesSample(&nbVertices.front(),nbVertices.size()); curvesSample.setCurvesNumVertices(nbVerticesSample); // allocate for the points and normals Abc::P3fArraySample posSample(&posVec.front(),posVec.size()); curvesSample.setPositions(posSample); mCurvesSchema.set(curvesSample); mNumSamples++; return true; }
/* ==================== exportNode ==================== */ void G3DAExport::exportNode( INode* i_node, NODE* parent ) { // if it is hidden? bool include = false; if(!i_node->IsHidden()) include = true; // get the result of the pipeline at the current time Object *obj = i_node->EvalWorldState(mTime).obj; if(obj) { if(obj->ClassID() == Class_ID(TARGET_CLASS_ID, 0)) include = false; if(obj->ClassID() == Class_ID(0x74f93b07, 0x1eb34300)) include = false; if(obj->ClassID() == Class_ID(BOXOBJ_CLASS_ID, 0)) include = false; if(obj->ClassID() == Class_ID(SPHERE_CLASS_ID, 0)) include = false; if(obj->ClassID() == Class_ID(CYLINDER_CLASS_ID, 0)) include = false; if(obj->ClassID() == Class_ID(CONE_CLASS_ID, 0)) include = false; if(obj->SuperClassID() == CAMERA_CLASS_ID) include = false; if(obj->SuperClassID() == LIGHT_CLASS_ID) include = false; if(obj->SuperClassID() == SHAPE_CLASS_ID) include = false; } // if this node is renderable? if(include) { if(getModifier(i_node,Class_ID(PHYSIQUE_CLASS_ID_A, PHYSIQUE_CLASS_ID_B)) != NULL) { include = false; } if(getModifier(i_node,SKIN_CLASSID) != NULL) { mSkins.push_back(i_node); include = false; } } // the new node NODE* this_node = new NODE; MAX_CHECK(this_node); if(parent==NULL) { mRoot = this_node; } else { parent->children.push_back(this_node); this_node->parent = parent; } this_node->i_node = i_node; this_node->include = include; this_node->name = i_node->GetName(); if(this_node->include) { NODE* parent = this_node->parent; while(parent) { parent->include = true; parent = parent->parent; } } // process the child node for(int i = 0; i < i_node->NumberOfChildren(); i++) { exportNode(i_node->GetChildNode(i),this_node); } }
// Get hold of the transform controllers for the node... void XsiExp::ExportAnimKeys( INode * node, int & animHit) { // Targets are actually geomobjects, but we will export them // from the camera and light objects, so we skip them here. // Object * obj = node->EvalWorldState(GetStaticFrame()).obj; if (!obj || obj->ClassID() == Class_ID( TARGET_CLASS_ID, 0)) { return; } TSTR indent = GetIndent(1); BOOL bPosAnim, bRotAnim, bScaleAnim, bDoKeys = FALSE; TCHAR * name = FixupName( node->GetName()); BOOL isBone = obj->ClassID() == Class_ID(BONE_CLASS_ID, 0) ? TRUE : FALSE; if (isBone) { // bone anims get passed to children if (!node->GetParentNode() || node->GetParentNode()->IsRootNode()) { // can't anim top bone return; } node = node->GetParentNode(); } // We can only export keys if all TM controllers are "known" to us. // The reason for that is that some controllers control more than what // they should. Consider a path position controller, if you turn on // follow and banking, this position controller will also control // rotation. If a node that had a path position controller also had a // TCB rotation controller, the TCB keys would not describe the whole // rotation of the node. // For that reason we will only export keys if all controllers // position, rotation and scale are linear, hybrid (bezier) or tcb. if (!GetAlwaysSample()) { Control* pC = node->GetTMController()->GetPositionController(); Control* rC = node->GetTMController()->GetRotationController(); Control* sC = node->GetTMController()->GetScaleController(); if (IsKnownController(pC) && IsKnownController(rC) && IsKnownController(sC)) { bDoKeys = TRUE; } } if (bDoKeys) { // Only dump the track header if any of the controllers have keys if (node->GetTMController()->GetPositionController()->NumKeys() > 1 || node->GetTMController()->GetRotationController()->NumKeys() > 1 || node->GetTMController()->GetScaleController()->NumKeys() > 1) { if (!animHit) { fprintf(pStream,"AnimationSet {\n"); animHit = TRUE; } fprintf(pStream,"%sAnimation anim-%s {\n", indent.data(), name ); indent = GetIndent(2); fprintf(pStream,"%s{frm-%s}\n", indent.data(), name ); DumpRotKeys( node, 1); DumpPosKeys( node, 1); DumpScaleKeys( node, 1); indent = GetIndent(1); fprintf(pStream,"%s}\n\n", indent.data()); } } else if (CheckForAnimation(node, bPosAnim, bRotAnim, bScaleAnim)) { if (!animHit) { fprintf(pStream,"AnimationSet {\n"); animHit = TRUE; } fprintf(pStream,"%sAnimation anim-%s {\n", indent.data(), name ); indent = GetIndent(2); fprintf(pStream,"%s{frm-%s}\n", indent.data(), name ); DumpRotKeys( node, 1); DumpPosKeys( node, 1); DumpScaleKeys( node, 1); fprintf(pStream,"%s}\n", indent.data()); } }
/** * This method will export the argument node and traverse * into its child nodes to export them. */ BOOL OSGExp::nodeEnum(osg::Group* rootTransform, INode* node, osg::Group* parent) { osg::ref_ptr<osg::Group> child = NULL; _nCurNode++; _ip->ProgressUpdate((int)((float)_nCurNode/_nTotalNodeCount*100.0f)); // Stop traversing if the user pressed Cancel. if (_ip->GetCancel()) return TRUE; // If node is hidden and we are not exporting hidden nodes then return. if(node->IsNodeHidden() && !_options->getExportHiddenNodes()){ return TRUE; } // Capture a special group helper if one is returned. // Nodes such as LODs and Switches will have to apply // special flags to their immediate children and thus // cannot be traversed in the normal recursive flow. // osg::Group* specialGroup = NULL; // Only export if hole scene is to be exported or // this node is choosen to be exported. if(!_onlyExportSelected || node->Selected()) { // The ObjectState is a 'thing' that flows down the pipeline containing // all information about the object. By calling EvalWorldState() we tell // max to evaluate the object at the end of the pipeline. // An object may start out as an sphere, but could be modified by an modifier // object, the EvalWorldState will apply all modifiers to the original object // and return the final geometry for the object. ObjectState os = node->EvalWorldState(_ip->GetTime()); // Use temporary variables for cleaner code. Object* obj = os.obj; TimeValue timeValue = _ip->GetTime(); // If this a group node then make a OSG group node and add it to // the parent node and traverse into the children. if(node->IsGroupHead() || obj->ClassID() == Class_ID(DUMMY_CLASS_ID,0)) { // Do not export referenced groups. if(Util::isReferencedByHelperObjects(node, _helperIDs)) return TRUE; osg::MatrixTransform* groupNode = new osg::MatrixTransform(); // Set name of group node. groupNode->setName(std::string(node->GetName())); // Set static datavariance for better performance groupNode->setDataVariance(osg::Object::STATIC); // Are we exporting animations. if(_options->getExportAnimations()){ addAnimation(node, timeValue, groupNode); } // Set NodeMask if(_options->getUseDefaultNodeMaskValue()) groupNode->setNodeMask(_options->getDefaultNodeMaskValue()); groupNode->setMatrix(getNodeTransform(node, timeValue)); parent->addChild(groupNode); parent = groupNode; applyNodeMaskValue(node, timeValue, groupNode); } // If this is not a group node it could be a geomtry object, // a camera, a light, or some other class. Switch the class ID // to carry out a specific export. // Note, it is the obj member of ObjectState which // is the actual object we are exporting. else if(obj != NULL) { Class_ID cid = obj->ClassID(); // We look at the super class ID to determine the type of the object. switch(obj->SuperClassID()) { case GEOMOBJECT_CLASS_ID: if(!Util::isReferencedByHelperObjects(node, _helperIDs)) { child = createGeomObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } break; case CAMERA_CLASS_ID: if(_options->getExportCameras()) { child = createCameraObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } break; case LIGHT_CLASS_ID: if(_options->getExportLights()) { child = createLightObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } break; case SHAPE_CLASS_ID: if(_options->getExportShapes() && !Util::isReferencedByHelperObject(node, OCCLUDER_CLASS_ID)) { child = createShapeObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } break; case HELPER_CLASS_ID: { bool notRefByHelpers = Util::isReferencedByHelperObjects(node, _helperIDs) == NULL; bool exportHelpers = _options->getExportHelpers() == TRUE; if(_options->getExportPointHelpers() && cid == Class_ID(POINTHELP_CLASS_ID,0)) { child = createPointFromHelperObject(rootTransform, node, obj, timeValue).get(); parent->addChild(child.get()); } if(exportHelpers && notRefByHelpers) { if(cid == OSGGROUP_CLASS_ID) { child = createGroupFromHelper(parent, node, obj, timeValue).get(); } else if(cid == LOD_CLASS_ID) { child = createLODFromHelperObject(parent, node, obj, timeValue).get(); } else if(cid == SWITCH_CLASS_ID) { child = createSwitchFromHelperObject(parent, node, obj, timeValue).get(); } else if(cid == DOFTRANSFORM_CLASS_ID) { child = createDOFFromHelper(parent, node, obj, timeValue).get(); } else { rootTransform->addChild(createHelperObject(rootTransform, node, obj, timeValue).get()); } } } break; default: break; } } } for(int c = 0; c < node->NumberOfChildren(); c++) { if(_ip->GetCancel() || ! nodeEnum(rootTransform, node->GetChildNode(c),child.valid()?child.get():parent)) { // If user cancels export we return false. return FALSE; } } return TRUE; }
bool PFOperatorForceSpaceWarp::Proceed(IObject* pCont, PreciseTimeValue timeStart, PreciseTimeValue& timeEnd, Object* pSystem, INode* pNode, INode* actionNode, IPFIntegrator* integrator) { // acquire all necessary channels, create additional if needed IChannelContainer* chCont; chCont = GetChannelContainerInterface(pCont); if (chCont == NULL) return false; IParticleChannelAmountR* chAmount = GetParticleChannelAmountRInterface(pCont); if(chAmount == NULL) return false; int iQuant = chAmount->Count(); if (iQuant < 1) return true; // no particles to proceed IParticleChannelNewR* chNew = GetParticleChannelNewRInterface(pCont); if (chNew == NULL) return false; IParticleChannelIDR* chID = GetParticleChannelIDRInterface(pCont); if (chID == NULL) return false; IParticleChannelPTVR* chTime = GetParticleChannelTimeRInterface(pCont); if(chTime == NULL) return false; IParticleChannelPTVR* chAge = GetParticleChannelBirthTimeRInterface(pCont); if(chAge == NULL) return false; // the channel of interest speed bool initSpeed = false; //channel does not exist so make it and note that we have to fill it out IParticleChannelPoint3W* chSpeedW = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELSPEEDW_INTERFACE, ParticleChannelPoint3_Class_ID, true, PARTICLECHANNELSPEEDR_INTERFACE, PARTICLECHANNELSPEEDW_INTERFACE, true, actionNode, NULL, &initSpeed); IParticleChannelPoint3R* chSpeed = GetParticleChannelSpeedRInterface(pCont); if ((chSpeedW == NULL) || (chSpeed == NULL)) return false; bool initPosition = false; IParticleChannelPoint3W* chPosW = (IParticleChannelPoint3W*)chCont->EnsureInterface(PARTICLECHANNELPOSITIONW_INTERFACE, ParticleChannelPoint3_Class_ID, true, PARTICLECHANNELPOSITIONR_INTERFACE, PARTICLECHANNELPOSITIONW_INTERFACE, true, actionNode, NULL, &initPosition); IParticleChannelPoint3R* chPos = GetParticleChannelPositionRInterface(pCont); if ((chPosW == NULL) || (chPos == NULL)) return false; bool useScript = ((scriptPBlock()->GetInt(kForceSpaceWarp_useScriptWiring, 0) != 0) && (scriptPBlock()->GetInt(kForceSpaceWarp_useFloat, 0) == kForceSpaceWarp_useFloat_influence)); IParticleChannelFloatR* chFloat = NULL; if (useScript) { chFloat = GetParticleChannelMXSFloatRInterface(pCont); if (chFloat == NULL) return false; } int timeType = kAbsoluteTime; _pblock()->GetValue(kForceSpaceWarp_Sync,0, timeType, FOREVER); IParticleChannelPTVR* chEventStart = NULL; IParticleChannelPTVW* chEventStartW = NULL; bool initEventStart = false; if (timeType == kEventDuration) { chEventStartW = (IParticleChannelPTVW*) chCont->EnsureInterface(PARTICLECHANNELEVENTSTARTW_INTERFACE, ParticleChannelPTV_Class_ID, true, PARTICLECHANNELEVENTSTARTR_INTERFACE, PARTICLECHANNELEVENTSTARTW_INTERFACE, false, actionNode, NULL, &initEventStart); chEventStart = GetParticleChannelEventStartRInterface(pCont); if ((chEventStart == NULL) || (chEventStartW == NULL)) return false; } int overlapping = pblock()->GetInt(kForceSpaceWarp_Overlapping, 0); // collecting force fields Tab<ForceField*> ff; ForceField* curFF; int i, j; for(i=0; i<pblock()->Count(kForceSpaceWarp_ForceNodeList); i++) { INode* node = pblock()->GetINode(kForceSpaceWarp_ForceNodeList, 0, i); if (node == NULL) continue; Object* ob = GetPFObject(node->GetObjectRef()); if (ob == NULL) continue; if (ob->SuperClassID() == WSM_OBJECT_CLASS_ID) { WSMObject* obref = (WSMObject*)ob; curFF = obref->GetForceField(node); if (curFF != NULL) { if (ob->ClassID() == CS_VFIELDOBJECT_CLASS_ID) { // CS VectorField SW doesn't init properly partobj on GetForceField // this is a quick fix for that (bayboro 3/6/2003) CS_VectorField* vf = (CS_VectorField*)curFF; vf->partobj = GetParticleInterface(pSystem); } ff.Append(1, &curFF); } } } if (ff.Count() == 0) return true; // no force fields // some calls for a reference node TM may initiate REFMSG_CHANGE notification // we have to ignore that while processing the particles bool wasIgnoring = IsIgnoringRefNodeChange(); if (!wasIgnoring) SetIgnoreRefNodeChange(); float influence = 0.0f; for(i = 0; i < iQuant; i++) { TimeValue t = 0; if (timeType == kAbsoluteTime) t = chTime->GetValue(i).TimeValue(); else if (timeType == kParticleAge) t = chTime->GetValue(i).TimeValue() - chAge->GetValue(i).TimeValue(); else { if (initEventStart && chNew->IsNew(i)) chEventStartW->SetValue(i, chTime->GetValue(i)); t = chTime->GetValue(i).TimeValue() - chEventStart->GetValue(i).TimeValue(); } if (useScript) { influence = chFloat->GetValue(i); } else { influence = GetPFFloat(pblock(), kForceSpaceWarp_Influence, t); } Point3 v(0.0f,0.0f,0.0f); if (!initSpeed || !chNew->IsNew(i)) //if we created a speed channel the channel incoming is bogus so just use 0,0,0 ad default v = chSpeed->GetValue(i); Point3 p(0.0f,0.0f,0.0f); if (!initPosition || !chNew->IsNew(i)) //if we created a pos channel the channel incoming is bogus so just use 0,0,0 ad default p = chPos->GetValue(i); Point3 force = Point3::Origin; for(j=0; j<ff.Count(); j++) { // buffer vectors to guard true position and speed from malicious force Point3 pp = p; Point3 vv = v; Point3 nextForce = ff[j]->Force(t,pp,vv,chID->GetParticleBorn(i)) * influence; float lenSq = LengthSquared(nextForce); if (lenSq <= 0.0f) continue; // not a valid force if (overlapping == kForceSpaceWarp_Overlapping_additive) { force += nextForce; } else { if (lenSq > LengthSquared(force)) force = nextForce; } // p = pp; // v = vv; } v += force * float(timeEnd - chTime->GetValue(i)); chPosW->SetValue(i, p); chSpeedW->SetValue(i, v); } for(i=0; i<ff.Count(); i++) if (ff[i] != NULL) ff[i]->DeleteThis(); if (!wasIgnoring) ClearIgnoreRefNodeChange(); return true; }