Ejemplo n.º 1
0
	Degree wrapAngle(Degree angle)
	{
		if (angle.valueDegrees() < -360.0f)
			angle += Degree(360.0f);

		if (angle.valueDegrees() > 360.0f)
			angle -= Degree(360.0f);

		return angle;
	}
Ejemplo n.º 2
0
void SkyManager::update(float duration)
{
    if (!mEnabled) return;
    const MWWorld::Fallback* fallback=MWBase::Environment::get().getWorld()->getFallback();

    if (!mParticle.isNull())
    {
        for (unsigned int i=0; i<mParticle->mControllers.size(); ++i)
            mParticle->mControllers[i].update();
    }

    updateRain(duration);

    // UV Scroll the clouds
    mCloudAnimationTimer += duration * mCloudSpeed;
    sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer",
        sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mCloudAnimationTimer)));

    /// \todo improve this
    mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
    mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );

    mSecunda->setColour ( mMoonRed ? fallback->getFallbackColour("Moons_Script_Color") : ColourValue(1,1,1,1));
    mMasser->setColour (ColourValue(1,1,1,1));

    if (mSunEnabled)
    {
        // take 1/10 sec for fading the glare effect from invisible to full
        if (mGlareFade > mGlare)
        {
            mGlareFade -= duration*10;
            if (mGlareFade < mGlare) mGlareFade = mGlare;
        }
        else if (mGlareFade < mGlare)
        {
            mGlareFade += duration*10;
            if (mGlareFade > mGlare) mGlareFade = mGlare;
        }

        // increase the strength of the sun glare effect depending
        // on how directly the player is looking at the sun
        Vector3 sun = mSunGlare->getPosition();
        Vector3 cam = mCamera->getRealDirection();
        const Degree angle = sun.angleBetween( cam );
        float val = 1- (angle.valueDegrees() / 180.f);
        val = (val*val*val*val)*6;
        mSunGlare->setSize(val * mGlareFade);
    }

    mSunGlare->setVisible(mSunEnabled);
    mSun->setVisible(mSunEnabled);
    mMasser->setVisible(mMasserEnabled);
    mSecunda->setVisible(mSecundaEnabled);

    // rotate the stars by 360 degrees every 4 days
    mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f)));
}
Ejemplo n.º 3
0
void SkyManager::update(float duration)
{
    if (!mEnabled) return;

    mCamera->getParentSceneNode ()->needUpdate ();
    mRootNode->setPosition(mCamera->getDerivedPosition());

    // UV Scroll the clouds
    mCloudAnimationTimer += duration * mCloudSpeed * (MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f);
    sh::Factory::getInstance().setSharedParameter ("cloudAnimationTimer",
        sh::makeProperty<sh::FloatValue>(new sh::FloatValue(mCloudAnimationTimer)));

    /// \todo improve this
    mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
    mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );

    mSecunda->setColour ( mMoonRed ? ColourValue(1.0, 0.0784, 0.0784) : ColourValue(1,1,1,1));
    mMasser->setColour (ColourValue(1,1,1,1));

    if (mSunEnabled)
    {
        // take 1/10 sec for fading the glare effect from invisible to full
        if (mGlareFade > mGlare)
        {
            mGlareFade -= duration*10;
            if (mGlareFade < mGlare) mGlareFade = mGlare;
        }
        else if (mGlareFade < mGlare)
        {
            mGlareFade += duration*10;
            if (mGlareFade > mGlare) mGlareFade = mGlare;
        }

        // increase the strength of the sun glare effect depending
        // on how directly the player is looking at the sun
        Vector3 sun = mSunGlare->getPosition();
        sun = Vector3(sun.x, sun.z, -sun.y);
        Vector3 cam = mCamera->getRealDirection();
        const Degree angle = sun.angleBetween( cam );
        float val = 1- (angle.valueDegrees() / 180.f);
        val = (val*val*val*val)*2;

        mSunGlare->setSize(val * mGlareFade);
    }

    mSunGlare->setVisible(mSunEnabled);
    mSun->setVisible(mSunEnabled);
    mMasser->setVisible(mMasserEnabled);
    mSecunda->setVisible(mSecundaEnabled);

    // rotate the stars by 360 degrees every 4 days
    mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f)));
}
Ejemplo n.º 4
0
void SkyManager::update(float duration)
{
    if (!mEnabled) return;

    // UV Scroll the clouds
    mCloudMaterial->getTechnique(0)->getPass(0)->getFragmentProgramParameters()->setNamedConstantFromTime("time", MWBase::Environment::get().getWorld()->getTimeScaleFactor()/30.f);

    /// \todo improve this
    mMasser->setPhase( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );
    mSecunda->setPhase ( static_cast<Moon::Phase>( (int) ((mDay % 32)/4.f)) );


    if (mSunEnabled)
    {
        // take 1/5 sec for fading the glare effect from invisible to full
        if (mGlareFade > mGlare)
        {
            mGlareFade -= duration*5;
            if (mGlareFade < mGlare) mGlareFade = mGlare;
        }
        else if (mGlareFade < mGlare)
        {
            mGlareFade += duration*5;
            if (mGlareFade > mGlare) mGlareFade = mGlare;
        }

        // increase the strength of the sun glare effect depending
        // on how directly the player is looking at the sun
        Vector3 sun = mSunGlare->getPosition();
        sun = Vector3(sun.x, sun.z, -sun.y);
        Vector3 cam = mCamera->getRealDirection();
        const Degree angle = sun.angleBetween( cam );
        float val = 1- (angle.valueDegrees() / 180.f);
        val = (val*val*val*val)*2;

        mSunGlare->setSize(val * mGlareFade);
    }

    mSunGlare->setVisible(mSunEnabled);
    mSun->setVisible(mSunEnabled);
    mMasser->setVisible(mMasserEnabled);
    mSecunda->setVisible(mSecundaEnabled);

    // rotate the stars by 360 degrees every 4 days
    mAtmosphereNight->roll(Degree(MWBase::Environment::get().getWorld()->getTimeScaleFactor()*duration*360 / (3600*96.f)));
}
Ejemplo n.º 5
0
void TreeLoader2D::addTree(Entity *entity, const Vector3 &position, Degree yaw, Real scale, void* userData)
{
  //First convert the coordinate to PagedGeometry's local system
#ifdef PAGEDGEOMETRY_ALTERNATE_COORDSYSTEM
  Vector3 pos = geom->_convertToLocal(position);
#else
  Vector3 pos = position;
#endif

  //Check that the tree is within bounds (DEBUG)
#ifdef _DEBUG
  const Real smallVal = 0.01f;
  if (pos.x < actualBounds.left-smallVal || pos.x > actualBounds.right+smallVal || pos.z < actualBounds.top-smallVal || pos.z > actualBounds.bottom+smallVal)
  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Tree position is out of bounds", "TreeLoader::addTree()");
  if (scale < minimumScale || scale > maximumScale)
  OGRE_EXCEPT(Exception::ERR_INVALIDPARAMS, "Tree scale out of range", "TreeLoader::addTree()");
#endif

  //If the tree is slightly out of bounds (due to imprecise coordinate conversion), fix it
  if (pos.x < actualBounds.left)
    pos.x = actualBounds.left;
  else if (pos.x > actualBounds.right)
    pos.x = actualBounds.right;

  if (pos.z < actualBounds.top)
    pos.z = actualBounds.top;
  else if (pos.z > actualBounds.bottom)
    pos.z = actualBounds.bottom;

  Real x = pos.x;
  Real z = pos.z;

  //Find the appropriate page grid for the entity
  PageGridListIterator i;
  i = pageGridList.find(entity);

  std::vector<TreeDef> *pageGrid;
  if (i != pageGridList.end()) {
    //If it exists, get the page grid
    pageGrid = i->second;
  } else {
    //If it does not exist, create a new page grid
    pageGrid = new std::vector<TreeDef>[pageGridX * pageGridZ];

    //Register the new page grid in the pageGridList for later retrieval
    pageGridList.insert(PageGridListValue(entity, pageGrid));
  }

  //Calculate the gridbounds-relative position of the tree
  Real xrel = x - gridBounds.left;
  Real zrel = z - gridBounds.top;

  //Get the appropriate grid element based on the new tree's position
  int pageX = Math::Floor(xrel / pageSize);
  int pageZ = Math::Floor(zrel / pageSize);
  std::vector<TreeDef> &treeList = _getGridPage(pageGrid, pageX, pageZ);

  //Create the new tree
  TreeDef tree;
  tree.xPos = 65535 * (xrel - (pageX * pageSize)) / pageSize;
  tree.zPos = 65535 * (zrel - (pageZ * pageSize)) / pageSize;
  tree.rotation = 255 * (yaw.valueDegrees() / 360.0f);
  tree.scale = 255 * ((scale - minimumScale) / maximumScale);

#ifdef PAGEDGEOMETRY_USER_DATA
  tree.userData = userData;
#endif

  //Add it to the tree list
  treeList.push_back(tree);

  //Rebuild geometry if necessary
  geom->reloadGeometryPage(Vector3(x, 0, z));
}
Ejemplo n.º 6
0
void Turboprop::updateForces(float dt, int doUpdate)
{
	if (doUpdate)
	{
		//tropospheric model valid up to 11.000m (33.000ft)
		float altitude=nodes[noderef].AbsPosition.y;
		//float sea_level_temperature=273.15+15.0; //in Kelvin
		float sea_level_pressure=101325; //in Pa
		//float airtemperature=sea_level_temperature-altitude*0.0065; //in Kelvin
		float airpressure=sea_level_pressure*pow(1.0-0.0065*altitude/288.15, 5.24947); //in Pa
		airdensity=airpressure*0.0000120896;//1.225 at sea level
#ifdef USE_OPENAL
		//sound update
		SoundScriptManager::getSingleton().modulate(trucknum, mod_id, rpm);
#endif //OPENAL
	}

	timer+=dt;
	//evaluate the rotation speed
	float velacc=0;
	for (int i=0; i<numblades; i++) velacc+=(nodes[nodep[i]].Velocity-nodes[noderef].Velocity).length();
	rpm=(velacc/numblades) * RAD_PER_SEC_TO_RPM / radius;
	//check for broken prop
	Vector3 avg=Vector3::ZERO;
	for (int i=0; i<numblades; i++) avg+=nodes[nodep[i]].RelPosition;
	avg=avg/numblades;
	if ((avg-nodes[noderef].RelPosition).length()>0.4)
	{
		failed=true;
	}
	//evaluate engine power
	float enginepower=0; //in kilo-Watt
	float warmupfactor=1.0;
	if (warmup)
	{
		warmupfactor=(timer-warmupstart)/warmuptime;
		if (warmupfactor>=1.0) warmup=false;
	}
	float revpenalty=1.0;
	if (reverse) revpenalty=0.5;
	if (!failed && ignition) enginepower=(0.0575+throtle*revpenalty*0.9425)*fullpower*warmupfactor;
	//the magic formula
	float enginecouple=0.0; //in N.m
	if (rpm>10.0) enginecouple=9549.3*enginepower/rpm;
	else enginecouple=9549.3*enginepower/10.0;
	indicated_torque=enginecouple;
	
	if (torquenode!=-1)
	{
		Vector3 along=nodes[noderef].RelPosition-nodes[nodeback].RelPosition;
		Plane ppl=Plane(along, 0);
		Vector3 orth=ppl.projectVector(nodes[noderef].RelPosition)-ppl.projectVector(nodes[torquenode].RelPosition);
		Vector3 cdir=orth.crossProduct(along);
		cdir.normalise();
		nodes[torquenode].Forces+=(enginecouple/torquedist)*cdir;
	}
	
	float tipforce=(enginecouple/radius)/numblades;
	//okay, now we know the contribution from the engine

	//pitch
	if (fixed_pitch>0) pitch=fixed_pitch; else
	{
		if (!reverse)
		{
			if (throtle<0.01)
			{
				//beta range
				if (pitch>0 && rpm<regspeed*1.4) pitch-=pitchspeed*dt;
				if (rpm>regspeed*1.4) pitch+=pitchspeed*dt;
			}
			else
			{
				float dpitch=rpm-regspeed;
				if (dpitch>pitchspeed) dpitch=pitchspeed;
				if (dpitch<-pitchspeed) dpitch=-pitchspeed;
				if (!(dpitch<0 && pitch<0) && !(dpitch>0 && pitch>45)) pitch+=dpitch*dt;
			}
		} else
		{
			if (rpm<regspeed*1.1)
			{
				if (pitch<-4.0) pitch+=pitchspeed*dt;
				else pitch-=pitchspeed*dt;
			}
			if (rpm>regspeed*1.11)
			{
				pitch-=pitchspeed*dt;
			}
		}
	}
	if (!failed)
	{
		axis=nodes[noderef].RelPosition-nodes[nodeback].RelPosition;
		axis.normalise();
	}
	//estimate amount of energy
	float estrotenergy=0.5*numblades*nodes[nodep[0]].mass*radius*radius*(rpm/RAD_PER_SEC_TO_RPM)*(rpm/RAD_PER_SEC_TO_RPM);
	//for each blade
	float totthrust=0;
	float tottorque=0;
	for (int i=0; i<numblades; i++)
	{
		if (!failed && ignition)
		{
			Vector3 totaltipforce=Vector3::ZERO;
			//span vector, left to right
			Vector3 spanv=(nodes[nodep[i]].RelPosition-nodes[noderef].RelPosition);
			spanv.normalise();
			//chord vector, front to back
			Vector3 refchordv=-axis.crossProduct(spanv);
			//grab this for propulsive forces
			Vector3 tipf=-refchordv;
			totaltipforce+=(tipforce-rpm/10.0)*tipf; //add a bit of mechanical friction
			//for each blade segment (there are 6 elements)
			for (int j=0; j<5; j++) //outer to inner, the 6th blade element is ignored
			{
				//proportion
				float proport=((float)j+0.5)/6.0;
				//evaluate wind direction
				Vector3 wind=-(nodes[nodep[i]].Velocity*(1.0-proport)+nodes[noderef].Velocity*proport);
				float wspeed=wind.length();

				Vector3 liftv=spanv.crossProduct(-wind);
				liftv.normalise();
				//rotate according to pitch
				Vector3 chordv=Quaternion(Degree(pitch+twistmap[j]-7.0), spanv)*refchordv;
				//wing normal
				Vector3 normv=chordv.crossProduct(spanv);
				//calculate angle of attack
				Vector3 pwind=Plane(Vector3::ZERO, normv, chordv).projectVector(wind);
				Vector3 dumb;
				Degree daoa;
				chordv.getRotationTo(pwind).ToAngleAxis(daoa, dumb);
				float aoa=daoa.valueDegrees();
				float raoa=daoa.valueRadians();
				if (dumb.dotProduct(spanv)>0) {aoa=-aoa; raoa=-raoa;};
				//get airfoil data
				float cz, cx, cm;
				airfoil->getparams(aoa, 1.0, 0.0, &cz, &cx, &cm);
				//surface computation
				float s=radius*bladewidth/6.0;

				//drag
				//wforce=(8.0*cx+cx*cx/(3.14159*radius/0.4))*0.5*airdensity*wspeed*s*wind;
				Vector3 eforce=(4.0*cx+cx*cx/(3.14159*radius/bladewidth))*0.5*airdensity*wspeed*s*wind;
				//lift
				float lift=cz*0.5*airdensity*wspeed*wspeed*s;
				eforce+=lift*liftv;
				totthrust+=eforce.dotProduct(axis);

				//apply forces
				nodes[noderef].Forces+=eforce*proport;
				totaltipforce+=eforce*(1.0-proport);

//				if (i==0) sprintf(debug, "rend %.4i%%, wind %.3i kts, aoa %.3i, power %.5ihp, thrust %.6ilbf, torque %.6ilbft, pitch %.3i, propwash %.3i kts", (int)(100.0*wforce.dotProduct(axis)*numblades*nodes[noderef].Velocity.length()/(rpm*0.10471976*2.0*3.14159*enginecouple)), (int)(wspeed*1.9438), (int)aoa, (int)(enginepower*1.34), (int)(wforce.dotProduct(axis)*numblades*0.2248), (int)(enginecouple/1.35582), (int)pitch, (int)(propwash*1.9438));
				//			if (i==0) sprintf(debug, "lfx=%f lfy=%f lfz=%f vx=%f vy=%f vz=%f cx=%f cz=%f lift=%f", liftv.x, liftv.y, liftv.z, wind.x, wind.y, wind.z, cx, cz, lift);
			}
			tottorque+=tipf.dotProduct(totaltipforce)*radius;
			//correct amount of energy
			float correctfactor=0;
			if (rpm>100) correctfactor=(rotenergy-estrotenergy)/(numblades*radius*dt*rpm/RAD_PER_SEC_TO_RPM);
			if (correctfactor>1000.0) correctfactor=1000.0;
			if (correctfactor<-1000.0) correctfactor=-1000.0;
			nodes[nodep[i]].Forces+=totaltipforce+correctfactor*tipf;
		}
		else
		{
			//failed case
			//add drag
			Vector3 wind=-nodes[nodep[i]].Velocity;
			// determine nodes speed and divide by engines speed (with some magic numbers for tuning) to keep it rotating longer when shutoff in flight and stop after a while when plane is stopped (on the ground)
			float wspeed= (wind.length()/15.0f) / (nodes[noderef].Velocity.length()/2.0f);
			nodes[nodep[i]].Forces+=airdensity*wspeed*wind;
		}
	}
	//compute the next energy level
	rotenergy+=(double)tottorque*dt*rpm/RAD_PER_SEC_TO_RPM;
//	sprintf(debug, "pitch %i thrust %i totenergy=%i apparentenergy=%i", (int)pitch, (int)totthrust, (int)rotenergy, (int)estrotenergy);
	//prop wash
	float speed=nodes[noderef].Velocity.length();
	float thrsign=1.0;
	if (totthrust<0) {thrsign=-0.1; totthrust=-totthrust;};
	if (!failed) propwash=thrsign*sqrt(totthrust/(0.5*airdensity*proparea)+speed*speed)-speed; else propwash=0;
	if (propwash<0) propwash=0;
}
Ejemplo n.º 7
0
void FlexAirfoil::updateForces()
{
	if(!airfoil) return;
	if (broken) return;
//	if (innan) {LOG("STEP "+TOSTRING(innan)+" "+TOSTRING(nblu));innan++;}
	//evaluate wind direction
	Vector3 wind=-(nodes[nfld].Velocity+nodes[nfrd].Velocity)/2.0;
	//add wash
	int i;
	for (i=0; i<free_wash; i++)
		wind-=(0.5*washpropratio[i]*aeroengines[washpropnum[i]]->getpropwash())*aeroengines[washpropnum[i]]->getAxis();
	float wspeed=wind.length();
	//chord vector, front to back
	Vector3 chordv=((nodes[nbld].RelPosition-nodes[nfld].RelPosition)+(nodes[nbrd].RelPosition-nodes[nfrd].RelPosition))/2.0;
	float chord=chordv.length();
	//span vector, left to right
	Vector3 spanv=((nodes[nfrd].RelPosition-nodes[nfld].RelPosition)+(nodes[nbrd].RelPosition-nodes[nbld].RelPosition))/2.0;
	float span=spanv.length();
	//lift vector
//if (_isnan(spanv.x) || _isnan(spanv.y) || _isnan(spanv.z)) LOG("spanv is NaN "+TOSTRING(nblu));
//if (_isnan(wind.x) || _isnan(wind.y) || _isnan(wind.z)) LOG("wind is NaN "+TOSTRING(nblu));
	Vector3 liftv=spanv.crossProduct(-wind);
//if (_isnan(liftv.x) || _isnan(liftv.y) || _isnan(liftv.z)) LOG("liftv0 is NaN "+TOSTRING(nblu));
//if (_isnan(liftv.x) || _isnan(liftv.y) || _isnan(liftv.z)) LOG("liftv1 is NaN "+TOSTRING(nblu));

	//wing normal
	float s=span*chord;
	Vector3 normv=chordv.crossProduct(spanv);
	normv.normalise();
	//calculate angle of attack
	Vector3 pwind;
	pwind=Plane(Vector3::ZERO, normv, chordv).projectVector(-wind);
	Vector3 dumb;
	Degree daoa;
	chordv.getRotationTo(-pwind).ToAngleAxis(daoa, dumb);
	aoa=daoa.valueDegrees();
	float raoa=daoa.valueRadians();
	if (dumb.dotProduct(spanv)>0) {aoa=-aoa; raoa=-raoa;};

//if (_isnan(aoa)) LOG("aoa is NaN "+TOSTRING(nblu));
	//get airfoil data
	float cz, cx, cm;
	if (isstabilator)
		airfoil->getparams(aoa-deflection, chordratio, 0, &cz, &cx, &cm);
	else
		airfoil->getparams(aoa, chordratio, deflection, &cz, &cx, &cm);
	//compute surface
//if (_isnan(cz)) LOG("cz is NaN "+TOSTRING(nblu));
	//float fs=span*(fabs(thickness*cos(raoa))+fabs(chord*sin(raoa)));
	//float ts=span*(fabs(chord*cos(raoa))+fabs(thickness*sin(raoa)));

	//tropospheric model valid up to 11.000m (33.000ft)
	float altitude=nodes[nfld].AbsPosition.y;
	//float sea_level_temperature=273.15+15.0; //in Kelvin (not used)
	float sea_level_pressure=101325; //in Pa
	//float airtemperature=sea_level_temperature-altitude*0.0065; //in Kelvin (not used)
	float airpressure=sea_level_pressure*approx_pow(1.0-0.0065*altitude/288.15, 5.24947); //in Pa
	float airdensity=airpressure*0.0000120896;//1.225 at sea level

	Vector3 wforce=Vector3::ZERO;
	//drag
	wforce=(cx*0.5*airdensity*wspeed*s)*wind;

//if (_isnan(wforce.x) || _isnan(wforce.y) || _isnan(wforce.z)) LOG("wforce1 is NaN "+TOSTRING(nblu));
	//induced drag
	if (useInducedDrag) 
	{
		Vector3 idf=(cx*cx*0.25*airdensity*wspeed*idArea*idArea/(3.14159*idSpan*idSpan))*wind;
//if (_isnan(idf.length())) LOG("idf is NaN "+TOSTRING(nblu));

		if (idLeft)
		{
			nodes[nblu].Forces+=idf;
			nodes[nbld].Forces+=idf;
		}
		else
		{
			nodes[nbru].Forces+=idf;
			nodes[nbrd].Forces+=idf;
		}
	}

//if (_isnan(wforce.x) || _isnan(wforce.y) || _isnan(wforce.z)) LOG("wforce1a is NaN "+TOSTRING(nblu));
//if (_isnan(cz)) LOG("cz is NaN "+TOSTRING(nblu));
//if (_isnan(wspeed)) LOG("wspeed is NaN "+TOSTRING(nblu));
//if (_isnan(airdensity)) LOG("airdensity is NaN "+TOSTRING(nblu));
//if (_isnan(s)) LOG("s is NaN "+TOSTRING(nblu));
//if (_isnan(liftv.x) || _isnan(liftv.y) || _isnan(liftv.z)) LOG("liftv is NaN "+TOSTRING(nblu));
	//lift
	wforce+=(cz*0.5*airdensity*wspeed*chord)*liftv;


/*if (_isnan(wforce.x) || _isnan(wforce.y) || _isnan(wforce.z)) 
{
	if (innan==0) innan=1;
	LOG("wforce2 is NaN "+TOSTRING(nblu));
}
*/
	//moment
	float moment=-cm*0.5*airdensity*wspeed*wspeed*s;//*chord;
	//apply forces

	Vector3 f1=wforce*(liftcoef * 0.75/4.0f)+normv*(liftcoef *moment/(4.0f*0.25f));
	Vector3 f2=wforce*(liftcoef *0.25/4.0f)-normv*(liftcoef *moment/(4.0f*0.75f));

	//focal at 0.25 chord
	nodes[nfld].Forces+=f1;
	nodes[nflu].Forces+=f1;
	nodes[nfrd].Forces+=f1;
	nodes[nfru].Forces+=f1;
	nodes[nbld].Forces+=f2;
	nodes[nblu].Forces+=f2;
	nodes[nbrd].Forces+=f2;
	nodes[nbru].Forces+=f2;



//	sprintf(debug, "wind %i kts, aoa %i, cz %f, vf %f ", (int)(wspeed*1.9438), (int)aoa, cz, normv.y);

}
void LandVehicleSimulation::UpdateVehicle(Beam* curr_truck, float seconds_since_last_frame)
{
	using namespace Ogre;

	if (!curr_truck->replaymode)
	{
		if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_LEFT_MIRROR_LEFT))
			curr_truck->leftMirrorAngle-=0.001;

		if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_LEFT_MIRROR_RIGHT))
			curr_truck->leftMirrorAngle+=0.001;

		if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_RIGHT_MIRROR_LEFT))
			curr_truck->rightMirrorAngle-=0.001;

		if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_RIGHT_MIRROR_RIGHT))
			curr_truck->rightMirrorAngle+=0.001;

	} // end of (!curr_truck->replaymode) block

#ifdef USE_ANGELSCRIPT
	if (!curr_truck->replaymode && !curr_truck->vehicle_ai->IsActive())
#else
    if (!curr_truck->replaymode)
#endif // USE_ANGELSCRIPT
	{
		// steering
		float tmp_left_digital  = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_LEFT,  false, InputEngine::ET_DIGITAL);
		float tmp_right_digital = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_RIGHT, false, InputEngine::ET_DIGITAL);
		float tmp_left_analog   = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_LEFT,  false, InputEngine::ET_ANALOG);
		float tmp_right_analog  = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_STEER_RIGHT, false, InputEngine::ET_ANALOG);

		float sum = -std::max(tmp_left_digital,tmp_left_analog)+ std::max(tmp_right_digital,tmp_right_analog);

		if (sum < -1) sum = -1;
		if (sum > 1) sum = 1;

		curr_truck->hydrodircommand = sum;

		if ((tmp_left_digital < tmp_left_analog) || (tmp_right_digital < tmp_right_analog))
		{
			curr_truck->hydroSpeedCoupling = false;
		} 
		else
		{
			curr_truck->hydroSpeedCoupling = true;
		}

		if (curr_truck->engine)
		{
			static bool arcadeControls = BSETTING("ArcadeControls", false);

			float accl  = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE);
			float brake = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE);

			if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_25) ||
				RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_50))
			{
				float acclModifier = 0.0f;
				if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_25))
				{
					acclModifier += 0.25f;
				}
				if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_ACCELERATE_MODIFIER_50))
				{
					acclModifier += 0.50f;
				}
				accl *= acclModifier;
			}

			if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_25) ||
				RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_50))
			{
				float brakeModifier = 0.0f;
				if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_25))
				{
					brakeModifier += 0.25f;
				}
				if (RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_BRAKE_MODIFIER_50))
				{
					brakeModifier += 0.50f;
				}
				brake *= brakeModifier;
			}

			// arcade controls are only working with auto-clutch!
			if (!arcadeControls || curr_truck->engine->getAutoMode() > BeamEngine::SEMIAUTO)
			{
				// classic mode, realistic
				curr_truck->engine->autoSetAcc(accl);
				curr_truck->brake = brake * curr_truck->brakeforce;
			} 
			else
			{
				// start engine
				if (curr_truck->engine->hasContact() && !curr_truck->engine->isRunning() && (accl > 0 || brake > 0))
				{
					curr_truck->engine->start();
				}

				// arcade controls: hey - people wanted it x| ... <- and it's convenient
				if (curr_truck->engine->getGear() >= 0)
				{
					// neutral or drive forward, everything is as its used to be: brake is brake and accel. is accel.
					curr_truck->engine->autoSetAcc(accl);
					curr_truck->brake = brake * curr_truck->brakeforce;
				} 
				else
				{
					// reverse gear, reverse controls: brake is accel. and accel. is brake.
					curr_truck->engine->autoSetAcc(brake);
					curr_truck->brake = accl * curr_truck->brakeforce;
				}

				// only when the truck really is not moving anymore
				if (fabs(curr_truck->WheelSpeed) <= 1.0f)
				{
					Vector3 hdir = curr_truck->getDirection();
					float velocity = hdir.dotProduct(curr_truck->nodes[0].Velocity);

					// switching point, does the user want to drive forward from backward or the other way round? change gears?
					if (velocity < 1.0f && brake > 0.5f && accl < 0.5f && curr_truck->engine->getGear() > 0)
					{
						// we are on the brake, jump to reverse gear
						if (curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC)
						{
							curr_truck->engine->autoShiftSet(BeamEngine::REAR);
						} 
						else
						{
							curr_truck->engine->setGear(-1);
						}
					} else if (velocity > -1.0f && brake < 0.5f && accl > 0.5f && curr_truck->engine->getGear() < 0)
					{
						// we are on the gas pedal, jump to first gear when we were in rear gear
						if (curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC)
						{									
							curr_truck->engine->autoShiftSet(BeamEngine::DRIVE);
						} 
						else
						{
							curr_truck->engine->setGear(1);
						}
					}
				}
			}

			// IMI
			// gear management -- it might, should be transferred to a standalone function of Beam or RoRFrameListener
			if (curr_truck->engine->getAutoMode() == BeamEngine::AUTOMATIC)
			{
				if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_AUTOSHIFT_UP))
				{
					curr_truck->engine->autoShiftUp();
				}
				if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_AUTOSHIFT_DOWN))
				{
					curr_truck->engine->autoShiftDown();
				}
			}

			if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_TOGGLE_CONTACT))
			{
				curr_truck->engine->toggleContact();
			}

			if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_STARTER) && curr_truck->engine->hasContact() && !curr_truck->engine->isRunning())
			{
				// starter
				curr_truck->engine->setstarter(1);
#ifdef USE_OPENAL
				SoundScriptManager::getSingleton().trigStart(curr_truck, SS_TRIG_STARTER);
#endif // OPENAL
			} 
			else
			{
				curr_truck->engine->setstarter(0);
#ifdef USE_OPENAL
				SoundScriptManager::getSingleton().trigStop(curr_truck, SS_TRIG_STARTER);
#endif // OPENAL
			}

			if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SWITCH_SHIFT_MODES))
			{
				// toggle Auto shift
				curr_truck->engine->toggleAutoMode();

				// force gui update
				curr_truck->triggerGUIFeaturesChanged();
#ifdef USE_MYGUI
				switch(curr_truck->engine->getAutoMode())
				{
					case BeamEngine::AUTOMATIC:
						RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Automatic shift"), "cog.png", 3000);
						RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Automatic shift");
						break;
					case BeamEngine::SEMIAUTO:
						RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Manual shift - Auto clutch"), "cog.png", 3000);
						RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Manual shift - Auto clutch");
						break;
					case BeamEngine::MANUAL:
						RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Fully Manual: sequential shift"), "cog.png", 3000);
						RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Fully Manual: sequential shift");
						break;
					case BeamEngine::MANUAL_STICK:
						RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Fully manual: stick shift"), "cog.png", 3000);
						RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Fully manual: stick shift");
						break;
					case BeamEngine::MANUAL_RANGES:
						RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Fully Manual: stick shift with ranges"), "cog.png", 3000);
						RoR::Application::GetGuiManager()->PushNotification("Gearbox Mode:", "Fully Manual: stick shift with ranges");
						break;
				}
#endif //USE_MYGUI
			}

			// joy clutch
			float cval = RoR::Application::GetInputEngine()->getEventValue(EV_TRUCK_MANUAL_CLUTCH);
			curr_truck->engine->setManualClutch(cval);

			int shiftmode = curr_truck->engine->getAutoMode();

			if (shiftmode <= BeamEngine::MANUAL) // auto, semi auto and sequential shifting
			{
				if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_UP))
				{
						curr_truck->engine->shift(1);
				} 
				else if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_DOWN))
				{
					if (shiftmode  > BeamEngine::SEMIAUTO ||
						shiftmode == BeamEngine::SEMIAUTO  && !arcadeControls ||
						shiftmode == BeamEngine::SEMIAUTO  && curr_truck->engine->getGear() > 0 ||
						shiftmode == BeamEngine::AUTOMATIC)
					{
						curr_truck->engine->shift(-1);
					}
				} 
				else if (shiftmode != BeamEngine::AUTOMATIC && RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_NEUTRAL))
				{
					curr_truck->engine->shiftTo(0);
				}
			} 
			else //if (shiftmode > BeamEngine::MANUAL) // h-shift or h-shift with ranges shifting
			{
				bool gear_changed = false;
				bool found        = false;
				int curgear       = curr_truck->engine->getGear();
				int curgearrange    = curr_truck->engine->getGearRange();
				int gearoffset      = std::max(0, curgear - curgearrange * 6);

				// one can select range only if in neutral
				if (shiftmode==BeamEngine::MANUAL_RANGES && curgear == 0)
				{
					//  maybe this should not be here, but should experiment
					if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_LOWRANGE) && curgearrange != 0)
					{
						curr_truck->engine->setGearRange(0);
						gear_changed = true;
#ifdef USE_MYGUI
						RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Low range selected"), "cog.png", 3000);
#endif //USE_MYGUI
					} 
					else if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_MIDRANGE)  && curgearrange != 1 && curr_truck->engine->getNumGearsRanges()>1)
					{
						curr_truck->engine->setGearRange(1);
						gear_changed = true;
#ifdef USE_MYGUI
						RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Mid range selected"), "cog.png", 3000);
#endif //USE_MYGUI
					} 
					else if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_SHIFT_HIGHRANGE) && curgearrange != 2 && curr_truck->engine->getNumGearsRanges()>2)
					{
						curr_truck->engine->setGearRange(2);
						gear_changed = true;
#ifdef USE_MYGUI
						RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("High range selected"), "cog.png", 3000);
#endif // USE_MYGUI
					}
				}
//zaxxon
				if (curgear == -1)
				{
					gear_changed = !RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR_REVERSE);
				} 
				else if (curgear > 0 && curgear < 19)
				{
					if (shiftmode==BeamEngine::MANUAL)
					{
						gear_changed = !RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + curgear -1);
					} else
					{
						gear_changed = !RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + gearoffset-1); // range mode
					}
				}

				if (gear_changed || curgear == 0)
				{
					if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR_REVERSE))
					{
						curr_truck->engine->shiftTo(-1);
						found = true;
					} 
					else if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_NEUTRAL))
					{
						curr_truck->engine->shiftTo(0);
						found = true;
					} 
					else
					{
						if (shiftmode == BeamEngine::MANUAL_STICK)
						{
							for (int i=1; i < 19 && !found; i++)
							{
								if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + i - 1))
								{
									curr_truck->engine->shiftTo(i);
									found = true;
								}
							}
						} 
						else // BeamEngine::MANUALMANUAL_RANGES
						{
							for (int i=1; i < 7 && !found; i++)
							{
								if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_SHIFT_GEAR01 + i - 1))
								{
									curr_truck->engine->shiftTo(i + curgearrange * 6);
									found = true;
								}
							}
						}
					}
					if (!found)
					{
						curr_truck->engine->shiftTo(0);
					}
				} // end of if (gear_changed)
			} // end of shitmode > BeamEngine::MANUAL

			if (curr_truck->engine->hasContact() &&
				curr_truck->engine->getAutoMode()  == BeamEngine::AUTOMATIC &&
				curr_truck->engine->getAutoShift() != BeamEngine::NEUTRAL &&
				std::abs(curr_truck->WheelSpeed) < 0.1f)
			{
				Vector3 dirDiff = curr_truck->getDirection();
				Degree pitchAngle = Radian(asin(dirDiff.dotProduct(Vector3::UNIT_Y)));

				if (std::abs(pitchAngle.valueDegrees()) > 1.0f)
				{
					if (curr_truck->engine->getAutoShift() > BeamEngine::NEUTRAL && curr_truck->WheelSpeed < +0.1f && pitchAngle.valueDegrees() > +1.0f ||
					    curr_truck->engine->getAutoShift() < BeamEngine::NEUTRAL && curr_truck->WheelSpeed > -0.1f && pitchAngle.valueDegrees() < -1.0f)
					{
						// anti roll back in BeamEngine::AUTOMATIC (DRIVE, TWO, ONE) mode
						// anti roll forth in BeamEngine::AUTOMATIC (REAR) mode
						float downhill_force = std::abs(sin(pitchAngle.valueRadians()) * curr_truck->getTotalMass());
						float engine_force = std::abs(curr_truck->engine->getTorque());
						float ratio = std::max(0.0f, 1.0f - (engine_force / downhill_force) / 2.0f);
						curr_truck->brake = curr_truck->brakeforce * sqrt(ratio);
					}
				} else if (brake == 0.0f && accl == 0.0f && curr_truck->parkingbrake == 0)
				{
					float ratio = std::max(0.0f, 0.1f - std::abs(curr_truck->WheelSpeed)) * 5.0f;
					curr_truck->brake = curr_truck->brakeforce * ratio;
				}
			}
		} // end of ->engine
#ifdef USE_OPENAL
		if (curr_truck->brake > curr_truck->brakeforce / 6.0f)
		{
			SoundScriptManager::getSingleton().trigStart(curr_truck, SS_TRIG_BRAKE);
		} 
		else
		{
			SoundScriptManager::getSingleton().trigStop(curr_truck, SS_TRIG_BRAKE);
		}
#endif // USE_OPENAL
	} // end of ->replaymode

	if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_TOGGLE_AXLE_LOCK))
	{
		// toggle auto shift
		if (!curr_truck->getAxleLockCount())
		{
#ifdef USE_MYGUI
			RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("No differential installed on current vehicle!"), "warning.png", 3000);
			RoR::Application::GetGuiManager()->PushNotification("Differential:", "No differential installed on current vehicle!");
#endif // USE_MYGUI
		} 
		else
		{
			curr_truck->toggleAxleLock();
#ifdef USE_MYGUI
			RoR::Application::GetConsole()->putMessage(Console::CONSOLE_MSGTYPE_INFO, Console::CONSOLE_SYSTEM_NOTICE, _L("Differentials switched to: ") + curr_truck->getAxleLockName(), "cog.png", 3000);
			RoR::Application::GetGuiManager()->PushNotification("Differential:", "Differentials switched to: " + curr_truck->getAxleLockName());
#endif // USE_MYGUI
		}
	}

#ifdef USE_OPENAL
	if (curr_truck->ispolice)
	{
		if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_HORN))
		{
			SoundScriptManager::getSingleton().trigToggle(curr_truck, SS_TRIG_HORN);
		}
	} 
	else
	{
		if (RoR::Application::GetInputEngine()->getEventBoolValue(EV_TRUCK_HORN) && !curr_truck->replaymode)
		{
			SoundScriptManager::getSingleton().trigStart(curr_truck, SS_TRIG_HORN);
		} else
		{
			SoundScriptManager::getSingleton().trigStop(curr_truck, SS_TRIG_HORN);
		}
	}
#endif // OPENAL

	if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_PARKING_BRAKE))
	{
		curr_truck->parkingbrakeToggle();
	}

	if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_ANTILOCK_BRAKE))
	{
		if (curr_truck->alb_present && !curr_truck->alb_notoggle)
		{
			curr_truck->antilockbrakeToggle();
		}
	}

	if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_TRACTION_CONTROL))
	{
		if (!curr_truck->tc_notoggle) curr_truck->tractioncontrolToggle();
	}

	if (RoR::Application::GetInputEngine()->getEventBoolValueBounce(EV_TRUCK_CRUISE_CONTROL))
	{
		curr_truck->cruisecontrolToggle();
	}
	if (curr_truck->cc_mode)
	{
		LandVehicleSimulation::UpdateCruiseControl(curr_truck, seconds_since_last_frame);
	}
	LandVehicleSimulation::CheckSpeedLimit(curr_truck, seconds_since_last_frame);
}
tAction TeacherFollowTheLineLineRoom::computeNextAction()
{
    // Determine if a change of state is possible
    if (state == STATE_FORWARD_1)
    {
        if (target.x < 0)
        {
            target.x = m_pMap->properties.get("spot1_x")->toInt();
            target.y = m_pMap->properties.get("spot1_y")->toInt();
        }
        else
        {
            if ((m_robot_position.x >= target.x - 1) && (m_robot_position.x <= target.x + 1) &&
                (m_robot_position.y >= target.y - 1) && (m_robot_position.y <= target.y + 1))
            {
                target.x = m_pMap->properties.get("spot2_x")->toInt();
                target.y = m_pMap->properties.get("spot2_y")->toInt();

                state = STATE_FORWARD_2;
            }
        }
    }
    else if (state == STATE_FORWARD_2)
    {
        if ((m_robot_position.x >= target.x - 1) && (m_robot_position.x <= target.x + 1) &&
            (m_robot_position.y >= target.y - 1) && (m_robot_position.y <= target.y + 1))
        {
            target.x = -1;
            target.y = -1;

            state = STATE_LOOK_FOR_FLAG;
        }
    }
    else if (state == STATE_LOOK_FOR_FLAG)
    {
        if (!m_detected_targets.empty())
        {
            target = m_detected_targets[0];
            state = STATE_GO_TOWARD_FLAG;
        }
    }

    // Select the action to perform
    if (state == STATE_LOOK_FOR_FLAG)
    {
        if (m_pMap->properties.get("haxis")->toBool())
            return ACTION_TURN_RIGHT;
        else
            return ACTION_TURN_LEFT;
    }
    else if (target.x >= 0)
    {
        Degree angle = getAngleToTarget(target);

        if (angle.valueDegrees() >= 3.0f)
            return ACTION_TURN_RIGHT;
        else if (angle.valueDegrees() <= -3.0f)
            return ACTION_TURN_LEFT;
        else
            return ACTION_GO_FORWARD;
    }

    return ACTION_TURN_LEFT;
}
Ejemplo n.º 10
0
	String toString(Degree val, unsigned short precision, 
		unsigned short width, char fill, std::ios::fmtflags flags)
	{
		return toString(val.valueDegrees(), precision, width, fill, flags);
	}
Ejemplo n.º 11
0
    void SGModel::updateBone(int64_t time, ObjectPtr skeleton)
    {
        BonePtr bone = smart_pointer_cast<Bone>(skeleton);

        ActionDataPtr actionData = smart_pointer_cast<ActionData>(mCurActionData);
        
        KeyFrameDataPtr kf1, kf2;

        // 平移变换数据
        Vector3 translation;
        auto itrT = actionData->mBonesTranslation.find(bone->getName());
        if (itrT != actionData->mBonesTranslation.end())
        {
            ActionData::KeyFrames &keyframesT = itrT->second;

            if (searchKeyframe(keyframesT, time, actionData->mDuration, mCurKeyFrameT, kf1, kf2, mIsLoop))
            {
                KeyFrameDataTPtr keyframe1 = smart_pointer_cast<KeyFrameDataT>(kf1);
                KeyFrameDataTPtr keyframe2 = smart_pointer_cast<KeyFrameDataT>(kf2);
                double t = double(time - keyframe1->mTimestamp) / double(keyframe2->mTimestamp - keyframe1->mTimestamp);
                Vector3 &base = keyframe1->mTranslation;
                translation = (base + (keyframe2->mTranslation - base) * t);
                T3D_LOG_INFO("Keyframe #1 T(%f, %f, %f)", keyframe1->mTranslation[0], keyframe1->mTranslation[1], keyframe1->mTranslation[2]);
                T3D_LOG_INFO("Keyframe #2 T(%f, %f, %f)", keyframe2->mTranslation[0], keyframe2->mTranslation[1], keyframe2->mTranslation[2]);
                T3D_LOG_INFO("Bone : %s [%f], T(%f, %f, %f)", bone->getName().c_str(), t, translation[0], translation[1], translation[2]);

                bone->setTranslation(translation);
            }
        }
        
        // 旋转变换数据
        Quaternion orientation;
        auto itrR = actionData->mBonesRotation.find(bone->getName());
        if (itrR != actionData->mBonesRotation.end())
        {
            ActionData::KeyFrames &keyframesR = itrR->second;

            if (searchKeyframe(keyframesR, time, actionData->mDuration, mCurKeyFrameR, kf1, kf2, mIsLoop))
            {
                KeyFrameDataRPtr keyframe1 = smart_pointer_cast<KeyFrameDataR>(kf1);
                KeyFrameDataRPtr keyframe2 = smart_pointer_cast<KeyFrameDataR>(kf2);
                double t = double(time - keyframe1->mTimestamp) / double(keyframe2->mTimestamp - keyframe1->mTimestamp);
                orientation.lerp(keyframe1->mOrientation, keyframe2->mOrientation, t/* / 1000*/);
                T3D_LOG_INFO("Keyframe #1 R(%f, %f, %f, %f)", keyframe1->mOrientation[0], keyframe1->mOrientation[1], keyframe1->mOrientation[2], keyframe1->mOrientation[3]);
                T3D_LOG_INFO("Keyframe #2 R(%f, %f, %f, %f)", keyframe2->mOrientation[0], keyframe2->mOrientation[1], keyframe2->mOrientation[2], keyframe2->mOrientation[3]);
                Degree deg;
                Vector3 axis;
                orientation.toAngleAxis(deg, axis);
                T3D_LOG_INFO("Bone : %s [%d], R(%f, %f, %f, %f), deg=%f, Axis(%f, %f, %f)", bone->getName().c_str(), time, orientation[0], orientation[1], orientation[2], orientation[3], deg.valueDegrees(), axis[0], axis[1], axis[2]);

                bone->setOrientation(orientation);
            }
        }

        // 缩放变换数据
        Vector3 scaling;
        auto itrS = actionData->mBonesScaling.find(bone->getName());
        if (itrS != actionData->mBonesScaling.end())
        {
            ActionData::KeyFrames &keyframesS = itrS->second;

            if (searchKeyframe(keyframesS, time, actionData->mDuration, mCurKeyFrameS, kf1, kf2, mIsLoop))
            {
                KeyFrameDataSPtr keyframe1 = smart_pointer_cast<KeyFrameDataS>(kf1);
                KeyFrameDataSPtr keyframe2 = smart_pointer_cast<KeyFrameDataS>(kf2);
                double t = double(time - keyframe1->mTimestamp) / double(keyframe2->mTimestamp - keyframe1->mTimestamp);
                Vector3 &base = keyframe1->mScaling;
                scaling = (base * (keyframe2->mScaling - base) * t);
                T3D_LOG_INFO("Keyframe #1 S(%f, %f, %f)", keyframe1->mScaling[0], keyframe1->mScaling[1], keyframe1->mScaling[2]);
                T3D_LOG_INFO("Keyframe #2 S(%f, %f, %f)", keyframe2->mScaling[0], keyframe2->mScaling[1], keyframe2->mScaling[2]);
                T3D_LOG_INFO("Bone : %s [%f], S(%f, %f, %f)", bone->getName().c_str(), t, scaling[0], scaling[1], scaling[2]);

                bone->setScaling(scaling);
            }
        }

        bone->updateBone();

        auto itr = bone->getChildren().begin();
        while (itr != bone->getChildren().end())
        {
            updateBone(time, *itr);
            ++itr;
        }
    }
    bool StepRecognitionMovement::run(Ogre::Real elapsedTime,  Ogre::Vector3 direction, Ogre::Vector3 rotation)
    {
        Vector3 vel = mMovingCreature->getCreature()->getActor()->getPhysicalThing()->getVelocity();
        Real velY = vel.y;
        vel.y = 0;
        // raycast in the direction we should move to
        Vector3 globalDir = mMovingCreature->getCreature()->getOrientation() * direction; // the direction in global space
        if( globalDir == Vector3::ZERO )
            return true;



        // the materials that are triggered here
        PhysicsMaterialRaycast::MaterialVector materialVector;
        materialVector.push_back(PhysicsManager::getSingleton().getMaterialID("character")); // should we perhaps only use level here?
        materialVector.push_back(PhysicsManager::getSingleton().getMaterialID("camera"));



        // first of all check if we are not standing in front of a wall or sth like this
        PhysicalThing *thing = mMovingCreature->getCreature()->getActor()->getPhysicalThing();
        Real height = thing->_getBody()->getCollision()->getAABB().getSize().y;
        Vector3 start = mMovingCreature->getCreature()->getPosition() + Vector3(0,height/2,0);
        Vector3 end = start + globalDir * 0.5;
        RaycastInfo info;
        info = mRaycast.execute(
                PhysicsManager::getSingleton()._getNewtonWorld(),
                &materialVector,
                start,
                end,
                true);
        if(info.mBody)
        {
            mMoveToNextTarget = false;
            return false;
        }



        if( !mMoveToNextTarget ) // check if we need to move up for a step
        {
            Real raylen = vel.length() / 3;  // use longer ray, if higher velocity
            if ( raylen < 0.5 )
                raylen = 0.4;

            //std::ostringstream oss;
            //oss << "StepRecognition Raylen: " << raylen;
            //LOG_MESSAGE(Logger::RULES, oss.str());


            // raycasts
            Vector3 start = mMovingCreature->getCreature()->getPosition() + Vector3::UNIT_Y * 0.1f;
            globalDir.y = 0;
            globalDir.normalise();
            Vector3 end = start + globalDir*raylen;

            bool foundbody = false;
            Real foundDistance = 0;

            RaycastInfo info;
            do
            {
                info = 
                    mRaycast.execute(
                            PhysicsManager::getSingleton()._getNewtonWorld(),
                            &materialVector,
                            start, end, true);

                // do we need to check bodies left and right of this ray? (step width?)


                // already found nearer body
                if( foundbody )
                {
                    if( info.mBody && (info.mDistance*raylen >= foundDistance*raylen + 0.19) || // step deep enough
                            !info.mBody )
                    {
                        // found a step
                        mMoveToNextTarget = true;
                        mNextTarget = start + globalDir*raylen*foundDistance + 0.1 * globalDir;
                        std::ostringstream oss;
                        Vector3 stepInLocalCoords = mNextTarget - mMovingCreature->getCreature()->getPosition();
                        Quaternion ori = mMovingCreature->getCreature()->getOrientation();
                        stepInLocalCoords = ori.Inverse() * stepInLocalCoords;
                        oss << "Step-Recognition: Next Step: " << stepInLocalCoords;
                        LOG_MESSAGE(Logger::RULES, oss.str());
                        break;
                    }
                }

                if( info.mBody )
                {
                    foundbody = true;
                    foundDistance = info.mDistance;
                }


                start += Vector3::UNIT_Y * 0.05f;
                end += Vector3::UNIT_Y * 0.05f;
            }
            while( info.mBody && (start - mMovingCreature->getCreature()->getPosition()).y <= 0.5 );
        }


        // check if the target is still needed
        // perform check also to verify found step
        if( mMoveToNextTarget )
        {
            Vector3 diffToTarget = mNextTarget - mMovingCreature->getCreature()->getPosition();
            Real diffToTargetY = diffToTarget.y;
            diffToTarget.y = 0;

            // different direction
            Vector3 globalDir = mMovingCreature->getCreature()->getOrientation() * direction; // the direction in global space
            globalDir.y = 0;


            if( globalDir == Vector3::ZERO )
            {
                mMoveToNextTarget = false;
                LOG_MESSAGE(Logger::RULES, "Testing Step-Recognition: Step direction null");
                return false;
            }

            // target reached
            if( diffToTarget.squaredLength() < 0.01)
            {
                mMoveToNextTarget = false;
                LOG_MESSAGE(Logger::RULES, "Testing Step-Recognition: Step reached");
                return false;
            }

            // different direction
            Quaternion oriDiff = diffToTarget.getRotationTo(globalDir, Vector3::UNIT_Y);
            Degree angleDiff;
            Vector3 axis = Vector3::UNIT_Y;
            oriDiff.ToAngleAxis(angleDiff, axis);
            Real f = angleDiff.valueDegrees();
            //std::ostringstream oss;
            //oss << "Step-Recognition: angle: " << f << "    axis: " << axis;
            //LOG_MESSAGE(Logger::RULES, oss.str());
            //if( !diffToTarget.directionEquals(globalDir, Degree(15)) )
            if( f > 2.0f )
            {
                mMoveToNextTarget = false;
                //LOG_MESSAGE(Logger::RULES, "Testing Step-Recognition: Step direction wrong");
                return false;
            }


            // already above target, but slow velocity
            if( diffToTargetY < 0 && fabs(velY) < 0.01 )
            {
                mMoveToNextTarget = false;
                //LOG_MESSAGE(Logger::RULES, "Testing Step-Recognition: slow and abov target-height!");
                return false;
            }
        }

        return mMoveToNextTarget;
    }