コード例 #1
0
ファイル: Tentacle.cpp プロジェクト: CalebVDW/smr-motion
/**
* update the Horde tentacle according to Smr _tentacleIK
*/
static void updateTentacle()
{
  //set of floats storing Horde's tentacle joints state
  float tx,ty,tz,rx,ry,rz,foo;
  double rrx,rry,rrz;
  // a Horde handle towards a tentacle Bone (joint)
  H3DNode tentacleBone;
  // and its corresponding node in Smr
  SMRKinematicJoint* ikJoint;

  //get the transformation parameters from the SmrTentacle
  for( unsigned int i=0; i < _tentacleIK->getNumJoints()-1 ; i++)
  {
    ikJoint = _tentacleIK->getJoint(i);

    //get Horde tentacle's corresponding joint joint (Horde) 
    h3dFindNodes(H3DRootNode,ikJoint->getName().c_str(), H3DNodeTypes::Joint);
    tentacleBone = h3dGetNodeFindResult(0);
    h3dGetNodeTransform(tentacleBone,&tx,&ty,&tz,&rx,&ry,&rz,&foo,&foo,&foo);

    //put the rotation values into euler angles (in degrees)
    ikJoint->getOrientation().toEulerAngles(rrx,rry,rrz);

    // update tentacle's joint according to Smr kinematic chain equivalent
    h3dSetNodeTransform( tentacleBone, tx, ty, tz, radToDeg( ((float)(rrx)) ), radToDeg( ((float)(rry)) ), radToDeg( ((float)(rrz)) ), foo, foo, foo );
  }
  // orientate Horde tentacles root joint correctly //No more in the new version !
  ikJoint = _tentacleIK->getJoint(0);
  h3dFindNodes(H3DRootNode,ikJoint->getName().c_str(), H3DNodeTypes::Joint);
  tentacleBone = h3dGetNodeFindResult(0);
  h3dGetNodeTransform(tentacleBone,&tx,&ty,&tz,&rx,&ry,&foo,&foo,&foo,&foo);
  h3dSetNodeTransform(tentacleBone,tx,ty,tz,rx,ry,rz,foo,foo,foo);
}
コード例 #2
0
Joint* Joint::getInstance(H3DNode model, const char *name)
{
	h3dFindNodes( model, name, H3DNodeTypes::Joint );
	H3DNode id = h3dGetNodeFindResult(0);

	Joint* j = getInstance(id);

	return j;
}
コード例 #3
0
ファイル: main.cpp プロジェクト: dreamsxin/nawia
SCENEGRAPHPLUGINEXP void dllLoadScene( const char* sceneFile )
{
    GameLog::logMessage("Setting Horde3D Paths");

    XMLResults results;
    XMLNode scene = XMLNode::parseFile( sceneFile, "Configuration", &results);
    XMLNode& engineSettings(scene.getChildNode("EngineConfig"));
    if ( !engineSettings.isEmpty() )
    {
        bool loadTextures =
            _stricmp(engineSettings.getAttribute("loadTextures", "true"), "true") == 0 ||
            _stricmp(engineSettings.getAttribute("loadTextures", "1"), "1") == 0;
        GameLog::logMessage("LoadTextures: %s", loadTextures ? "enabled" : "disabled");
        h3dSetOption( H3DOptions::LoadTextures, loadTextures ? 1.0f : 0.0f );
        int shadowMapSize = atoi(engineSettings.getAttribute("shadowMapSize", "1024"));
        GameLog::logMessage("ShadowMapSize: %d", shadowMapSize);
        h3dSetOption( H3DOptions::ShadowMapSize, float( shadowMapSize) );
        int anisotropyFactor = atoi(engineSettings.getAttribute("anisotropyFactor", "1"));
        GameLog::logMessage("Anisotropy: %d", anisotropyFactor);
        h3dSetOption( H3DOptions::MaxAnisotropy, float( anisotropyFactor ) );
        bool texCompression =
            _stricmp(engineSettings.getAttribute("texCompression", "true"), "true") == 0 ||
            _stricmp(engineSettings.getAttribute("texCompression", "1"), "1") == 0;
        GameLog::logMessage("TexCompression: %s", texCompression ? "enabled" : "disabled");
        h3dSetOption( H3DOptions::TexCompression, texCompression );
        int maxNumMessages = atoi(engineSettings.getAttribute("maxNumMessages", "1024"));
        h3dSetOption( H3DOptions::MaxNumMessages, float( maxNumMessages ) );
    }

    // Loading scene graph
    XMLNode& sceneGraph(scene.getChildNode("SceneGraph"));
    if ( sceneGraph.isEmpty() ) GameLog::errorMessage("No Scene Graph Node found!");
    else
    {
        GameLog::logMessage("Loading SceneGraph %s", sceneGraph.getAttribute("path"));
        // Environment
        H3DRes sceneGraphID = h3dAddResource( H3DResTypes::SceneGraph, sceneGraph.getAttribute("path"), 0 );
        GameLog::logMessage("Loading Resources...");
        // Load resources
        h3dutLoadResourcesFromDisk( "." );
        GameLog::logMessage("Adding scene graph to root node");
        // Add scene nodes
        H3DNode newSceneID = h3dAddNodes( H3DRootNode, sceneGraphID);
        SceneGraphManager::instance()->addNewHordeNode( newSceneID );
    }
    // Use the specified render cam
    if (scene.getChildNode("ActiveCamera").getAttribute("name") && h3dFindNodes( H3DRootNode, scene.getChildNode("ActiveCamera").getAttribute("name"), H3DNodeTypes::Camera ) > 0)
        SceneGraphManager::instance()->setActiveCam( h3dGetNodeFindResult(0) );

}
コード例 #4
0
void SceneGraphComponent::setParentNode(H3DNode newParentNode, const Attach* data)
{
	if (m_hordeID > 0)
	{
		if(data->Child && strcmp(data->Child,"") != 0 )
		{
			int nodes = h3dFindNodes( newParentNode, data->Child, H3DNodeTypes::Undefined );
			H3DNode child = h3dGetNodeFindResult(0);
	
			h3dSetNodeParent(m_hordeID, child);
		}
		else
		{
			h3dSetNodeParent(m_hordeID, newParentNode);
		}

		h3dSetNodeTransform(m_hordeID,data->Tx,data->Ty, data->Tz,
			data->Rx, data->Ry, data->Rz,
			data->Sx, data->Sy, data->Sz);

		checkTransformation();
	}
}
コード例 #5
0
SCENEGRAPHPLUGINEXP void dllLoadScene( const char* sceneFile )
{
	GameLog::logMessage("Setting Horde3D Configuration");
	
	XMLResults results;
	XMLNode scene = XMLNode::parseFile( sceneFile, "Configuration", &results);
	const XMLNode& engineSettings(scene.getChildNode("EngineConfig"));
	if ( !engineSettings.isEmpty() )
	{
		int maxLogLevel = atoi(engineSettings.getAttribute("maxLogLevel", "4"));
		GameLog::logMessage("MaxLogLevel: %d", maxLogLevel);
		h3dSetOption( H3DOptions::MaxLogLevel, float( maxLogLevel ) );

		int maxNumMessages = atoi(engineSettings.getAttribute("maxNumMessages", "1024"));
		GameLog::logMessage("MaxNumMessages: %d", maxNumMessages);
		h3dSetOption( H3DOptions::MaxNumMessages, float( maxNumMessages ) );

		int trilinearFiltering = atoi(engineSettings.getAttribute("trilinearFiltering", "1"));
		GameLog::logMessage("TrilinearFiltering: %d", trilinearFiltering);
		h3dSetOption( H3DOptions::TrilinearFiltering, float( trilinearFiltering ) );

		int maxAnisotropy = atoi(engineSettings.getAttribute("maxAnisotropy", "1"));
		GameLog::logMessage("MaxAnisotropy: %d", maxAnisotropy);
		h3dSetOption( H3DOptions::MaxAnisotropy, float( maxAnisotropy ) );

		bool sRGBLinearization = 
			_stricmp(engineSettings.getAttribute("sRGBLinearization", "0"), "true") == 0 ||
			_stricmp(engineSettings.getAttribute("sRGBLinearization", "0"), "1") == 0;
		GameLog::logMessage("SRGBLinearization: %s", sRGBLinearization ? "enabled" : "disabled");
		h3dSetOption( H3DOptions::SRGBLinearization, sRGBLinearization );

		bool texCompression = 
			_stricmp(engineSettings.getAttribute("texCompression", "0"), "true") == 0 ||
			_stricmp(engineSettings.getAttribute("texCompression", "0"), "1") == 0;
		GameLog::logMessage("TexCompression: %s", texCompression ? "enabled" : "disabled");
		h3dSetOption( H3DOptions::TexCompression, texCompression );

		bool loadTextures = 
			_stricmp(engineSettings.getAttribute("loadTextures", "1"), "1") == 0
			|| _stricmp(engineSettings.getAttribute("loadTextures", "1"), "true") == 0;
		GameLog::logMessage("LoadTextures: %s", loadTextures ? "enabled" : "disabled");
		h3dSetOption( H3DOptions::LoadTextures, loadTextures ? 1.0f : 0.0f );

		const XMLNode& pathes(scene.getChildNode("EnginePath"));
		if (!pathes.isEmpty())
		{
			GameLog::logMessage("AnimationPath: %s", pathes.getAttribute("animationpath", "animations"));
			h3dutSetResourcePath(H3DResTypes::Animation, pathes.getAttribute("animationpath", "animations"));
		}
		const XMLNode& engineSettings(scene.getChildNode("EngineConfig"));
		if ( !engineSettings.isEmpty() )
		{				
			bool fastAnim = 
				_stricmp(engineSettings.getAttribute("fastAnimation", "false"), "true") == 0 ||
				_stricmp(engineSettings.getAttribute("fastAnimation", "0"), "1") == 0;
			GameLog::logMessage("FastAnimation: %s", fastAnim ? "enabled" : "disabled");
			h3dSetOption( H3DOptions::FastAnimation, fastAnim ? 1.0f : 0.0f );
		}

		int shadowMapSize = atoi(engineSettings.getAttribute("shadowMapSize", "1024"));					
		GameLog::logMessage("ShadowMapSize: %d", shadowMapSize);
		h3dSetOption( H3DOptions::ShadowMapSize, float( shadowMapSize) );

		int sampleCount = atoi(engineSettings.getAttribute("sampleCount", "0"));					
		GameLog::logMessage("SampleCount: %d", sampleCount);
		h3dSetOption( H3DOptions::SampleCount, float( sampleCount) );

		bool wireframeMode = 
			_stricmp(engineSettings.getAttribute("wireframeMode", "0"), "1") == 0 ||
			_stricmp(engineSettings.getAttribute("wireframeMode", "0"), "true") == 0;
		GameLog::logMessage("WireframeMode: %s", wireframeMode ? "enabled" : "disabled");
		h3dSetOption( H3DOptions::WireframeMode, wireframeMode );

		bool debugViewMode = 
			_stricmp(engineSettings.getAttribute("debugViewMode", "0"), "1") == 0 ||
			_stricmp(engineSettings.getAttribute("debugViewMode", "0"), "true") == 0;
		GameLog::logMessage("DebugViewMode: %s", debugViewMode ? "enabled" : "disabled");
		h3dSetOption( H3DOptions::DebugViewMode, debugViewMode );

		bool dumpFailedShaders = 
			_stricmp(engineSettings.getAttribute("dumpFailedShaders", "0"), "1") == 0 ||
			_stricmp(engineSettings.getAttribute("dumpFailedShaders", "0"), "true") == 0;
		GameLog::logMessage("DumpFailedShaders: %s", dumpFailedShaders ? "enabled" : "disabled");
		h3dSetOption( H3DOptions::DumpFailedShaders, dumpFailedShaders );

		bool gatherTimeStats = 
			_stricmp(engineSettings.getAttribute("gatherTimeStats", "1"), "1") == 0 ||
			_stricmp(engineSettings.getAttribute("gatherTimeStats", "1"), "true") == 0;
		GameLog::logMessage("GatherTimeStats: %s", gatherTimeStats ? "enabled" : "disabled");
		h3dSetOption( H3DOptions::GatherTimeStats, gatherTimeStats );

	}

	const XMLNode& stereoSettings(scene.getChildNode("StereoscopyConfig"));
	if ( !stereoSettings.isEmpty() )
	{
		const char* modeC = stereoSettings.getAttribute("mode", "0");
		unsigned int mode = 0;
		if (_stricmp(modeC, "0") == 0 || _stricmp(modeC, "disabled") == 0)
			mode = 0;
		else if (_stricmp(modeC, "1") == 0 || _stricmp(modeC, "sideBySide") == 0)
			mode = 1;
		else if (_stricmp(modeC, "2") == 0 || _stricmp(modeC, "quadBuffering") == 0)
			mode = 2;
		SceneGraphManager::instance()->setStereoscopyMode(mode);

		const char* methodC = stereoSettings.getAttribute("method", "0");
		unsigned int method = 0;
		if (_stricmp(methodC, "0") == 0 || _stricmp(methodC, "toedIn") == 0)
			method = 0;
		else if (_stricmp(methodC, "1") == 0 || _stricmp(methodC, "asymmetricFrustum") == 0)
			method = 1;
		SceneGraphManager::instance()->setStereoscopyMethod(method);

		SceneGraphManager::instance()->setStereoscopyParams((float)atof(stereoSettings.getAttribute("eyeOffset", "0.05")),
			(float)atof(stereoSettings.getAttribute("strabismus", "2.5")), (float)atof(stereoSettings.getAttribute("focalLength", "1")));

		const char* stereoPipeline = stereoSettings.getAttribute("renderPipeline");
		if (stereoPipeline)
		{
			int resID = h3dAddResource( H3DResTypes::Pipeline, stereoPipeline, 0 );
			h3dutLoadResourcesFromDisk( "." );
			if (resID > 0)
				SceneGraphManager::instance()->setStereoPipelineResource(resID);
		}
		const char* stereoOverlayMaterial = stereoSettings.getAttribute("overlayMaterial");
		if (stereoOverlayMaterial)
		{
			int materialId = h3dAddResource( H3DResTypes::Material, stereoOverlayMaterial, 0 );
			h3dutLoadResourcesFromDisk( "." );
			if (materialId > 0)
				SceneGraphManager::instance()->setStereoOverlayMaterial(materialId);
		}
	}

	// Loading scene graph
	const XMLNode& sceneGraph(scene.getChildNode("SceneGraph"));
	if ( sceneGraph.isEmpty() )
		GameLog::errorMessage("No Scene Graph Node found!");
	else
	{
		GameLog::logMessage("Loading SceneGraph %s", sceneGraph.getAttribute("path"));
		// Environment
		H3DRes sceneGraphID = h3dAddResource( H3DResTypes::SceneGraph, sceneGraph.getAttribute("path"), 0 );
		GameLog::logMessage("Loading Resources...");
		// Load resources
		h3dutLoadResourcesFromDisk( "." );
		GameLog::logMessage("Adding scene graph to root node");
		// Add scene nodes	
		H3DNode newSceneID = h3dAddNodes( H3DRootNode, sceneGraphID);
		SceneGraphManager::instance()->addNewHordeNode( newSceneID );
	}
	// Use the specified render cam
	if (scene.getChildNode("ActiveCamera").getAttribute("name") && h3dFindNodes( H3DRootNode, scene.getChildNode("ActiveCamera").getAttribute("name"), H3DNodeTypes::Camera ) > 0)
		SceneGraphManager::instance()->setActiveCam( h3dGetNodeFindResult(0) );

}
コード例 #6
0
//  This function's code is from the RecastDemo project's main.cpp file by Mikko Mononen
void MyRecastDemo::guiRender()
{

	GLdouble proj[16];
	GLdouble model[16];
	GLint view[4];
	glGetDoublev(GL_PROJECTION_MATRIX, proj);
	glGetDoublev(GL_MODELVIEW_MATRIX, model);
	glGetIntegerv(GL_VIEWPORT, view);
		
	GLdouble x, y, z;
	gluUnProject(m_mouseX, m_mouseY, 0.0f, model, proj, view, &x, &y, &z);
	m_rays[0] = (float)x; m_rays[1] = (float)y; m_rays[2] = (float)z;
	gluUnProject(m_mouseX, m_mouseY, 1.0f, model, proj, view, &x, &y, &z);
	m_raye[0] = (float)x; m_raye[1] = (float)y; m_raye[2] = (float)z;


	glDisable(GL_DEPTH_TEST);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	gluOrtho2D(0, m_width, 0, m_height);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
		
	glColor4ub(255,255,255,255);
	glEnable(GL_BLEND);
	glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);

	m_mouseOverMenu = false;
		
	imguiBeginFrame( m_mouseX,m_mouseY,m_mouseBut,m_mouseScroll );
		
	const char msg[] = "W/S/A/D: move (+ shift)  |  F1: toggle recast gui  |  F2: toggle node names  |  F12: invert mouse";
	imguiDrawText(280, m_height-20, IMGUI_ALIGN_LEFT, msg, imguiRGBA(255,255,255,200));
	
		
	if (m_showMenu)
	{
		if (m_sample)
		{
			m_sample->handleRenderOverlay((double*)proj, (double*)model, (int*)view);

		}

		if (imguiBeginScrollArea("Properties", m_width-250-10, 10, 250, m_height-20, &m_propScroll))
			m_mouseOverMenu = true;

		if (imguiCheck("Show Log", m_showLog))
			m_showLog = !m_showLog;
		if (imguiCheck("Show Tools", m_showTools))
			m_showTools = !m_showTools;

		imguiSeparator();
		imguiLabel("Sample");
		if (imguiButton(m_sampleName))
		{
			if (m_showSample)
			{
				m_showSample = false;
			}
			else
			{
				m_showSample = true;
				m_showConfig = false;
			}
		}
			
		imguiSeparator();
		imguiLabel("Config File");
		if (imguiButton(m_configName))
		{
			if (m_showConfig)
			{
				m_showConfig = false;
			}
			else
			{
				m_showSample = false;
				m_showConfig = true;
				scanDirectory("Content", ".xml", m_files);
			}
		}
		if (m_geom)
		{
			char text[64];
			snprintf(text, 64, "Verts: %.1fk  Tris: %.1fk",
						m_geom->getMesh()->getVertCount()/1000.0f,
						m_geom->getMesh()->getTriCount()/1000.0f);
			imguiValue(text);
		}
		imguiSeparator();

		if (m_geom && m_sample)
		{
			imguiSeparatorLine();
				
			m_sample->handleSettings();

			if (imguiButton("Build"))
			{
				m_ctx.resetLog();
				if (!m_sample->handleBuild())
				{
					m_showLog = true;
					m_logScroll = 0;
				}
				m_ctx.dumpLog("Build log %s:", m_configName);
			}

			imguiSeparator();
		}
			
		if (m_sample)
		{
			imguiSeparatorLine();
			m_sample->handleDebugMode();
		}

		imguiEndScrollArea();
	}
	
	
	// Sample selection dialog.
	if (m_showSample)
	{
		static int levelScroll = 0;
		if (imguiBeginScrollArea("Choose Sample", m_width-10-250-10-200, m_height-10-250, 200, 250, &levelScroll))
			m_mouseOverMenu = true;

		Sample* newSample = 0;
		for (int i = 0; i < g_nsamples; ++i)
		{
			if (imguiItem(g_samples[i].name))
			{
				newSample = g_samples[i].create();
				if (newSample)
					strcpy(m_sampleName, g_samples[i].name);
			}
		}
		if (newSample)
		{
			delete m_geom;
			m_geom = 0;
			delete m_sample;
			m_sample = newSample;
			m_sample->setContext(&m_ctx);
			if (m_geom && m_sample)
			{
				m_sample->handleMeshChanged(m_geom);
			}
			else if(!m_geom)
			{
				m_geom = new InputGeom();
				m_geom->loadMesh( &m_ctx, m_configXmlFile.c_str() );
			}
			if( m_geom && m_sample )
			{
				m_sample->handleMeshChanged(m_geom);
				m_sample->handleSettings();
			}

			m_showSample = false;
		}			
		imguiEndScrollArea();
	}

	// Config selection dialog.
	if (m_showConfig)
	{
		static int levelScroll = 0;
		if (imguiBeginScrollArea("Choose Config File", m_width-10-250-10-200, m_height-10-450, 200, 450, &levelScroll))
			m_mouseOverMenu = true;
			
		int levelToLoad = -1;
		for (int i = 0; i < m_files.size; ++i)
		{
			if (imguiItem(m_files.files[i]))
				levelToLoad = i;
		}
			
		if (levelToLoad != -1)
		{
			strncpy(m_configName, m_files.files[levelToLoad], sizeof(m_configName));
			m_configName[sizeof(m_configName)-1] = '\0';
			m_showConfig = false;
				
			delete m_geom;
			m_geom = 0;
				
			char path[256];
			strcpy(path, "Content/");
			strcat(path, m_configName);
			
			m_configXmlFile = path;

			m_geom = new InputGeom();

			if( m_loadedSceneGraphRes )
			{
				// Remove previously loaded scene .
				// Every scene.xml file loaded should group its children in a GroupNode.
				int nrFoundNodes = h3dFindNodes( H3DRootNode, "", H3DNodeTypes::Group);
				for( int i = 0; i<2; ++i )
				{
					int node = h3dGetNodeFindResult(i);
					const char* name = h3dGetNodeParamStr( node, H3DNodeParams::NameStr);
					std::string camName(name);
					// Do not delete nodes directly under the root node (e.g. the demo's camera)
					if( camName.compare("RootNode") != 0) 
					{
						h3dRemoveNode( h3dGetNodeFindResult(i) );
					}
				}
				
				int a =	h3dRemoveResource( m_loadedSceneGraphRes );
				h3dReleaseUnusedResources();
			}

			if( !loadSceneFileFromConfig( path) )
			{
				m_showLog = true;
				m_logScroll = 0;
				m_ctx.log(RC_LOG_ERROR, "Error loading resources from specified scene file.");
			}

			if (!m_geom || !m_geom->loadMesh(&m_ctx, m_configXmlFile.c_str()) )
			{
				delete m_geom;
				m_geom = 0;
					
				m_showLog = true;
				m_logScroll = 0;
				m_ctx.log(RC_LOG_ERROR, "Error loading nav mesh geometry from: \"%s\"", m_configName);
				m_ctx.dumpLog("Config: Geom load log %s:", m_configName);
			}
			if (m_sample && m_geom)
			{
				m_sample->handleMeshChanged(m_geom);
			}
		}
			
		imguiEndScrollArea();
			
	}

	// Log
	if (m_showLog && m_showMenu)
	{
		if (imguiBeginScrollArea("Log", 250+20, 10, m_width - 300 - 250, 200, &m_logScroll))
			m_mouseOverMenu = true;
		for (int i = 0; i < m_ctx.getLogCount(); ++i)
			imguiLabel(m_ctx.getLogText(i));
		imguiEndScrollArea();
	}
		
	// Tools
	if (!m_showTestCases && m_showTools && m_showMenu) // && m_geom && m_sample)
	{
		if (imguiBeginScrollArea("Tools", 10, 10, 250, m_height-20, &m_toolsScroll))
			m_mouseOverMenu = true;

		if (m_sample)
			m_sample->handleTools();
			
		imguiEndScrollArea();
	}

	m_wasMouseOverMenu = m_mouseOverMenu;
	if(!m_wasMouseOverMenu)
	{
		// In case we move a GUI slider and leave the menu area
		m_mouseBut = 0;
	}
	m_mouseScroll = 0;
	
	imguiEndFrame();
	
	imguiRenderGLDraw();

	glDisable(GL_BLEND);
	glEnable(GL_DEPTH_TEST);
}
コード例 #7
0
ファイル: GazeComponent.cpp プロジェクト: dreamsxin/nawia
void GazeComponent::headShake(int axis, float extent, int count, float speed, float duration)
{
	//get head position
	h3dFindNodes( m_hID, Config::getParamS( Agent_Param::HeadName_S ), H3DNodeTypes::Joint );
	int head_hID = h3dGetNodeFindResult(0);
	if(head_hID <= 0)
		return;

	const float *head_absArray;
	h3dGetNodeTransMats( head_hID, 0, &head_absArray );
	Vec3f head_pos(head_absArray[12], head_absArray[13], head_absArray[14]);

	//check parameters
	if(count < 0) count = Config::getParamI(Agent_Param::DfltHeadShakeReps_I);
	if(extent < 0) extent = Config::getParamF(Agent_Param::DfltHeadShakeExt_F);
	if(speed < 0) speed = Config::getParamF(Agent_Param::DfltHeadShakeSpd_F);
	if(duration < 0) duration = Config::getParamF(Agent_Param::DfltHeadShakeDur_F);
	if(axis < 0 || axis > 2) axis = Config::getParamI(Agent_Param::DfltHeadShakeAxis_I);

	Vec3f deviation(0,0,0);
	switch((utils::Axis::List)axis)
	{
	case utils::Axis::X:
		deviation.x = extent;
		break;
	case utils::Axis::Y:
		deviation.y = extent;
		break;
	case utils::Axis::Z:
		deviation.z = extent;
		break;
	}	

	Vec3f p,r,s;
	Matrix4f head_absMat(head_absArray);
	head_absMat.decompose(p,r,s);
	
	Vec3f currentGaze = getGazeCoord();

	//convert current gaze to head coord sys	
	currentGaze = head_absMat.inverted() * currentGaze;

	//compute target vectors
	Vec3f targetGaze1 = currentGaze - deviation;
	Vec3f targetGaze2 = currentGaze + deviation;

	//conver them to world coord sys
	targetGaze1 = head_absMat * targetGaze1;
	targetGaze2 = head_absMat * targetGaze2;

	std::list<Gaze*> nodes;
	for(int i=0; i<count; i++)
	{
		nodes.push_back( new Gaze(this, getGazeCoord(), (i%2 == 0)? targetGaze1 : targetGaze2, (speed >= 0)? speed : m_speed, duration) );
	}
	
	//now add the new gaze nodes to the gaze stack (in reverse order ... 'cause it's a stack)
	std::list<Gaze*>::reverse_iterator riter = nodes.rbegin();
	while(riter != nodes.rend())
	{
		if((*riter)->isValid()) m_gazeNodes.push( (*riter) );
		++riter;
	}
}