Beispiel #1
0
/*
	Init character given serialized skeleton information
*/
void SBDebuggerUtility::initCharacter(const std::string& name, const std::string& skelName)
{
	if (name == "")
	{
		LOG("Character has no name - will not be created.");
		return;
	}
	SmartBody::SBCharacter* sbCharacter = SmartBody::SBScene::getScene()->createCharacter(name, "");
	if (!sbCharacter)
	{
		LOG("Problem creating character %s, will not be created in remote session...", name.c_str());
		return;
	}
	SmartBody::SBSkeleton* sbSkeleton = SmartBody::SBScene::getScene()->getSkeleton(skelName);
	if (!sbSkeleton)
	{
		LOG("Problem creating skeleton %s, character %s will not be created in remote session...", name.c_str(), skelName.c_str());
		return;
	}
	SmartBody::SBSkeleton* copySbSkeleton = new SmartBody::SBSkeleton(sbSkeleton);
	if (!copySbSkeleton)
	{
		LOG("Problem creating copy of skeleton %s, character %s will not be created in remote session...", name.c_str(), skelName.c_str());
		return;
	}
	sbCharacter->setSkeleton(copySbSkeleton);	
}
Beispiel #2
0
void ResourceWindow::updateCharacter( Fl_Tree_Item* tree, SmartBody::SBCharacter* character )
{
	SmartBody::SBCharacter* sbcharacter = dynamic_cast<SmartBody::SBCharacter*>(character);
	Fl_Tree_Item* item = resourceTree->add(tree,character->getName().c_str());
	item->user_data((void*) addSpecialName(character->getName()));
	resourceTree->sortorder(FL_TREE_SORT_NONE);		
	Fl_Tree_Item* skeletonFolder = resourceTree->add(item,"skeleton");	
	skeletonFolder->user_data((void*) _reverseSpecialNames["skeleton"]); 
	SmartBody::SBSkeleton* sbSk = sbcharacter->getSkeleton();
	if (sbSk)
	{
		Fl_Tree_Item* charSkItem = resourceTree->add(skeletonFolder, sbSk->getName().c_str());
	}
	Fl_Tree_Item* controllerFolder = resourceTree->add(item,"controllers");	
	controllerFolder->user_data((void*) _reverseSpecialNames["controller"]); 
	controllerFolder->close();
	// add controllers
	MeControllerTreeRoot* ctTree = character->ct_tree_p ;
	if( ctTree )
	{
		int n = ctTree->count_controllers();
		for (int c = 0; c < n; c++)
		{
			//LOG( "%s", ctTree->controller(c)->name() );
			Fl_Tree_Item* ctrlItem = resourceTree->add(controllerFolder,ctTree->controller(c)->getName().c_str());
//			ctrlItem->user_data((void*)ITEM_CONTROLLER);
		}
	}
	/*
	// add gesture map
	Fl_Tree_Item* gestureFolder = resourceTree->add(item,"gestures");	
	gestureFolder->user_data((void*)-1);
	gestureFolder->close();
	// add individual gesture mappings
	SmartBody::SBScene* scene = SmartBody::SBScene::getScene();

	SBGestureMap* gestureMap = scene->getGestureMapManager()->getGestureMap(sbcharacter->getName());
	if (gestureMap)
	{
		std::string lexeme;
		std::string type;
		std::string hand;
		std::string style;
		std::string posture;

		gestureMap->getGestureByInfo(lexeme, type, hand, style, posture);
		Fl_Tree_Item* gestureItem = resourceTree->add(gestureFolder, lexeme.c_str());
		gestureItem->user_data((void*)ITEM_GESTUREMAP);
	}
	*/

	// add NVBG
	Fl_Tree_Item* nvbgItem = resourceTree->add(item, "minibrain");
	nvbgItem->user_data((void*) _reverseSpecialNames["minibrain"]); 
	SmartBody::Nvbg* nvbg = character->getNvbg();
	if (nvbg)
	{
		nvbgItem = resourceTree->add(item, nvbg->getName().c_str());
	}
}
Beispiel #3
0
SBAPI bool SBM_GetCharacter( SBMHANDLE sbmHandle, const char * name, SBM_CharacterFrameDataMarshalFriendly * character )
{
   if ( !SBM_HandleExists( sbmHandle ) )
   {
      LOG("SBM_GetCharcter : Handle %d does not exist", sbmHandle);
      return false;
   }

   SmartBody::SBScene * scene = SmartBody::SBScene::getScene();
   SmartBody::SBCharacter * sbcharacter = scene->getCharacter(name);

   const SBM_CharacterFrameDataMarshalFriendly & data = sbcharacter->GetFrameDataMarshalFriendly();

   if (character->m_numJoints == 0 || character->m_numJoints != data.m_numJoints)
   {
      SBM_ReleaseCharacterJoints(character);

      character->m_numJoints = data.m_numJoints;
      character->jname = new char * [ character->m_numJoints ];
      character->jx = new float [ character->m_numJoints ];
      character->jy = new float [ character->m_numJoints ];
      character->jz = new float [ character->m_numJoints ];
      character->jrw = new float [ character->m_numJoints ];
      character->jrx = new float [ character->m_numJoints ];
      character->jry = new float [ character->m_numJoints ];
      character->jrz = new float [ character->m_numJoints ];

      for ( int i = 0; i < character->m_numJoints; i++ )
      {
         character->jname[ i ] = new char[ strlen(data.jname[ i ]) + 1 ];
         strcpy( character->jname[ i ], data.jname[ i ] );
      }
   }

   character->x = data.x;
   character->y = data.y;
   character->z = data.z;
   character->rw = data.rw;
   character->rx = data.rx;
   character->ry = data.ry;
   character->rz = data.rz;

   memcpy(character->jx,  data.jx,  data.m_numJoints * sizeof(float));
   memcpy(character->jy,  data.jy,  data.m_numJoints * sizeof(float));
   memcpy(character->jz,  data.jz,  data.m_numJoints * sizeof(float));
   memcpy(character->jrw, data.jrw, data.m_numJoints * sizeof(float));
   memcpy(character->jrx, data.jrx, data.m_numJoints * sizeof(float));
   memcpy(character->jry, data.jry, data.m_numJoints * sizeof(float));
   memcpy(character->jrz, data.jrz, data.m_numJoints * sizeof(float));

   return true;
}
Beispiel #4
0
void SBDebuggerUtility::initCharacterFaceDefinition(const std::string& characterName, const std::string& faceDefName, const std::string& message)
{
	SmartBody::SBScene* sbScene = SmartBody::SBScene::getScene();
	SmartBody::SBCharacter* sbCharacter = sbScene->getCharacter(characterName);
	if (!sbCharacter)
		return;

	SmartBody::SBFaceDefinition* faceDef = sbScene->getFaceDefinition(faceDefName);
	if (!faceDef)
		return;

	sbCharacter->setFaceDefinition(faceDef);
}
Beispiel #5
0
int main_sb( int argc, char** argv )
{
    osg::ArgumentParser arguments( &argc, argv );
    
    SmartBody::SBScene* scene = SmartBody::SBScene::getScene();
    scene->setMediaPath( "./smartbody/" );   // data/
    scene->addAssetPath( "motion", "ChrBrad" );
    scene->addAssetPath( "mesh", "mesh");
    scene->addAssetPath( "script", "scripts");
    scene->loadAssets();
    
    int numMotions = scene->getNumMotions();
    std::cout << "Loaded motions: " << numMotions << std::endl;
    
    SmartBody::SBCharacter* character = scene->createCharacter( "mycharacter", "" );
    SmartBody::SBSkeleton* skeleton = scene->createSkeleton( "ChrBrad.sk" );
    character->setSkeleton( skeleton );
    character->createStandardControllers();
    
    SmartBody::SBSimulationManager* sim = scene->getSimulationManager();
    sim->setupTimer();
    
    osg::ref_ptr<osg::Group> root = new osg::Group;
    
    osgViewer::Viewer viewer;
    viewer.setCameraManipulator( new osgGA::TrackballManipulator );
    viewer.addEventHandler( new osgGA::StateSetManipulator(viewer.getCamera()->getOrCreateStateSet()) );
    viewer.addEventHandler( new osgViewer::StatsHandler );
    viewer.addEventHandler( new osgViewer::WindowSizeHandler );
    viewer.setSceneData( root.get() );
    viewer.setUpViewOnSingleScreen( 1 );
    
    std::string ret =  scene->getBmlProcessor()->execBML( "mycharacter", "<body posture=\"ChrBrad@Idle01\"/>" );
    sim->start();
    while ( !viewer.done() )
    {
        scene->update();
		
		int numCharacters = scene->getNumCharacters();
		if (numCharacters == 0)
			return true;

		sim->updateTimer();
        viewer.frame();
    }
    sim->stop();
    return 0;
}
Beispiel #6
0
void SBDebuggerUtility::updateCharacter(const std::string& cName, const std::string& jName, 
										 float& posX, float& posY, float& posZ, 
										 float& rotX, float& rotY, float& rotZ, float& rotW)
{
	SmartBody::SBCharacter* sbCharacter = SmartBody::SBScene::getScene()->getCharacter(cName);
	if (!sbCharacter)
		return;

	SmartBody::SBJoint* sbJoint = sbCharacter->getSkeleton()->getJointByName(jName);
	if (sbJoint)
	{
		sbJoint->pos()->value(0, (float)posX);
		sbJoint->pos()->value(1, (float)posY);
		sbJoint->pos()->value(2, (float)posZ);
		SrQuat q = SrQuat((float)rotW, (float)rotX, (float)rotY, (float)rotZ);
		SrQuat newq = sbJoint->getPrerotation().inverse()*q;
		sbJoint->quat()->value(newq);
	}
}
Beispiel #7
0
void MiniBrain::update(SBCharacter* character, double time, double dt)
{
	
	if (minibrainCounter < 300)
	{
		minibrainCounter ++;
		return;
	}
	SrVec myVelocity;
	SrVec myPosition;
	float mySpeed = 0.0f;
	SrVec myFacing(0, 0, 1);
	// determine the facing vector
	SkJoint* base = character->getSkeleton()->search_joint("base");
	if (base)
	{
		SkJointQuat* jointQuat = base->quat();
		const SrQuat& quat = jointQuat->orientation();
		SrVec zfacing(0, 0, 1);
		myFacing = zfacing * quat;
	}
	const std::vector<std::string>& pawns = SmartBody::SBScene::getScene()->getPawnNames();
	for (std::vector<std::string>::const_iterator pawnIter = pawns.begin();
		pawnIter != pawns.end();
		pawnIter++)
	{
		SBPawn* pawn = SmartBody::SBScene::getScene()->getPawn((*pawnIter));

		// determine the velocity of the object
		std::map<std::string, ObjectData>::iterator piter = _data.find(pawn->getName());
		if (piter != _data.end())
		{
			ObjectData& data = (*piter).second;
			// get the last position
			SrVec& lastPosition = data.position;
			// get the current position
			SmartBody::SBCharacter* curCharacter = dynamic_cast<SmartBody::SBCharacter*>(pawn);
			SrVec curPosition;
			if (curCharacter)
			{
				curPosition = curCharacter->getPosition();
				data.isAnimate = true;
			}
			else
			{
				float x, y, z, h, p, r;
				pawn->get_world_offset(x, y, z, h, p, r);
				curPosition.x = x;
				curPosition.y = y;
				curPosition.z = z;
				data.isAnimate = false;
			}
			
			data.velocity = (curPosition - data.position) / (float) dt;
			if ((int)data.cachePositions.size() > _cacheLimit)
				data.cachePositions.pop_front();
			data.cachePositions.push_back(curPosition);
			SrVec temp;
			for (	std::list<SrVec>::iterator iter = data.cachePositions.begin();
					iter != data.cachePositions.end();
					iter++)
			{
				temp += (*iter);
			}
			data.position = temp / float(data.cachePositions.size());

			//data.position = curPosition;
			if (curCharacter && curCharacter == character)
			{
				myVelocity = data.velocity;
				myPosition = data.position;
				mySpeed = myVelocity.len();
			}
		}
		else
		{
			// seed the object data with position, no velocity
			ObjectData data;
			// get the current position
			SmartBody::SBCharacter* curCharacter = dynamic_cast<SmartBody::SBCharacter*>(pawn);
			SrVec curPosition;
			if (curCharacter)
			{
				curPosition = curCharacter->getPosition();
			}
			else
			{
				float x, y, z, h, p, r;
				pawn->get_world_offset(x, y, z, h, p, r);
				curPosition.x = x;
				curPosition.y = y;
				curPosition.z = z;
			}
			data.velocity = SrVec();
			data.position = curPosition;
			if ((int)data.cachePositions.size() > _cacheLimit)
				data.cachePositions.pop_front();
			data.cachePositions.push_back(curPosition);
			data.startGazeTime = -1;
			_data.insert(std::pair<std::string, ObjectData>(pawn->getName(), data));
		}
	}

	std::string fastestObject = "";
	float fastest = -1;
	ObjectData* fastestData = NULL;
	for (std::map<std::string, ObjectData>::iterator piter = _data.begin();
		 piter != _data.end();
		 piter++)
	{
		std::string pawnName = (*piter).first;
		if (pawnName == character->getName())
			continue;
		// calculate the relative positon and relative velocity
		ObjectData& data = (*piter).second;
		data.relativePosition = myPosition - data.position;
		data.relativeVelocity = myVelocity - data.velocity;
		float size = data.relativeVelocity.len();
		// ignore objects that aren't moving faster than you are
		if (size <= mySpeed)
			continue;
		if (size > fastest)
		{
			// ignore activity that is happening behind the character
			SrVec diffVec = data.position - myPosition;
			float result = dot(myFacing, diffVec);
			if (result < 0.0f)
				continue;
			fastestObject = pawnName;
			fastest = size;
			fastestData = &data;
		}
	}
	
	Nvbg* nvbg = character->getNvbg();
	if (nvbg) // if an NVBG instance is running, send this information there
	{
		for (std::map<std::string, ObjectData>::iterator piter = _data.begin();
			 piter != _data.end();
			 piter++)
		{
			const std::string& pawnName = (*piter).first;
			ObjectData& data = (*piter).second;
			nvbg->objectEvent(character->getName(), pawnName, data.isAnimate, myPosition, myVelocity, data.position, data.velocity, data.relativePosition, data.relativeVelocity);
		}
	}
	else // simple functionality - look at things that move quickly
	{
		

		// now look at the fastest thing moving that exceeds a threshold
		float characterHeight = character->getHeight();
		if (fastest > characterHeight / 10.0)
		{
			SbmPawn* gazeTarget =  SmartBody::SBScene::getScene()->getPawn(fastestObject);
			if (!gazeTarget)
				return;

			// make sure that we aren't already gazing at this object
			MeCtScheduler2* gazeSchedule = character->gaze_sched_p;
			if (!gazeSchedule)
				return;
			MeCtScheduler2::VecOfTrack tracks = gazeSchedule->tracks();
			for (size_t t = 0; t < tracks.size(); t++)
			{
				MeController* controller = tracks[t]->animation_ct();
				MeCtGaze* gaze = dynamic_cast<MeCtGaze*>(controller);
				if (gaze)
				{
					float x, y, z;
					SkJoint* joint = gaze->get_target_joint(x, y, z);
					if (joint && joint->skeleton() == gazeTarget->getSkeleton())
					{
						// update the time
						fastestData->startGazeTime = time;
						return;
					}
				}
			}
			std::stringstream strstr;
			strstr << "bml char " << character->getName() << " <gaze target=\"" << fastestObject << "\" sbm:joint-range=\"EYES NECK\"/>" << std::endl;
			fastestData->startGazeTime = time;
			SmartBody::SBScene::getScene()->getCommandManager()->execute((char*) strstr.str().c_str());
			return;
		}

		// if we are staring at nothing, fade out any gazes for objects that have been 'uninteresting' for more than 2 seconds
		for (std::map<std::string, ObjectData>::iterator piter = _data.begin();
			 piter != _data.end();
			 piter++)
		{
			ObjectData& data = (*piter).second;
			if (data.startGazeTime > 0 && (time - data.startGazeTime) > 2.0 + float(rand() % 100) * .01f)
			{
				std::stringstream strstr;
				strstr << "char " << character->getName() << " gazefade out .5" << std::endl;
				data.startGazeTime = -1;
				SmartBody::SBScene::getScene()->getCommandManager()->execute((char*) strstr.str().c_str());

				std::stringstream strstr2;
				strstr2 << "char " << character->getName() << " prune" << std::endl;
				SmartBody::SBScene::getScene()->getCommandManager()->execute_later((char*) strstr2.str().c_str(), 3 + float(rand() % 100) * .01f);


			}
		}
	}

	
}
Beispiel #8
0
bool OgreSmartBody::frameRenderingQueued(const Ogre::FrameEvent& evt)
{
    if(mWindow->isClosed())
        return false;
 
    //Need to capture/update each device
    mKeyboard->capture();
    mMouse->capture();
 
    if(mKeyboard->isKeyDown(OIS::KC_ESCAPE))
        return false;

	// smartbody
	if (!m_pScene)
		return true;

	SmartBody::SBSimulationManager* sim = m_pScene->getSimulationManager();
	sim->setTime((Ogre::Root::getSingleton().getTimer()->getMilliseconds() / 1000.0f) - mStartTime);
	m_pScene->update();

	int numCharacters = m_pScene->getNumCharacters();
	if (numCharacters == 0)
		return true;

	const std::vector<std::string>& characterNames = m_pScene->getCharacterNames();

	for (size_t n = 0; n < characterNames.size(); n++)
	{
		SmartBody::SBCharacter* character = m_pScene->getCharacter(characterNames[n]);
		if (!this->getSceneManager()->hasEntity(characterNames[n]))
			continue;

		Ogre::Entity* entity = this->getSceneManager()->getEntity(characterNames[n]);
		Ogre::Skeleton* meshSkel = entity->getSkeleton();
		Ogre::Node* node = entity->getParentNode();

		SrVec pos = character->getPosition();
		SrQuat ori = character->getOrientation();
		//std::cout << ori.w << ori.x << " " << ori.y << " " << ori.z << std::endl;
		node->setPosition(pos.x, pos.y, pos.z);
		node->setOrientation(ori.w, ori.x, ori.y, ori.z);
	
		// Update joints
		SmartBody::SBSkeleton* sbSkel = character->getSkeleton();
			
		int numJoints = sbSkel->getNumJoints();
		for (int j = 0; j < numJoints; j++)
		{
			SmartBody::SBJoint* joint = sbSkel->getJoint(j);
	
			try
			{
				SrQuat orientation = joint->quat()->value();
	
				Ogre::Vector3 posDelta(joint->getPosition().x, joint->getPosition().y, joint->getPosition().z);
				Ogre::Quaternion quatDelta(orientation.w, orientation.x, orientation.y, orientation.z);
				Ogre::Bone* bone = meshSkel->getBone(joint->getName());
				if (!bone)
					continue;
				bone->setPosition(bone->getInitialPosition() + posDelta);
				bone->setOrientation(quatDelta);
			}
			catch (Ogre::ItemIdentityException& ex)
			{
				// Should not happen as we filtered using m_mValidBones
			}
		}
	}
	

 
    return true;
}
Beispiel #9
0
BML::BehaviorRequestPtr BML::parse_bml_states( DOMElement* elem, const std::string& unique_id, BehaviorSyncPoints& behav_syncs, bool required, BmlRequestPtr request, SmartBody::SBScene* scene )
{
	// local Id
	std::string localId;
	const XMLCh* attrID = elem->getAttribute(BMLDefs::ATTR_ID);
	xml_utils::xml_translate(&localId, attrID);

	// get character
	std::string characterName = request->actor->getName();
	SmartBody::SBCharacter* character = SmartBody::SBScene::getScene()->getCharacter(characterName);
	if (character == NULL)
	{
		LOG("parse_bml_states ERR: cannot find character with name %s.", characterName.c_str());
		return BehaviorRequestPtr();
	}


	MeCtParamAnimation* paramCt = character->param_animation_ct;
	std::string layer = xml_parse_string(BMLDefs::ATTR_LAYER, elem);
	if (layer == "1")
		paramCt = character->param_animation_ct;
	if (layer == "2")
		paramCt = character->param_animation_ct_layer1;
	if (layer == "3")
		paramCt = character->param_animation_ct_layer2;

	if (!paramCt)
	{
		LOG("No parameterized animation controller present for character %s.", character->getName().c_str());
		return BehaviorRequestPtr();
	}

	// get state
	std::string stateName = xml_parse_string(BMLDefs::ATTR_NAME, elem);
	if (stateName == "")
	{
		LOG("parse_bml_states ERR: expecting a state name.");
		return BehaviorRequestPtr();
	}
	PABlend* state = SmartBody::SBScene::getScene()->getBlendManager()->getBlend(stateName);
	if (!state)
	{
		LOG("parse_bml_states WARNING: Can't find state name %s, will schedule PseudoIdle state under schedule mode", stateName.c_str());
	}

	// get parameters
	std::string mode = xml_parse_string(BMLDefs::ATTR_MODE, elem);
	if (mode == "")
		mode = "schedule";
	std::string xString = xml_parse_string(BMLDefs::ATTR_X, elem);
	std::string yString = xml_parse_string(BMLDefs::ATTR_Y, elem);
	std::string zString = xml_parse_string(BMLDefs::ATTR_Z, elem);

	// get weights from parameters
	std::vector<double> weights;
	if (state)
	{
		weights.resize(state->getNumMotions());
	}

	if (weights.size() > 0)
		weights[0] = 1.0f;

	double x = 0;
	double y = 0;
	double z = 0;
	if ((xString != "" || yString != "" || zString != "") && state)
	{
		x = atof(xString.c_str());
		y = atof(yString.c_str());
		z = atof(zString.c_str());
		int parameterType = state->getType();
		if (parameterType == 0)
			state->getWeightsFromParameters(x, weights);
		if (parameterType == 1)
			state->getWeightsFromParameters(x, y, weights);
		if (parameterType == 2)
			state->getWeightsFromParameters(x, y, z, weights);
	}

	// wrap mode
	ScheduleType scType;
	std::string wrap = xml_parse_string(BMLDefs::ATTR_WRAPMODE, elem);
	if (wrap == "")
		wrap = "Loop";
	boost::algorithm::to_lower(wrap);
	scType.wrap = PABlendData::Loop;
	if (wrap == "once")
		scType.wrap = PABlendData::Once;
	if (wrap == "clamp")
		scType.wrap = PABlendData::Clamp;

	// schedule mode
	std::string schedule = xml_parse_string(BMLDefs::ATTR_SCHEDULEMODE, elem);
	if (schedule == "")
		schedule = "Queued";
	boost::algorithm::to_lower(schedule);
	scType.schedule = PABlendData::Queued;
	if (schedule == "now")
		scType.schedule = PABlendData::Now;

	// blend mode
	std::string blend = xml_parse_string(BMLDefs::ATTR_BLENDMODE, elem);
	if (blend == "")
		blend = "Overwrite";
	boost::algorithm::to_lower(blend);
	scType.blend =PABlendData::Overwrite;
	if (blend == "additive")
		scType.blend = PABlendData::Additive;

	// partial joint name
	std::string joint = xml_parse_string(BMLDefs::ATTR_PARTIALJOINT, elem);
	if (joint == "")
		joint = "null";

	// take time offset0
	scType.jName = joint;
	scType.timeOffset = xml_parse_double(BMLDefs::ATTR_START, elem);
	scType.stateTimeOffset = xml_parse_double(BMLDefs::ATTR_OFFSET, elem, 0.0);
	scType.stateTimeTrim = xml_parse_double(BMLDefs::ATTR_TRIM, elem, 0.0);
	scType.transitionLen = xml_parse_double(BMLDefs::ATTR_TRANSITION_LENGTH, elem, -1.0);
	scType.playSpeed = xml_parse_double(BMLDefs::ATTR_SPEED, elem, 1.0);
	scType.duration = xml_parse_double(BMLDefs::ATTR_DURATION, elem, -1.0);
	std::string directPlayStr = xml_parse_string(BMLDefs::ATTR_DIRECTPLAY, elem, "false");
	scType.directPlay = false;
	if (directPlayStr == "true")
		scType.directPlay = true;

	SmartBody::SBAnimationBlend0D* ZeroDState = dynamic_cast<SmartBody::SBAnimationBlend0D*>(state);
	if (!ZeroDState) // don't use state offset unless it is a 0-D state
	{
		scType.stateTimeOffset = 0.0;
		scType.stateTimeTrim = 0.0;
	}
	// schedule a state
	if (mode == "schedule")
	{
		if (state)
			//character->param_animation_ct->schedule(state, x, y, z, wrapMode, scheduleMode, blendMode, joint, timeOffset, stateStartOffset, stateEndTrim, transitionLen, directPlay);
			//character->param_animation_ct->schedule(state, weights, scType);
			paramCt->schedule(state, weights, scType);
		else
			//character->param_animation_ct->schedule(state, weights, scType);
			paramCt->schedule(state, weights, scType);
	}

	// update parameter
	if (mode == "update")
	{
		// character->param_animation_ct->updateWeights(weights);
		paramCt->updateWeights(weights);
		paramCt->getCurrentPABlendData()->wrapMode = scType.wrap;
	}

	return BehaviorRequestPtr( new EventRequest(unique_id, localId, "", "", behav_syncs, ""));
}
void PAAutoFootStepsEditor::confirmEditting(Fl_Widget* widget, void* data)
{
	PAAutoFootStepsEditor* footStepEditor = (PAAutoFootStepsEditor*) data;
	
	PABlend* currentState = footStepEditor->stateEditor->getCurrentState();
	if (!currentState)
	{	
		LOG("PAAutoFootStepsEditor::confirmEditting WARNING: please select a state!");
		return;
	}

	// take down previous correspondence points first
	footStepEditor->stateEditor->previousKeys.clear();
	footStepEditor->stateEditor->previousKeys.resize(currentState->getNumMotions());
	for (int i = 0; i < currentState->getNumMotions(); i++)
	{
		footStepEditor->stateEditor->previousKeys[i].resize(currentState->getNumKeys());
		footStepEditor->stateEditor->previousKeys[i] = currentState->keys[i];
	}

	// auto foot steps algorithm
	float floorHeight = (float)atof(footStepEditor->inputFloorHeight->value());
	float heightThresh = (float)atof(footStepEditor->inputHeightThreshold->value());
	float speedThresh = (float)atof(footStepEditor->inputSpeedThreshold->value());
	int speedWindow = atoi(footStepEditor->inputSpeedDetectWindow->value());
	int stepsPerJoint = atoi(footStepEditor->inputStepsPerJoint->value());
	if (stepsPerJoint < 1)
		stepsPerJoint = 1;
	int checkDebugInfoVal = footStepEditor->checkDebugInfo->value();
	if (checkDebugInfoVal == 0)
		footStepEditor->isPrintDebugInfo = false;
	if (checkDebugInfoVal == 1)
		footStepEditor->isPrintDebugInfo = true;

	const std::vector<std::string>& selectedMotions = footStepEditor->stateEditor->getSelectedMotions();
	SmartBody::SBCharacter* curCharacter = footStepEditor->stateEditor->paWindow->getCurrentCharacter();
	std::vector<std::string> selectedJoints;
	for (int i = 0; i < footStepEditor->browserJoint->size(); i++)
	{
		if (footStepEditor->browserJoint->selected(i+1))
		{
			selectedJoints.push_back(footStepEditor->browserJoint->text(i + 1));
		}
	}
	if (selectedJoints.size() == 0)
	{
		fl_alert("Please select at least one joint.");
		return;
	}

	std::stringstream finalMessage;
	std::vector<std::string> motionsNeedManualAdjusting;
	finalMessage << "Current State: " << currentState->stateName << "\n";

	bool isConvergent = true;
	for (size_t m = 0; m < selectedMotions.size(); m++)
	{
		// shared
		std::vector<double> possibleTiming;

		// divided
		std::vector<std::vector<double> > vecOutMeans;
		vecOutMeans.resize(selectedJoints.size());
		std::vector<std::vector<double> > vecTiming;
		vecTiming.resize(selectedJoints.size());

		SmartBody::SBMotion* motion = SmartBody::SBScene::getScene()->getMotion(selectedMotions[m]);
		if (!motion)
			continue;

#if 1 // feng : I tried to refactor the footstep detection into a API function in SBMotion. 
	  // Still contains too many parameters to be used as an API. But would clean it up more and see if we can come up with 
	  // a version that can also detect the number of steps as the input. If this is interfering with the editor, set this back to 0.	  
		std::vector<double> outMeans;
		int maxNumSteps = footStepEditor->stateEditor->getCurrentState()->getNumKeys();
		if (!footStepEditor->isProcessAll)
		{
			stepsPerJoint = maxNumSteps / selectedJoints.size();
		}
		else
		{
			maxNumSteps = stepsPerJoint * selectedJoints.size();
		}

// 		std::vector<FootStepRecord> footSteps;
// 		motion->autoFootPlantDetection(curCharacter->getSkeleton(),selectedJoints,floorHeight, heightThresh,speedThresh,footSteps);
// 
// 		for (int i=0;i<footSteps.size();i++)
// 		{
// 			FootStepRecord& record = footSteps[i];
// 			LOG("Footstep joint = %s, start frame = %f, end frame = %f",record.jointName.c_str(), record.startTime, record.endTime);
// 		}


		isConvergent = motion->autoFootStepDetection(outMeans, stepsPerJoint, maxNumSteps, curCharacter->getSkeleton(), selectedJoints,
			                          floorHeight, heightThresh, speedThresh, speedWindow, footStepEditor->isPrintDebugInfo);

#else 
		motion->connect(curCharacter->getSkeleton());

		for(int f = 0; f < motion->getNumFrames(); f++)
		{
			motion->apply_frame(f);
			motion->connected_skeleton()->update_global_matrices();

			for (size_t jointId = 0; jointId < selectedJoints.size(); jointId ++)
			{
				std::string jointName = selectedJoints[jointId];
				SBJoint* joint = curCharacter->getSkeleton()->getJointByName(jointName);
				if (!joint)
					continue;

				// get height
				const SrMat& gMat = joint->gmat();
				SrVec gPos = SrVec(gMat.get(12), gMat.get(13), gMat.get(14));

				// get speed
				int startFrame = f - speedWindow / 2;
				int endFrame = f + speedWindow / 2;
				float startTime = startFrame * (float)motion->getFrameRate();
				float endTime = endFrame * (float)motion->getFrameRate();
				float speed = motion->getJointSpeed(joint, startTime, endTime);
				
				// print info
				if (footStepEditor->isPrintDebugInfo)
					LOG("motion %s at time %f-> speed is %f, height is %f, joint is %s", motion->getName().c_str(), f * motion->getFrameRate(), speed, gPos.y, jointName.c_str());

				// filter for height
				if (gPos.y < floorHeight || gPos.y > (floorHeight + heightThresh))
					continue;

				// filter speed
				if (speed <= speedThresh)
				{
					vecTiming[jointId].push_back(f * (float)motion->getFrameRate());
					possibleTiming.push_back(f * (float)motion->getFrameRate());
				}
			}
		}

		// K means algorithm according to desired number of steps
		std::vector<double> outMeans;
		int maxNumSteps = footStepEditor->stateEditor->getCurrentState()->getNumKeys();
		if (!footStepEditor->isProcessAll)
		{
			stepsPerJoint = maxNumSteps / selectedJoints.size();
		}
		else
		{
			maxNumSteps = stepsPerJoint * selectedJoints.size();
		}

		/*
		int numSteps = footStepEditor->stateEditor->getCurrentState()->getNumKeys();
		isConvergent = footStepEditor->kMeansClustering1D(numSteps, possibleTiming, outMeans);
		*/

		for (size_t jointId = 0; jointId < selectedJoints.size(); jointId++)
		{
			if (jointId == (selectedJoints.size() - 1) && !footStepEditor->isProcessAll)
			{
				int mod = footStepEditor->stateEditor->getCurrentState()->getNumKeys() % selectedJoints.size();
				stepsPerJoint += mod;
			}

			bool retBoolean = footStepEditor->kMeansClustering1D(stepsPerJoint, vecTiming[jointId], vecOutMeans[jointId]);
			if (!retBoolean)
			{
				isConvergent = false;
				break;
			}
		}
		if (isConvergent)
		{
			outMeans.clear();
			for (size_t joinId = 0; joinId < selectedJoints.size(); joinId++)
			{
				for (size_t meanId = 0; meanId < vecOutMeans[joinId].size(); meanId++)
					outMeans.push_back(vecOutMeans[joinId][meanId]);
			}
			std::sort(outMeans.begin(), outMeans.end());
		}
#endif

		// apply it to corresponding points
		// also appending starting and ending corresponding points
		int motionIndex = currentState->getMotionId(selectedMotions[m]);
		if (isConvergent)
		{
			std::stringstream ss;
			ss << "[" << motion->getName() << "]detected ";
			for (size_t i = 0; i < outMeans.size(); i++)
				ss << outMeans[i] << " ";
			LOG("%s", ss.str().c_str());
			finalMessage << ss.str() << "\n";
			currentState->keys[motionIndex].clear();
			if (footStepEditor->isProcessAll)
				currentState->keys[motionIndex].push_back(0);
			for (size_t i = 0; i < outMeans.size(); i++)
				currentState->keys[motionIndex].push_back(outMeans[i]);
			if (footStepEditor->isProcessAll)
				currentState->keys[motionIndex].push_back(motion->getDuration());
		}
		else
		{
			motionsNeedManualAdjusting.push_back(motion->getName());
			std::stringstream ss;
			ss << "[" << motion->getName() << "]NOT detected(evenly distrubted): ";
			int actualNum = maxNumSteps;
			currentState->keys[motionIndex].clear();
			if (footStepEditor->isProcessAll)
				actualNum += 2;
			for (int i = 0; i < actualNum; i++)
			{
				double step = motion->getDuration() / double(actualNum - 1);
				currentState->keys[motionIndex].push_back(step * i);
				ss << step * i << " ";
			}
			LOG("%s", ss.str().c_str());
			finalMessage << ss.str() << "\n";
		}
		motion->disconnect();
	}

	// print out final message
	finalMessage << "\n\n=======Summary=======\n";
	for (size_t m = 0; m < motionsNeedManualAdjusting.size(); m++)
	{
		finalMessage << motionsNeedManualAdjusting[m] << " may need manual adjusting\n";
	}
	fl_message("%s", finalMessage.str().c_str());

	// refresh state editor
	footStepEditor->stateEditor->buttonUndoAutoFootSteps->activate();
	footStepEditor->stateEditor->refresh();
	footStepEditor->hide();	
}
PAAutoFootStepsEditor::PAAutoFootStepsEditor(PABlendEditor* editor, int x, int y, int w, int h) : Fl_Window(x, y, w, h)
{
	set_modal();
	stateEditor = editor;
	xDis = 10;
	yDis = 10;
	int csx = xDis;
	int csy = yDis;	
	isPrintDebugInfo = false;

	this->label("Auto Footsteps Editor");
	this->begin();
	inputFloorHeight = new Fl_Input(xDis + csx + 100, yDis, 10 * xDis, 2 * yDis, "FloorHeight");
	inputFloorHeight->value("0");
	inputHeightThreshold = new Fl_Input(xDis + csx + 100, 4 * yDis, 10 * xDis, 2 * yDis, "HeightThreshold");
	std::stringstream inputHeightSS;
	inputHeightSS << 0.15f / SmartBody::SBScene::getScene()->getScale();
	inputHeightThreshold->value(inputHeightSS.str().c_str());
	inputSpeedThreshold = new Fl_Input(xDis + csx + 100, 7 * yDis, 10 * xDis, 2 * yDis, "SpeedThreshold");
	std::stringstream inputSpeedSS;
	inputSpeedSS << 0.4f / SmartBody::SBScene::getScene()->getScale();
	inputSpeedThreshold->value(inputSpeedSS.str().c_str());

	inputSpeedDetectWindow = new Fl_Input(xDis + csx + 100, 10 * yDis, 10 * xDis, 2 * yDis, "SpeedDetectWindow");
	inputSpeedDetectWindow->value("3");
	inputSpeedDetectWindow->deactivate();
	
	browserJoint = new Fl_Multi_Browser(xDis + csx + 100, 13 * yDis, 28 * xDis, 20 * yDis, "Joint");
	SmartBody::SBCharacter* character = stateEditor->paWindow->getCurrentCharacter();
	if (character)
	{
		const std::vector<std::string>& charJNames = character->getSkeleton()->getJointNames();
		for (size_t i = 0; i < charJNames.size(); i++)
			browserJoint->add(charJNames[i].c_str());
	}

	inputStepsPerJoint = new Fl_Input(xDis + csx + 100, 36 * yDis, 10 * xDis, 2 * yDis, "StepsPerJoint");
	PABlend* curState = stateEditor->getCurrentState();
	std::vector<std::string> selectedMotions = stateEditor->getSelectedMotions();
	if (selectedMotions.size() == curState->getNumMotions())
		inputStepsPerJoint->activate();
	else
		inputStepsPerJoint->deactivate();
	int stepsPerJoint = 2;
	std::stringstream ss;
	ss << stepsPerJoint;
	inputStepsPerJoint->value(ss.str().c_str());


	browserSelectedMotions = new Fl_Browser(xDis + csx + 100, 39 * yDis, 28 * xDis, 10 * yDis, "SelectedMotions");
	browserSelectedMotions->deactivate();
	refreshSelectedMotions();

	checkDebugInfo = new Fl_Check_Button(xDis + csx + 100, 51 * yDis, 10 * xDis, 2 * yDis, "DumpDetailInformation");

	buttonConfirm = new Fl_Button(xDis + csx, 55 * yDis, 10 * xDis, 2 * yDis, "Apply");
	buttonConfirm->callback(confirmEditting, this);
	buttonCancel = new Fl_Button(xDis + csx + 120, 55 * yDis, 10 * xDis, 2 * yDis, "Leave");
	buttonCancel->callback(cancelEditting, this);
	this->end();
}