Example #1
0
bool CCameraTracking::Update(SViewParams &viewParams, float &fHOffObstacleStrength, const SCamModeSettings &camMode, const CPlayer &hero, bool bObstacleFound /* = false */)
{
	if(!g_pGameCVars->cl_cam_tracking || !m_pCamRayScan)
		return false;

	m_fFrameTime = max(g_fCamError, gEnv->pTimer->GetFrameTime());

	//in combat mode this function doesn't really avoid obstacles, it avoids clipping
	float fCombatModeWeight = 5.0f;

	//default angle and minimum
	const float fNow = gEnv->pTimer->GetFrameStartTime().GetSeconds();

	CCameraInputHelper *pCamHelper = hero.GetCameraInputHelper();
	CRY_ASSERT(pCamHelper);
	float fLastUserInput = pCamHelper->GetLastUserInputTime();

	//user input overrides auto-follow
	if(fNow - fLastUserInput < 0.5f)
		return false;

	bool bTrackingActive = camMode.camType == ECT_CamFollow && (camMode.collisionType == ECCT_CollisionTrack || camMode.collisionType == ECCT_CollisionTrackOrCut);

	//get current values
	Vec3 curCamDir = viewParams.position-viewParams.targetPos;
	m_curCamOrientation.Set(0.0f, 0.0f, 0.0f);
	CartesianToSpherical(curCamDir, m_curCamOrientation);
	curCamDir.Normalize();

	if(m_curCamOrientation.m_fDist < g_pGameCVars->cl_cam_min_distance)
		m_curCamOrientation.m_fDist = g_pGameCVars->cl_cam_min_distance;

	//work in 0 .. 2PI
	m_curCamOrientation.m_fYaw += gf_PI;

	//if there is something in the way
	if(bObstacleFound)
	{
		//re-start fadeout
		m_fTimeCovered = 0.5f;
		//set last obstacle pos
		m_vLastObstaclePos = viewParams.position;

		//scan obstacle
		if(!IdentifyObstacle(curCamDir, hero))
			return false;
	}
	else if(fabsf(m_fYawDelta) > g_fCamError || fabsf(m_fPitchDelta) > g_fCamError)
	{
		//if there is nothing in the way, fade out the movement

		//time based fade
		if(m_fTimeCovered > 0)
		{
			m_fTimeCovered = max(m_fTimeCovered - m_fFrameTime, 0.0f);

			//these interpolators should be time and not frame based
			m_fYawDelta = (g_fInterpolationRate * m_fYawDelta) * g_fInterpolationWeight;
			m_fPitchDelta = (g_fInterpolationRate * m_fPitchDelta) * g_fInterpolationWeight;
			m_fSpeed = (g_fInterpolationRate * m_fSpeed) * g_fInterpolationWeight;
		}
		else
		{
			m_fYawDelta = 0.0f;
			m_fPitchDelta = 0.0f;
			m_fSpeed = 0.0f;
		}
	}

	//apply delta rotation for obstacle avoidance
	if(fabsf(m_fYawDelta) > g_fCamError || fabsf(m_fPitchDelta) > g_fCamError)
	{
		if(bTrackingActive)
		{
			//set new yaw
			float newYaw = m_curCamOrientation.m_fYaw + m_fYawDelta;
			//re-align yaw
			//the camera direction is 90 degrees off and flipped compared to entity space
			newYaw = (newYaw - gf_PI * 0.5f) * -1.0f;
			//set new pitch
			float newPitch = m_curCamOrientation.m_fPitch + m_fPitchDelta;

			if(g_pGameCVars->cl_cam_orbit != 0)
			{
				//pCamHelper->SetTrackingDelta(-m_fYawDelta, m_fPitchDelta);
				pCamHelper->SetYawDelta(-m_fYawDelta);
				pCamHelper->SetPitchDelta(m_fPitchDelta);
			}
			else
			{
				//apply yaw/pitch on camera
				//pCamHelper->SetInterpolationTarget(newYaw, newPitch, gf_PI, 0.1f, 0.0f);
				//this will always reset follow cam interpolation
				pCamHelper->SetYawDelta(m_fYawDelta);
				pCamHelper->SetPitchDelta(m_fPitchDelta);
			}
		}
		else
		{
			//in orbit mode we basically simulate user input
			//pCamHelper->SetTrackingDelta(-fCombatModeWeight*g_fYawDelta, fCombatModeWeight*g_fPitchDelta);

			//in cutting mode we offset the camera to avoid clipping
			float offsetStrength = 0.0f;
			float offsetSpeed = 2.0f;

			if(bObstacleFound)
			{
				offsetStrength = (m_fYawDelta < 0.0f)?-g_fOffsetTrackingDistance:g_fOffsetTrackingDistance;
				offsetSpeed = 0.5f;
			}

			fHOffObstacleStrength = InterpolateTo(fHOffObstacleStrength, offsetStrength, offsetSpeed);
		}

		//CryLogAlways("new yaw %f, yawDelta %f", newYaw, g_yawDelta);
		return true;
	}
	else
		UpdateAutoFollow(viewParams, hero);

	return false;
}
Example #2
0
 bool IntersectLineLine(const Vec3<double> & p1, const Vec3<double> & p2, 
                       const Vec3<double> & p3, const Vec3<double> & p4,
                       Vec3<double> & pa, Vec3<double> & pb, 
                       double & mua, double & mub)
 {
     Vec3<double> p13,p43,p21;
     double d1343,d4321,d1321,d4343,d2121;
     double numer,denom;
     
     p13.X() = p1.X() - p3.X();
     p13.Y() = p1.Y() - p3.Y();
     p13.Z() = p1.Z() - p3.Z();
     p43.X() = p4.X() - p3.X();
     p43.Y() = p4.Y() - p3.Y();
     p43.Z() = p4.Z() - p3.Z();
     if (p43.X()==0.0 && p43.Y()==0.0 && p43.Z()==0.0)
         return false;
     p21.X() = p2.X() - p1.X();
     p21.Y() = p2.Y() - p1.Y();
     p21.Z() = p2.Z() - p1.Z();
     if (p21.X()==0.0 && p21.Y()==0.0 && p21.Z()==0.0)
         return false;
     
     d1343 = p13.X() * p43.X() + p13.Y() * p43.Y() + p13.Z() * p43.Z();
     d4321 = p43.X() * p21.X() + p43.Y() * p21.Y() + p43.Z() * p21.Z();
     d1321 = p13.X() * p21.X() + p13.Y() * p21.Y() + p13.Z() * p21.Z();
     d4343 = p43.X() * p43.X() + p43.Y() * p43.Y() + p43.Z() * p43.Z();
     d2121 = p21.X() * p21.X() + p21.Y() * p21.Y() + p21.Z() * p21.Z();
     
     denom = d2121 * d4343 - d4321 * d4321;
     if (denom==0.0)
         return false;
     numer = d1343 * d4321 - d1321 * d4343;
     
     mua = numer / denom;
     mub = (d1343 + d4321 * (mua)) / d4343;
     
     pa.X() = p1.X() + mua * p21.X();
     pa.Y() = p1.Y() + mua * p21.Y();
     pa.Z() = p1.Z() + mua * p21.Z();
     pb.X() = p3.X() + mub * p43.X();
     pb.Y() = p3.Y() + mub * p43.Y();
     pb.Z() = p3.Z() + mub * p43.Z();
     
     return true;
 }
Example #3
0
Vec4 RayTracer::traceLights(const Vec3& intersection, Drawable *drawable, Vec3 eye )
{
    Vec4 out_color;
    Vec4 spec_color;
    Vec4 diffuse_color =  drawable->getColorAt(intersection);
    float factor_ambient = drawable->getMaterial().getAmbientFactor();
    LightVector::iterator light = _scene->getLights().begin();
    while (light != _scene->getLights().end()) {
        //Vec3 light_direction = intersection - (*light)->getPosition();
        Vec3 light_direction = (*light)->getPosition() - intersection;
        float lightdist = light_direction.length();
        light_direction.normalize();

        Ray ray(intersection, light_direction);
        float light_scaling = drawable->getNormalAt(intersection) * light_direction;  // no effect if light ray and object normal are orthogonal
        if (light_scaling < 0) 
            light_scaling = 0.0f;

        // check for shadows
        DrawableVector::iterator object = _scene->getDrawables().begin();
        Drawable *hitobject = 0;
        while (object != _scene->getDrawables().end()) {
            float tmp;
            Vec3 tmp_intersection;
            // nothing to do if current object is the drawable
            if ( ((*object) != drawable) && (*object)->intersect(ray, tmp_intersection, tmp) ) {
                // object is between drawable and current light
                Vec3 intersection_vec = tmp_intersection - (*light)->getPosition();
                float dist = intersection_vec.length();
                if ( dist < lightdist) {
                    hitobject = *object;
                    break;
                }

            }
            object++;
        }

        // do specular component
        if ( !hitobject ) {
            switch ((*light)->getType()) {
                case Light::DIRECTIONAL:
                    out_color += (*light)->getColor() * (*light)->getIntensity();
                    out_color += (*light)->getAmbientColor() * factor_ambient;
                    break;
                case Light::POINT:
                    {
                    out_color += (*light)->getColor() * (*light)->getIntensity() * light_scaling * 1.0f/(lightdist);
                    Vec3 half =  light_direction - eye;
                    half.normalize();
                    Vec3 normal = drawable->getNormalAt(intersection);
                    normal.normalize();
                    float shine = 16.0f;
                    float temp = MAX(0.0, normal * half);
                    float spec_val = pow(temp, shine);
                    spec_color += (*light)->getColor() * (*light)->getIntensity() * spec_val * drawable->getMaterial().getReflectionFactor();
                    out_color += (*light)->getAmbientColor() * factor_ambient;
                    break;
                    }
                default:
                    break;
            }
        }

        light++;
    }
    out_color = diffuse_color.componentMultiply(out_color);
    out_color += spec_color;
    return out_color;
}
Example #4
0
/** findOutOfRoadSector finds the sector where XYZ is, but as it name
    implies, it is more accurate for the outside of the track than the
    inside, and for STK's needs the accuracy on top of the track is
    unacceptable; but if this was a 2D function, the accuracy for out
    of road sectors would be perfect.

    To find the sector we look for the closest line segment from the
    right and left drivelines, and the number of that segment will be
    the sector.

    The SIDE argument is used to speed up the function only; if we know
    that XYZ is on the left or right side of the track, we know that
    the closest driveline must be the one that matches that condition.
    In reality, the side used in STK is the one from the previous frame,
    but in order to move from one side to another a point would go
    through the middle, that is handled by findRoadSector() which doesn't
    has speed ups based on the side.

    NOTE: This method of finding the sector outside of the road is *not*
    perfect: if two line segments have a similar altitude (but enough to
    let a kart get through) and they are very close on a 2D system,
    if a kart is on the air it could be closer to the top line segment
    even if it is supposed to be on the sector of the lower line segment.
    Probably the best solution would be to construct a quad that reaches
    until the next higher overlapping line segment, and find the closest
    one to XYZ.
 */
int QuadGraph::findOutOfRoadSector(const Vec3& xyz,
                                   const int curr_sector,
                                   std::vector<int> *all_sectors) const
{
    int count = (all_sectors!=NULL) ? (int) all_sectors->size() : getNumNodes();
    int current_sector = 0;
    if(curr_sector != UNKNOWN_SECTOR && !all_sectors)
    {
        // We have to test all nodes here: reason is that on track with
        // shortcuts the n quads of the main drivelines is followed by
        // the quads of the shortcuts. So after quad n-1 (the last one
        // before the lap counting line) quad n will not be 0 (the first
        // quad after the lap counting line), but one of the quads on a
        // shortcut. If we only tested a limited number of quads to
        // improve the performance the crossing of a lap might not be
        // detected (because quad 0 is not tested, only quads on the
        // shortcuts are tested). If this should become a performance
        // bottleneck, we need to set up a graph of 'next' quads for each
        // quad (similar to what the AI does), and only test the quads
        // in this graph.
        const int LIMIT = getNumNodes();
        count           = LIMIT;
        // Start 10 quads before the current quad, so the quads closest
        // to the current position are tested first.
        current_sector  = curr_sector -10;
        if(current_sector<0) current_sector += getNumNodes();
    }

    int   min_sector = UNKNOWN_SECTOR;
    float min_dist_2 = 999999.0f*999999.0f;

    // If a kart is falling and in between (or too far below)
    // a driveline point it might not fulfill
    // the height condition. So we run the test twice: first with height
    // condition, then again without the height condition - just to make sure
    // it always comes back with some kind of quad.
    for(int phase=0; phase<2; phase++)
    {
        for(int j=0; j<count; j++)
        {
            int next_sector;
            if(all_sectors)
                next_sector = (*all_sectors)[j];
            else
                next_sector  = current_sector+1 == (int)getNumNodes()
                ? 0
                : current_sector+1;

            // A first simple test uses the 2d distance to the center of the quad.
            float dist_2 = m_all_nodes[next_sector]->getDistance2FromPoint(xyz);
            if(dist_2<min_dist_2)
            {
                const Quad &q = getQuadOfNode(next_sector);
                float dist    = xyz.getY() - q.getMinHeight();
                // While negative distances are unlikely, we allow some small
                // negative numbers in case that the kart is partly in the
                // track. Only do the height test in phase==0, in phase==1
                // accept any point, independent of height.
                if(phase==1 || (dist < 5.0f && dist>-1.0f) )
                {
                    min_dist_2 = dist_2;
                    min_sector = next_sector;
                }
            }
            current_sector = next_sector;
        }   // for j
        // Leave in phase 0 if any sector was found.
        if(min_sector!=UNKNOWN_SECTOR)
            return min_sector;
    }   // phase

    if(min_sector==UNKNOWN_SECTOR )
    {
        Log::info("Quad Grap", "unknown sector found.");
    }
    return min_sector;
}   // findOutOfRoadSector
//------------------------------------------------------------------------
void CVehicleMovementWarrior::Update(const float deltaTime)
{  
  FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

  if (!IsCollapsing())
    CVehicleMovementHovercraft::Update(deltaTime);
  else
    CVehicleMovementBase::Update(deltaTime);
  
  if (IsCollapsing())
  {
    m_collapseTimer += deltaTime; 

    // check platform
		Vec3 platformPos;

		if (m_pPlatformPos)
			platformPos = m_pPlatformPos->GetWorldTM().GetTranslation();
		else
			platformPos.zero();

    float dist = platformPos.z - GetISystem()->GetI3DEngine()->GetTerrainElevation(platformPos.x, platformPos.y);
    if (dist < 1.f)
    {
      m_platformDown = true;      
    }

    // center turret
    RotatePart(m_pTurret, DEG2RAD(0.f), AXIS_Z, DEG2RAD(2.5f), deltaTime);

    // take down wing and cannon
    RotatePart(m_pWing, DEG2RAD(-12.5f), AXIS_X, DEG2RAD(3.f), deltaTime);
    RotatePart(m_pCannon, DEG2RAD(-20.f), AXIS_X, DEG2RAD(2.5f), deltaTime);

    if (!m_platformDown)
    { 
      // handle legs to bring down platform
      TThrusters::iterator iter;
      for (iter=m_vecThrusters.begin(); iter!=m_vecThrusters.end(); ++iter)
      {
        SThruster* pThruster = *iter;

        if (pThruster->heightAdaption <= 0.f)        
        {
          pThruster->hoverHeight = max(0.1f, pThruster->hoverHeight - 0.6f*deltaTime);
          continue;
        }
        else
        {
          //if (!pThruster->groundContact)          
          //pThruster->hoverHeight = max(0.1f, pThruster->hoverHeight - 0.2f*deltaTime);          
        }

        /* 
        // special legs control
        float collapseSpeed = DEG2RAD(5.f);
        float maxDistMovable = 1.f/0.8f;

        float dist = (isneg(pThruster->prevDist)) ? 0.f : pThruster->hoverHeight - pThruster->prevDist;

        if (isneg(dist))
        {
        collapseSpeed *= max(0.f, 1.f + maxDistMovable*dist);
        }

        if (collapseSpeed > 0.f)
        { 
        float angle = RotatePart(pThruster->pParentPart, DEG2RAD(m_collapsedLegAngle), collapseSpeed, deltaTime);          
        RotatePart(pThruster->pPart, DEG2RAD(m_collapsedFeetAngle), collapseSpeed, deltaTime);
        }
        */
      }      
    }
    else
    {
      if (!m_collapsed)
      {
        Collapsed(true); 
      }
    }
  }
  
  if (IsPowered() && !IsCollapsed())
  { 
    // "normal" legs control here   

    bool bStartComplete = (m_startComplete > 1.5f);
    float adaptionSpeed = IsCollapsing() ? 0.8f : 1.5f;
    int t = 0;

    for (TThrusters::iterator iter=m_vecThrusters.begin(); iter!=m_vecThrusters.end(); ++iter)
    {
      SThruster* pThruster = *iter;
      ++t;

      if (pThruster->heightAdaption > 0.f && bStartComplete && pThruster->pPart && pThruster->pParentPart)
      {         
        const char* footName = pThruster->pPart->GetName().c_str();        
        EWarriorMovement mode = eWM_Hovering;
        float correction = 0.f, maxCorrection = 0.f;        

        // adjust legs        
        float error = 0.f; 

        if (!pThruster->hit)
          error = pThruster->hoverHeight; // when not hit, correct downwards 
        else if (pThruster->prevDist > 0.f)
          error = pThruster->prevDist - pThruster->hoverHeight; 
        
        if (mode != eWM_None && abs(error) > 0.05f)
        {
          float speed = max(0.1f, min(1.f, abs(error))) * adaptionSpeed;
          correction = -sgn(error) * min(speed*deltaTime, abs(error)); // correct up to error

          // don't correct more than heightAdaption allows
          maxCorrection = abs((pThruster->heightInitial + sgn(correction)*pThruster->heightAdaption) - pThruster->pos.z);          
          float minCorrection = (pThruster->groundContact) ? 0.f : -maxCorrection;          

          correction = CLAMP(correction, minCorrection, maxCorrection);

          if (abs(correction) > 0.0001f)
          { 
            // positive correction for leg, negative for foot
            Matrix34 legLocal  = pThruster->pParentPart->GetLocalBaseTM();
            Matrix34 footLocal = pThruster->pPart->GetLocalBaseTM();

            float radius = footLocal.GetTranslation().len();
            float deltaAngle = correction / radius; // this assumes correction on circle (accurate enough for large radius)

            Matrix34 legTM  = Matrix33(legLocal) * Matrix33::CreateRotationX(deltaAngle);
            Matrix34 footTM = Matrix33(footLocal) * Matrix33::CreateRotationX(-deltaAngle);

            legTM.SetTranslation(legLocal.GetTranslation());
            footTM.SetTranslation(footLocal.GetTranslation());

            pThruster->pParentPart->SetLocalBaseTM(legTM);
            pThruster->pPart->SetLocalBaseTM(footTM);
          }          
        }

        if (IsProfilingMovement())
        {
          static ICVar* pDebugLeg = GetISystem()->GetIConsole()->GetCVar("warrior_debug_leg");
          if (pDebugLeg && pDebugLeg->GetIVal() == t)
          {
            //CryLog("hoverErr %.2f, levelErr %.2f, neutralErr %.2f -> %s corr %.3f (max %.2f)", hoverError, levelError, neutralError, sMode, correction, maxCorrection);
          }                    
        }        
      }
    }
  }

  // regain control
  if (m_collapseTimer > m_recoverTime)
  {     
    Collapsed(false);
  }

  for (TThrusters::iterator it=m_vecThrusters.begin(); it!=m_vecThrusters.end(); ++it)
  {
    (*it)->groundContact = false;
  }
}
bool CIntersectionAssistanceUnit::GetHighestScoringLastKnownGoodPosition( const QuatT& baseOrientation, QuatT& outQuat ) const
{
	bool bFlippedIsBest = false;

	if(!m_lastKnownGoodPositions.empty())
	{
		// Higher is better
		float fBestScore = 0.0f; 
		int bestIndex = -1; 
		Vec3 vBaseUpDir = baseOrientation.q.GetColumn2().GetNormalized(); 
		for(uint8 i = 0; i < m_lastKnownGoodPositions.size(); ++i)
		{
			const QuatT& qLastKnownGood = m_lastKnownGoodPositions[i]; 
			if(IsPositionWithinAcceptedLimits(qLastKnownGood.t, baseOrientation.t, kDistanceTolerance))
			{
				// Generate [0.0f,1.0f] score for distance
				const Vec3 distVec = (qLastKnownGood.t - baseOrientation.t); 

				const float length = max(distVec.GetLengthFast(),0.0001f);
				const float distanceScore = max(1.0f - (length * kInverseDistanceTolerance) * kDistanceWeight, 0.0f);

				Vec3 vUpDir		 = qLastKnownGood.q.GetColumn2();

				const float regularOrientationScore = vBaseUpDir.Dot(vUpDir);
				const float flippedOrientationScore = vBaseUpDir.Dot(-vUpDir);

				float orientationScore = max(regularOrientationScore, flippedOrientationScore);
				orientationScore *= kOrientationWeight;

				const float fCandidateScore = distanceScore + orientationScore;

#ifndef _RELEASE
				if(g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled == 2)
				{
					CryWatch("[INDEX(%d)] : D[%.3f] O[%.3f] T[%.3f] (%s)", i, distanceScore, orientationScore, fCandidateScore, flippedOrientationScore > regularOrientationScore ? "*F*" : "R");
				}
#endif //#ifndef _RELEASE

				if(fCandidateScore > fBestScore)
				{
					bestIndex	 = i; 
					fBestScore = fCandidateScore;
					bFlippedIsBest = (flippedOrientationScore > regularOrientationScore);
				}
			}
		}

		if(bestIndex >= 0)
		{
			outQuat = m_lastKnownGoodPositions[bestIndex];
			if(bFlippedIsBest)
			{
				Matrix34 wMat(outQuat); 
				Vec3 vFlippedUpDir = -outQuat.q.GetColumn2().GetNormalized();
				Vec3 vForwardDir	 = outQuat.q.GetColumn1().GetNormalized(); 
				Vec3 vSideDir			 = -outQuat.q.GetColumn0().GetNormalized();
				Matrix34 wFlippedMat;
				wFlippedMat = Matrix34::CreateFromVectors(vSideDir, vForwardDir, vFlippedUpDir, wMat.GetTranslation());
				outQuat = QuatT(wFlippedMat);

				// Adjust pos (rotating around OOBB centre effectively)
				const IEntity* pSubjectEntity = gEnv->pEntitySystem->GetEntity(m_subjectEntityId);
				if(pSubjectEntity)
				{
					AABB entAABB;
					OBB  entOBB;
					pSubjectEntity->GetLocalBounds(entAABB);
					entOBB.SetOBBfromAABB(Quat(IDENTITY), entAABB);

					Vec3 Centre = wMat.TransformPoint(entOBB.c);
					Vec3 toCentre = Centre - outQuat.t;
					outQuat.t += (toCentre * 2.0f);
				}
			}

#ifndef _RELEASE
			if(g_pGameCVars->pl_pickAndThrow.intersectionAssistDebugEnabled == 2)
			{
				m_currentBestIndex = bestIndex;
				CryWatch("[BEST INDEX] : %d", bestIndex);
			}
#endif // ifndef _RELEASE

			return true;
		}
	}

#ifndef _RELEASE
	m_currentBestIndex = -1;
#endif // ifndef _RELEASE

	return false;
}
void ElasticFoundationForceImpl::processContact
   (const State& state, 
    ContactSurfaceIndex meshIndex, ContactSurfaceIndex otherBodyIndex, 
    const Parameters& param, const std::set<int>& insideFaces,
    Real areaScale, Vector_<SpatialVec>& bodyForces, Real& pe) const 
{
    const ContactGeometry& otherObject = subsystem.getBodyGeometry(set, otherBodyIndex);
    const MobilizedBody& body1 = subsystem.getBody(set, meshIndex);
    const MobilizedBody& body2 = subsystem.getBody(set, otherBodyIndex);
    const Transform t1g = body1.getBodyTransform(state)*subsystem.getBodyTransform(set, meshIndex); // mesh to ground
    const Transform t2g = body2.getBodyTransform(state)*subsystem.getBodyTransform(set, otherBodyIndex); // other object to ground
    const Transform t12 = ~t2g*t1g; // mesh to other object

    // Loop over all the springs, and evaluate the force from each one.

    for (std::set<int>::const_iterator iter = insideFaces.begin(); 
                                       iter != insideFaces.end(); ++iter) {
        int face = *iter;
        UnitVec3 normal;
        bool inside;
        Vec3 nearestPoint = otherObject.findNearestPoint(t12*param.springPosition[face], inside, normal);
        if (!inside)
            continue;
        
        // Find how much the spring is displaced.
        
        nearestPoint = t2g*nearestPoint;
        const Vec3 springPosInGround = t1g*param.springPosition[face];
        const Vec3 displacement = nearestPoint-springPosInGround;
        const Real distance = displacement.norm();
        if (distance == 0.0)
            continue;
        const Vec3 forceDir = displacement/distance;
        
        // Calculate the relative velocity of the two bodies at the contact point.
        
        const Vec3 station1 = body1.findStationAtGroundPoint(state, nearestPoint);
        const Vec3 station2 = body2.findStationAtGroundPoint(state, nearestPoint);
        const Vec3 v1 = body1.findStationVelocityInGround(state, station1);
        const Vec3 v2 = body2.findStationVelocityInGround(state, station2);
        const Vec3 v = v2-v1;
        const Real vnormal = dot(v, forceDir);
        const Vec3 vtangent = v-vnormal*forceDir;
        
        // Calculate the damping force.
        
        const Real area = areaScale * param.springArea[face];
        const Real f = param.stiffness*area*distance*(1+param.dissipation*vnormal);
        Vec3 force = (f > 0 ? f*forceDir : Vec3(0));
        
        // Calculate the friction force.
        
        const Real vslip = vtangent.norm();
        if (f > 0 && vslip != 0) {
            const Real vrel = vslip/transitionVelocity;
            const Real ffriction = 
                f*(std::min(vrel, Real(1))
                 *(param.dynamicFriction+2*(param.staticFriction-param.dynamicFriction)
                 /(1+vrel*vrel))+param.viscousFriction*vslip);
            force += ffriction*vtangent/vslip;
        }

        body1.applyForceToBodyPoint(state, station1, force, bodyForces);
        body2.applyForceToBodyPoint(state, station2, -force, bodyForces);
        pe += param.stiffness*area*displacement.normSqr()/2;
    }
}
Example #8
0
void testEwaldPME(bool includeExceptions) {

//      Use amorphous NaCl system for the tests

    const int numParticles = 894;
    const double cutoff = 1.2;
    const double boxSize = 3.00646;
    double tol = 1e-5;

    ReferencePlatform reference;
    System system;
    NonbondedForce* nonbonded = new NonbondedForce();
    nonbonded->setNonbondedMethod(NonbondedForce::Ewald);
    nonbonded->setCutoffDistance(cutoff);
    nonbonded->setEwaldErrorTolerance(tol);

    for (int i = 0; i < numParticles/2; i++)
        system.addParticle(22.99);
    for (int i = 0; i < numParticles/2; i++)
        system.addParticle(35.45);
    for (int i = 0; i < numParticles/2; i++)
        nonbonded->addParticle(1.0, 1.0,0.0);
    for (int i = 0; i < numParticles/2; i++)
        nonbonded->addParticle(-1.0, 1.0,0.0);
    system.setDefaultPeriodicBoxVectors(Vec3(boxSize, 0, 0), Vec3(0, boxSize, 0), Vec3(0, 0, boxSize));
    system.addForce(nonbonded);

    vector<Vec3> positions(numParticles);
    #include "nacl_amorph.dat"
    if (includeExceptions) {
        // Add some exclusions.

        for (int i = 0; i < numParticles-1; i++) {
            Vec3 delta = positions[i]-positions[i+1];
            if (sqrt(delta.dot(delta)) < 0.5*cutoff)
                nonbonded->addException(i, i+1, i%2 == 0 ? 0.0 : 0.5, 1.0, 0.0);
        }
    }

//    (1)  Check whether the Reference and CPU platforms agree when using Ewald Method

    VerletIntegrator integrator1(0.01);
    VerletIntegrator integrator2(0.01);
    Context cpuContext(system, integrator1, platform);
    Context referenceContext(system, integrator2, reference);
    cpuContext.setPositions(positions);
    referenceContext.setPositions(positions);
    State cpuState = cpuContext.getState(State::Forces | State::Energy);
    State referenceState = referenceContext.getState(State::Forces | State::Energy);
    tol = 1e-2;
    for (int i = 0; i < numParticles; i++) {
        ASSERT_EQUAL_VEC(referenceState.getForces()[i], cpuState.getForces()[i], tol);
    }
    tol = 1e-5;
    ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cpuState.getPotentialEnergy(), tol);

//    (2) Check whether Ewald method in CPU is self-consistent

    double norm = 0.0;
    for (int i = 0; i < numParticles; ++i) {
        Vec3 f = cpuState.getForces()[i];
        norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
    }

    norm = std::sqrt(norm);
    const double delta = 5e-3;
    double step = delta/norm;
    for (int i = 0; i < numParticles; ++i) {
        Vec3 p = positions[i];
        Vec3 f = cpuState.getForces()[i];
        positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
    }
    VerletIntegrator integrator3(0.01);
    Context cpuContext2(system, integrator3, platform);
    cpuContext2.setPositions(positions);

    tol = 1e-2;
    State cpuState2 = cpuContext2.getState(State::Energy);
    ASSERT_EQUAL_TOL(norm, (cpuState2.getPotentialEnergy()-cpuState.getPotentialEnergy())/delta, tol)

//    (3)  Check whether the Reference and CPU platforms agree when using PME

    nonbonded->setNonbondedMethod(NonbondedForce::PME);
    cpuContext.reinitialize();
    referenceContext.reinitialize();
    cpuContext.setPositions(positions);
    referenceContext.setPositions(positions);
    cpuState = cpuContext.getState(State::Forces | State::Energy);
    referenceState = referenceContext.getState(State::Forces | State::Energy);
    tol = 1e-2;
    for (int i = 0; i < numParticles; i++) {
        ASSERT_EQUAL_VEC(referenceState.getForces()[i], cpuState.getForces()[i], tol);
    }
    tol = 1e-5;
    ASSERT_EQUAL_TOL(referenceState.getPotentialEnergy(), cpuState.getPotentialEnergy(), tol);

//    (4) Check whether PME method in CPU is self-consistent

    norm = 0.0;
    for (int i = 0; i < numParticles; ++i) {
        Vec3 f = cpuState.getForces()[i];
        norm += f[0]*f[0] + f[1]*f[1] + f[2]*f[2];
    }

    norm = std::sqrt(norm);
    step = delta/norm;
    for (int i = 0; i < numParticles; ++i) {
        Vec3 p = positions[i];
        Vec3 f = cpuState.getForces()[i];
        positions[i] = Vec3(p[0]-f[0]*step, p[1]-f[1]*step, p[2]-f[2]*step);
    }
    VerletIntegrator integrator4(0.01);
    Context cpuContext3(system, integrator4, platform);
    cpuContext3.setPositions(positions);

    tol = 1e-2;
    State cpuState3 = cpuContext3.getState(State::Energy);
    ASSERT_EQUAL_TOL(norm, (cpuState3.getPotentialEnergy()-cpuState.getPotentialEnergy())/delta, tol)
}
//-------------------------------------------
void CGameRules::ProcessClientExplosionScreenFX(const ExplosionInfo &explosionInfo)
{
	IActor *pClientActor = g_pGame->GetIGameFramework()->GetClientActor();
	if (pClientActor)
	{
		//Distance
		float dist = (pClientActor->GetEntity()->GetWorldPos() - explosionInfo.pos).len();

		//Is the explosion in Player's FOV (let's suppose the FOV a bit higher, like 80)
		CActor *pActor = (CActor *)pClientActor;
		SMovementState state;
		if (IMovementController *pMV = pActor->GetMovementController())
		{
			pMV->GetMovementState(state);
		}

		Vec3 eyeToExplosion = explosionInfo.pos - state.eyePosition;
		eyeToExplosion.Normalize();
		bool inFOV = (state.eyeDirection.Dot(eyeToExplosion) > 0.68f);
		
		// if in a vehicle eyeDirection is wrong
		if(pActor && pActor->GetLinkedVehicle())
		{
			Vec3 eyeDir = static_cast<CPlayer*>(pActor)->GetVehicleViewDir();
			inFOV = (eyeDir.Dot(eyeToExplosion) > 0.68f);
		}

		//All explosions have radial blur (default 30m radius, to make Sean happy =))
		float maxBlurDistance = (explosionInfo.maxblurdistance>0.0f)?explosionInfo.maxblurdistance:30.0f;
		if (maxBlurDistance>0.0f && g_pGameCVars->g_radialBlur>0.0f && m_explosionScreenFX && explosionInfo.radius>0.5f)
		{		
			if (inFOV && dist < maxBlurDistance)
			{
				ray_hit hit;
				int col = gEnv->pPhysicalWorld->RayWorldIntersection(explosionInfo.pos , -eyeToExplosion*dist, ent_static | ent_terrain, rwi_stop_at_pierceable|rwi_colltype_any, &hit, 1);

				//If there was no obstacle between flashbang grenade and player
				if(!col)
				{
					float blurRadius = (-1.0f/maxBlurDistance)*dist + 1.0f;

					gEnv->p3DEngine->SetPostEffectParam("FilterRadialBlurring_Radius", blurRadius);
					gEnv->p3DEngine->SetPostEffectParam("FilterRadialBlurring_Amount", 1.0f);

					//CActor *pActor = (CActor *)pClientActor;
					if (pActor->GetScreenEffects() != 0)
					{
						CPostProcessEffect *pBlur = new CPostProcessEffect(pClientActor->GetEntityId(),"FilterRadialBlurring_Amount", 0.0f);
						CLinearBlend *pLinear = new CLinearBlend(1.0f);
						pActor->GetScreenEffects()->StartBlend(pBlur, pLinear, 1.0f, 98);
						pActor->GetScreenEffects()->SetUpdateCoords("FilterRadialBlurring_ScreenPosX","FilterRadialBlurring_ScreenPosY", explosionInfo.pos);
					}

					float distAmp = 1.0f - (dist / maxBlurDistance);
					if (gEnv->pInput) gEnv->pInput->ForceFeedbackEvent( SFFOutputEvent(eDI_XI, eFF_Rumble_Basic, 0.5f, distAmp*3.0f, 0.0f));
				}
			}
		}

		//Flashbang effect 
		if(dist<explosionInfo.radius && inFOV &&
			(!strcmp(explosionInfo.effect_class,"flashbang") || !strcmp(explosionInfo.effect_class,"FlashbangAI")))
		{
			ray_hit hit;
			int col = gEnv->pPhysicalWorld->RayWorldIntersection(explosionInfo.pos , -eyeToExplosion*dist, ent_static | ent_terrain, rwi_stop_at_pierceable|rwi_colltype_any, &hit, 1);

			//If there was no obstacle between flashbang grenade and player
			if(!col)
			{
				float power = explosionInfo.flashbangScale;
				power *= max(0.0f, 1 - (dist/explosionInfo.radius));
				float lookingAt = (eyeToExplosion.Dot(state.eyeDirection.normalize()) + 1)*0.5f;
				power *= lookingAt;

				SAFE_HUD_FUNC(OnFlashbang(1.0f + (power * 4), explosionInfo.blindAmount));

				SAFE_SOUNDMOODS_FUNC(AddSoundMood(SOUNDMOOD_EXPLOSION,MIN(power*40.0f,100.0f)));

				gEnv->p3DEngine->SetPostEffectParam("Flashbang_Time", 1.0f + (power * 4));
				gEnv->p3DEngine->SetPostEffectParam("FlashBang_BlindAmount",explosionInfo.blindAmount);
				gEnv->p3DEngine->SetPostEffectParam("Flashbang_DifractionAmount", (power * 2));
				gEnv->p3DEngine->SetPostEffectParam("Flashbang_Active", 1);
			}
		}
		else if(inFOV && (dist < explosionInfo.radius))
		{
			if (explosionInfo.damage>10.0f || explosionInfo.pressure>100.0f)
			{
				//Add some angular impulse to the client actor depending on distance, direction...
				float dt = (1.0f - dist/explosionInfo.radius);
				dt = dt * dt;
				float angleZ = g_PI*0.15f*dt;
				float angleX = g_PI*0.15f*dt;

				pActor->AddAngularImpulse(Ang3(Random(-angleX*0.5f,angleX),0.0f,Random(-angleZ,angleZ)),0.0f,dt*2.0f);
			}
		}


		float fDist2=(pClientActor->GetEntity()->GetWorldPos()-explosionInfo.pos).len2();
		if (fDist2<250.0f*250.0f)
		{		
			SAFE_HUD_FUNC(ShowSoundOnRadar(explosionInfo.pos, explosionInfo.hole_size));
			if (fDist2<sqr(SAFE_HUD_FUNC_RET(GetBattleRange())))
				SAFE_HUD_FUNC(TickBattleStatus(1.0f));
		}
	}

}
void
SoundD3D::Localize()
{
#ifdef DIRECT_SOUND_3D
	if (sound3d) {
		sound3d->SetMinDistance(min_dist,                        DS3D_IMMEDIATE);
		sound3d->SetMaxDistance(max_dist,                        DS3D_IMMEDIATE);
		sound3d->SetPosition(location.x, location.y, location.z, DS3D_IMMEDIATE);
		sound3d->SetVelocity(velocity.x, velocity.y, velocity.z, DS3D_IMMEDIATE);
	}

#else

	// if no buffer, nothing to do:
	if (!buffer) {
		moved = false;
		return;
	}

	// Compute pan and volume from scratch:
	
	if ((flags & LOC_3D) && creator) {
		Vec3 loc = location;

		SoundCardD3D* ears = (SoundCardD3D*) creator;
		Camera& listener = ears->listener;
		Vec3  ear_loc = listener.Pos();  ear_loc.SwapYZ();
		Vec3  direction = loc - ear_loc;
		
		loc.x = direction * listener.vrt();
		loc.y = direction * listener.vup();
		loc.z = direction * listener.vpn();

		double pan = 10000;
		if (loc.z != 0.0f) pan = fabs(1000.0f * loc.x / loc.z);
		if (pan > 10000)   pan = 10000;
		if (loc.x < 0)     pan = -pan;

		if (volume > 0)
		volume = 0;

		double vol   = volume;
		double mind2 = min_dist * min_dist;
		double maxd2 = max_dist * max_dist;
		double d2    = (loc.x*loc.x) + (loc.y*loc.y) + (loc.z*loc.z);

		if (d2 > maxd2)
		vol = -10000;
		else if (d2 > mind2)
		vol -= (d2-mind2)/(maxd2-mind2) * (vol+10000);

		// clamp volume to legal range:
		if (vol < -10000) vol = -10000;
		else if (vol > volume) vol = volume;

		/***
	Print("Localize: ears  = (%f, %f, %f)\n", ear_loc.x, ear_loc.y, ear_loc.z);
	Print("          world = (%f, %f, %f)\n", location.x, location.y, location.z);
	Print("          view  = (%f, %f, %f)\n", loc.x, loc.y, loc.z);
	Print("          Pan=%f  Volume=%f\n", pan, vol);
	/***/

		HRESULT hr = buffer->SetPan((LONG) pan);
		if (!SUCCEEDED(hr)) {
			char warn[512];
			sprintf_s(warn, "Warning could not set pan on buffer to %f", pan);
			SoundD3DError(warn, hr);
		}

		hr = buffer->SetVolume((LONG) vol);
		if (!SUCCEEDED(hr)) {
			char warn[512];
			sprintf_s(warn, "Warning: could not set volume on buffer to %f", vol);
			SoundD3DError(warn, hr);
		}
		
		// if not too far to hear...
		if ((flags & DOPPLER) && (d2 < maxd2)) {
			// COMPUTE DOPPLER SHIFT:
			const float c = 10000.0f;
			
			direction.Normalize();
			float v_L = ears->velocity * direction;
			float v_S =       velocity * direction;
			
			DWORD f_shift = wfex.nSamplesPerSec;

			if (v_L != v_S) {
				// towards listener:
				if (v_S < 0)
				f_shift = wfex.nSamplesPerSec + 20;
				else
				f_shift = wfex.nSamplesPerSec - 20;
			}

			// distance rolloff of high frequencies:
			double dist     = sqrt(d2);
			DWORD  roll_off = (DWORD) (80 * dist/max_dist);

			f_shift -= roll_off;
			
			if (f_shift < 100)    f_shift = 100;
			if (f_shift > 100000) f_shift = 100000;
			
			hr = buffer->SetFrequency(f_shift);
			if (!SUCCEEDED(hr)) {
				char warn[512];
				sprintf_s(warn, "Warning: could not set Doppler frequency on buffer to %d", f_shift); //-V576
				SoundD3DError(warn, hr);
			}
		}
	}
	else {
		buffer->SetPan((LONG) location.x);
		buffer->SetVolume((LONG) volume);
	}
#endif

	moved = false;
}
Example #11
0
void testErrorTolerance(NonbondedForce::NonbondedMethod method) {
    // Create a cloud of random point charges.

    const int numParticles = 51;
    const double boxWidth = 5.0;
    System system;
    system.setDefaultPeriodicBoxVectors(Vec3(boxWidth, 0, 0), Vec3(0, boxWidth, 0), Vec3(0, 0, boxWidth));
    NonbondedForce* force = new NonbondedForce();
    system.addForce(force);
    vector<Vec3> positions(numParticles);
    OpenMM_SFMT::SFMT sfmt;
    init_gen_rand(0, sfmt);

    for (int i = 0; i < numParticles; i++) {
        system.addParticle(1.0);
        force->addParticle(-1.0+i*2.0/(numParticles-1), 1.0, 0.0);
        positions[i] = Vec3(boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt), boxWidth*genrand_real2(sfmt));
    }
    force->setNonbondedMethod(method);

    // For various values of the cutoff and error tolerance, see if the actual error is reasonable.

    for (double cutoff = 1.0; cutoff < boxWidth/2; cutoff *= 1.2) {
        force->setCutoffDistance(cutoff);
        vector<Vec3> refForces;
        double norm = 0.0;
        for (double tol = 5e-5; tol < 1e-3; tol *= 2.0) {
            force->setEwaldErrorTolerance(tol);
            VerletIntegrator integrator(0.01);
            Context context(system, integrator, platform);
            context.setPositions(positions);
            State state = context.getState(State::Forces);
            if (refForces.size() == 0) {
                refForces = state.getForces();
                for (int i = 0; i < numParticles; i++)
                    norm += refForces[i].dot(refForces[i]);
                norm = sqrt(norm);
            }
            else {
                double diff = 0.0;
                for (int i = 0; i < numParticles; i++) {
                    Vec3 delta = refForces[i]-state.getForces()[i];
                    diff += delta.dot(delta);
                }
                diff = sqrt(diff)/norm;
                ASSERT(diff < 2*tol);
            }
            if (method == NonbondedForce::PME) {
                // See if the PME parameters were calculated correctly.

                double expectedAlpha, actualAlpha;
                int expectedSize[3], actualSize[3];
                NonbondedForceImpl::calcPMEParameters(system, *force, expectedAlpha, expectedSize[0], expectedSize[1], expectedSize[2]);
                force->getPMEParametersInContext(context, actualAlpha, actualSize[0], actualSize[1], actualSize[2]);
                ASSERT_EQUAL_TOL(expectedAlpha, actualAlpha, 1e-5);
                for (int i = 0; i < 3; i++) {
                    ASSERT(actualSize[i] >= expectedSize[i]);
                    ASSERT(actualSize[i] < expectedSize[i]+10);
                }
            }
        }
    }
}
Example #12
0
Mat4::Mat4(Vec3 a, double r)
{
	// Create a rotation matrix for an arbitrary axis.
	// See Wikipedia or whatever for the formulae.

	double cosR = cos(r);
	double sinR = sin(r);

	m[0] = cosR + a.x() * a.x() * (1 - cosR);
	m[1] = a.y() * a.x() * (1 - cosR) + a.z() * sinR;
	m[2] = a.z() * a.x() * (1 - cosR) - a.y() * sinR;
	m[3] = 0;

	m[4] = a.x() * a.y() * (1 - cosR) - a.z() * sinR;
	m[5] = cosR + a.y() * a.y() * (1 - cosR);
	m[6] = a.z() * a.y() * (1 - cosR) + a.x() * sinR;
	m[7] = 0;

	m[8]  = a.x() * a.z() * (1 - cosR) + a.y() * sinR;
	m[9]  = a.y() * a.z() * (1 - cosR) - a.x() * sinR;
	m[10] = cosR + a.z() * a.z() * (1 - cosR);
	m[11] = 0;

	m[12] = 0;
	m[13] = 0;
	m[14] = 0;
	m[15] = 1;
}
Example #13
0
// Dot product
double Vec3::dot(Vec3& o)
{
	return x() * o.x()  +  y() * o.y()  +  z() * o.z();
}
/** Actually reads in the data from the xml file.
 *  \param root Root of the xml tree.
 */
void KartProperties::getAllData(const XMLNode * root)
{
    root->get("version",           &m_version);

    root->get("name",              &m_name             );

    root->get("icon-file",         &m_icon_file        );

    root->get("minimap-icon-file", &m_minimap_icon_file);

    root->get("shadow-file",       &m_shadow_file      );
    Vec3 c;
    root->get("rgb",               &c                  );
    m_color.set(255, (int)(255*c.getX()), (int)(255*c.getY()), (int)(255*c.getZ()));

    root->get("groups",            &m_groups           );

    root->get("random-wheel-rot",  &m_has_rand_wheels  );

    root->get("shadow-scale",      &m_shadow_scale     );
    root->get("shadow-x-offset",   &m_shadow_x_offset  );
    root->get("shadow-y-offset",   &m_shadow_y_offset  );

    root->get("type",     &m_kart_type        );

    if(const XMLNode *dimensions_node = root->getNode("center"))
        dimensions_node->get("gravity-shift", &m_gravity_center_shift);

    if(const XMLNode *ai_node = root->getNode("ai"))
    {
        const XMLNode *easy = ai_node->getNode("easy");
        m_ai_properties[RaceManager::DIFFICULTY_EASY]->load(easy);
        const XMLNode *medium = ai_node->getNode("medium");
        m_ai_properties[RaceManager::DIFFICULTY_MEDIUM]->load(medium);
        const XMLNode *hard = ai_node->getNode("hard");
        m_ai_properties[RaceManager::DIFFICULTY_HARD]->load(hard);
        const XMLNode *best = ai_node->getNode("best");
        m_ai_properties[RaceManager::DIFFICULTY_BEST]->load(best);
    }

    if(const XMLNode *suspension_node = root->getNode("suspension"))
    {
        suspension_node->get("stiffness",            &m_suspension_stiffness);
        suspension_node->get("rest",                 &m_suspension_rest     );
        suspension_node->get("travel-cm",            &m_suspension_travel_cm);
        suspension_node->get("exp-spring-response",  &m_exp_spring_response );
        suspension_node->get("max-force",            &m_max_suspension_force);
    }

    if(const XMLNode *wheels_node = root->getNode("wheels"))
    {
        wheels_node->get("damping-relaxation",  &m_wheel_damping_relaxation );
        wheels_node->get("damping-compression", &m_wheel_damping_compression);
        wheels_node->get("radius",              &m_wheel_radius             );
    }

    if(const XMLNode *speed_weighted_objects_node = root->getNode("speed-weighted-objects"))
    {
        m_speed_weighted_object_properties.loadFromXMLNode(speed_weighted_objects_node);
    }

    if(const XMLNode *friction_node = root->getNode("friction"))
        friction_node->get("slip", &m_friction_slip);

    if(const XMLNode *stability_node = root->getNode("stability"))
    {
        stability_node->get("roll-influence",
                                                   &m_roll_influence         );
        stability_node->get("chassis-linear-damping",
                                                   &m_chassis_linear_damping );
        stability_node->get("chassis-angular-damping",
                                                   &m_chassis_angular_damping);
        stability_node->get("downward-impulse-factor",
                                                   &m_downward_impulse_factor);
        stability_node->get("track-connection-accel",
                                                   &m_track_connection_accel );
    }

    if(const XMLNode *collision_node = root->getNode("collision"))
    {
        collision_node->get("impulse",         &m_collision_impulse        );
        collision_node->get("impulse-time",    &m_collision_impulse_time   );
        collision_node->get("terrain-impulse", &m_collision_terrain_impulse);
        collision_node->get("restitution",     &m_restitution              );
        collision_node->get("bevel-factor",    &m_bevel_factor             );
        std::string s;
        collision_node->get("impulse-type",    &s                          );
        s = StringUtils::toLowerCase(s);
        if(s=="none")
            m_terrain_impulse_type = IMPULSE_NONE;
        else if(s=="normal")
            m_terrain_impulse_type = IMPULSE_NORMAL;
        else if(s=="driveline")
            m_terrain_impulse_type = IMPULSE_TO_DRIVELINE;
        else
        {
            Log::fatal("[KartProperties]",
                       "Missing or incorrect value for impulse-type: '%s'.",
                       s.c_str());
        }
    }

    //TODO: wheel front right and wheel front left is not loaded, yet is
    //TODO: listed as an attribute in the xml file after wheel-radius
    //TODO: same goes for their rear equivalents


    if(const XMLNode *jump_node= root->getNode("jump"))
    {
        jump_node->get("animation-time", &m_jump_animation_time);
    }

    if(const XMLNode *camera_node= root->getNode("camera"))
    {
        camera_node->get("distance", &m_camera_distance);
        camera_node->get("forward-up-angle", &m_camera_forward_up_angle);
        m_camera_forward_up_angle *= DEGREE_TO_RAD;
        camera_node->get("backward-up-angle", &m_camera_backward_up_angle);
        m_camera_backward_up_angle *= DEGREE_TO_RAD;
    }

    if(const XMLNode *sounds_node= root->getNode("sounds"))
    {
        std::string s;
        sounds_node->get("engine", &s);
        if      (s == "large") m_engine_sfx_type = "engine_large";
        else if (s == "small") m_engine_sfx_type = "engine_small";
        else
        {
            if (sfx_manager->soundExist(s))
            {
                m_engine_sfx_type = s;
            }
            else
            {
                Log::error("[KartProperties]",
                           "Kart '%s' has an invalid engine '%s'.",
                           m_name.c_str(), s.c_str());
                m_engine_sfx_type = "engine_small";
            }
        }

#ifdef WILL_BE_ENABLED_ONCE_DONE_PROPERLY
        // Load custom kart SFX files (TODO: enable back when it's implemented properly)
        for (int i = 0; i < SFXManager::NUM_CUSTOMS; i++)
        {
            std::string tempFile;
            // Get filename associated with each custom sfx tag in sfx config
            if (sounds_node->get(sfx_manager->getCustomTagName(i), tempFile))
            {
                // determine absolute filename
                // FIXME: will not work with add-on packs (is data dir the same)?
                tempFile = file_manager->getKartFile(tempFile, getIdent());

                // Create sfx in sfx manager and store id
                m_custom_sfx_id[i] = sfx_manager->addSingleSfx(tempFile, 1, 0.2f,1.0f);
            }
            else
            {
                // if there is no filename associated with a given tag
                m_custom_sfx_id[i] = -1;
            }   // if custom sound
        }   // for i<SFXManager::NUM_CUSTOMS
#endif
    }   // if sounds-node exist

    if(const XMLNode *nitro_node = root->getNode("nitro"))
    {
        nitro_node->get("consumption",          &m_nitro_consumption       );
        nitro_node->get("small-container",      &m_nitro_small_container   );
        nitro_node->get("big-container",        &m_nitro_big_container     );
        nitro_node->get("max-speed-increase",   &m_nitro_max_speed_increase);
        nitro_node->get("engine-force",         &m_nitro_engine_force      );
        nitro_node->get("duration",             &m_nitro_duration          );
        nitro_node->get("fade-out-time",        &m_nitro_fade_out_time     );
        nitro_node->get("max",                  &m_nitro_max               );
        nitro_node->get("min-consumption-time", &m_nitro_min_consumption   );
    }

    if(const XMLNode *bubble_node = root->getNode("bubblegum"))
    {
        bubble_node->get("time",           &m_bubblegum_time          );
        bubble_node->get("speed-fraction", &m_bubblegum_speed_fraction);
        bubble_node->get("fade-in-time",   &m_bubblegum_fade_in_time  );
        bubble_node->get("torque",         &m_bubblegum_torque        );
    }

    if(const XMLNode *rescue_node = root->getNode("rescue"))
    {
        rescue_node->get("vert-offset", &m_rescue_vert_offset);
        rescue_node->get("time",        &m_rescue_time       );
        rescue_node->get("height",      &m_rescue_height     );
    }

    if(const XMLNode *explosion_node = root->getNode("explosion"))
    {
        explosion_node->get("time",   &m_explosion_time  );
        explosion_node->get("radius", &m_explosion_radius);
        explosion_node->get("invulnerability-time",
                        &m_explosion_invulnerability_time);
    }

    if(const XMLNode *skid_node = root->getNode("skid"))
    {
        m_skidding_properties->load(skid_node);
    }


    if(const XMLNode *slipstream_node = root->getNode("slipstream"))
    {
        slipstream_node->get("length",       &m_slipstream_length            );
        slipstream_node->get("width",        &m_slipstream_width             );
        slipstream_node->get("collect-time", &m_slipstream_collect_time      );
        slipstream_node->get("use-time",     &m_slipstream_use_time          );
        slipstream_node->get("add-power",    &m_slipstream_add_power         );
        slipstream_node->get("min-speed",    &m_slipstream_min_speed         );
        slipstream_node->get("max-speed-increase",
                                             &m_slipstream_max_speed_increase);
        slipstream_node->get("duration",     &m_slipstream_duration          );
        slipstream_node->get("fade-out-time",&m_slipstream_fade_out_time     );
    }

    if(const XMLNode *turn_node = root->getNode("turn"))
    {
        turn_node->get("time-full-steer",      &m_time_full_steer     );
        turn_node->get("time-reset-steer",     &m_time_reset_steer    );
        turn_node->get("turn-radius",          &m_turn_angle_at_speed );
        // For now store the turn radius in turn angle, the correct
        // value can only be determined later in ::load
    }

    if(const XMLNode *engine_node = root->getNode("engine"))
    {
        engine_node->get("brake-factor", &m_brake_factor);
        engine_node->get("max-speed-reverse-ratio", &m_max_speed_reverse_ratio);
        engine_node->get("power", &m_engine_power);
        if(m_engine_power.size()!=RaceManager::DIFFICULTY_COUNT)
        {
            Log::fatal("[KartProperties]",
                       "Incorrect engine-power specifications for kart '%s'",
                       getIdent().c_str());
        }
        engine_node->get("max-speed", &m_max_speed);
        if(m_max_speed.size()!=RaceManager::DIFFICULTY_COUNT)
        {
            Log::fatal("[KartProperties]",
                       "Incorrect max-speed specifications for kart '%s'",
                       getIdent().c_str());
        }
    }   // if getNode("engine")

    if(const XMLNode *gear_node = root->getNode("gear"))
    {
        gear_node->get("switch-ratio",   &m_gear_switch_ratio  );
        gear_node->get("power-increase", &m_gear_power_increase);
    }

    if(const XMLNode *mass_node = root->getNode("mass"))
        mass_node->get("value", &m_mass);

    if(const XMLNode *plunger_node= root->getNode("plunger"))
    {
        plunger_node->get("band-max-length",    &m_rubber_band_max_length    );
        plunger_node->get("band-force",         &m_rubber_band_force         );
        plunger_node->get("band-duration",      &m_rubber_band_duration      );
        plunger_node->get("band-speed-increase",&m_rubber_band_speed_increase);
        plunger_node->get("band-fade-out-time", &m_rubber_band_fade_out_time );
        plunger_node->get("in-face-time", &m_plunger_in_face_duration);
        if(m_plunger_in_face_duration.size()!=RaceManager::DIFFICULTY_COUNT)
        {
            Log::fatal("KartProperties",
                       "Invalid plunger in-face-time specification.");
        }
    }

    if(const XMLNode *zipper_node= root->getNode("zipper"))
    {
        zipper_node->get("time",               &m_zipper_time              );
        zipper_node->get("fade-out-time",      &m_zipper_fade_out_time     );
        zipper_node->get("force",              &m_zipper_force             );
        zipper_node->get("speed-gain",         &m_zipper_speed_gain        );
        zipper_node->get("max-speed-increase", &m_zipper_max_speed_increase);
    }

    if(const XMLNode *swatter_node= root->getNode("swatter"))
    {
        swatter_node->get("duration",        &m_swatter_duration      );
        swatter_node->get("squash-duration", &m_squash_duration       );
        swatter_node->get("squash-slowdown", &m_squash_slowdown       );
        if(swatter_node->get("distance",     &m_swatter_distance2) )
        {
            // Avoid squaring if distance is not defined, so that
            // distance2 remains UNDEFINED (which is a negative value)
            m_swatter_distance2 *= m_swatter_distance2;
        }
    }

    if(const XMLNode *lean_node= root->getNode("lean"))
    {
        lean_node->get("max",   &m_max_lean  );
        lean_node->get("speed", &m_lean_speed);
        m_max_lean   *= DEGREE_TO_RAD;
        m_lean_speed *= DEGREE_TO_RAD;
    }

    if(const XMLNode *startup_node= root->getNode("startup"))
    {
        startup_node->get("time", &m_startup_times);
        startup_node->get("boost", &m_startup_boost);
    }

    if(m_kart_model)
        m_kart_model->loadInfo(*root);
}   // getAllData
Example #15
0
void MovementController::OnUpdate(DWORD const deltaMilliseconds)
{
	//if (m_bKey['Q'])
	//{
	//	// This code is a cheat to position the camera exactly in a given
	//	// spot so I can take screen shots!

	//	Mat4x4 camTranslate;
	//	D3DXMatrixTranslation(&m_matPosition, 8.847f, 7.055f, 11.618f);

	//	m_fTargetYaw = m_fYaw += -64.35f;
	//	m_fTargetPitch = m_fPitch = 28.57f;

	//	// Calculate the new rotation matrix from the camera
	//	// yaw and pitch.
	//	Mat4x4 matRot;
	//	D3DXMatrixRotationYawPitchRoll(&matRot, DEGREES_TO_RADIANS(m_fYaw), DEGREES_TO_RADIANS(m_fPitch), 0);

	//	// Create the new object-to-world matrix, and the
	//	// new world-to-object matrix. 
	//	D3DXMatrixMultiply(&m_matToWorld, &matRot, &m_matPosition);
	//	D3DXMatrixInverse(&m_matFromWorld, NULL, &m_matToWorld);

	//	m_object->VSetTransform(&m_matToWorld, &m_matFromWorld);
	//	return;
	//}

	bool bTranslating = false;
	Vec4 atWorld(0,0,0,0);
	Vec4 rightWorld(0,0,0,0);
	Vec4 upWorld(0,0,0,0);

	if (m_bKey['W'] || m_bKey['S'])
	{
		// In D3D, the "look at" default is always
		// the positive Z axis.
		Vec4 at = g_Forward4; 
		if (m_bKey['S'])
			at *= -1;

		// This will give us the "look at" vector 
		// in world space - we'll use that to move
		// the camera.
		atWorld = m_matToWorld.Xform(at);
		bTranslating = true;
	}

	if (m_bKey['A'] || m_bKey['D'])
	{
		// In D3D, the "right" default is always
		// the positive X axis.
		Vec4 right = g_Right4; 
		if (m_bKey['A'])
			right *= -1;

		// This will give us the "right" vector 
		// in world space - we'll use that to move
		// the camera
		rightWorld = m_matToWorld.Xform(right);
		bTranslating = true;
	}

	if (m_bKey[' '] || m_bKey['C'] || m_bKey['X'])
	{
		// In D3D, the "up" default is always
		// the positive Y axis.
		Vec4 up = g_Right4; 
		if (!m_bKey[' '])
			up *= -1;

		//Unlike strafing, Up is always up no matter
		//which way you are looking
		upWorld = up;
		bTranslating = true;
	}

	//Handling rotation as a result of mouse position
	{
		// The secret formula!!! Don't give it away!
		//If you are seeing this now, then you must be some kind of elite hacker!
		m_fYaw += (m_fTargetYaw - m_fYaw) * ( .35f );
		m_fTargetPitch = MAX(-90, MIN(90, m_fTargetPitch));
		m_fPitch += (m_fTargetPitch - m_fPitch) * ( .35f );

		// Calculate the new rotation matrix from the camera
		// yaw and pitch.
		Mat4x4 matRot;
		matRot.BuildYawPitchRoll(DEGREES_TO_RADIANS(-m_fYaw), DEGREES_TO_RADIANS(m_fPitch), 0);

		// Create the new object-to-world matrix, and the
		// new world-to-object matrix. 

		m_matToWorld = matRot * m_matPosition;
		m_matFromWorld = m_matToWorld.Inverse(); 
		m_object->VSetTransform(&m_matToWorld, &m_matFromWorld);
	}

	if (bTranslating)
	{
		float elapsedTime = (float)deltaMilliseconds / 1000.0f;

		Vec3 direction = atWorld + rightWorld + upWorld;
		direction.Normalize(); 

		// Ramp the acceleration by the elapsed time.
		float numberOfSeconds = 5.f;
		m_currentSpeed += m_maxSpeed * ( (elapsedTime*elapsedTime) / numberOfSeconds);
		if (m_currentSpeed > m_maxSpeed)
			m_currentSpeed = m_maxSpeed;

		direction *= m_currentSpeed;

		Vec3 pos = m_matPosition.GetPosition() + direction;
		m_matPosition.SetPosition(pos);
		m_matToWorld.SetPosition(pos);

		m_matFromWorld = m_matToWorld.Inverse();
		m_object->VSetTransform(&m_matToWorld, &m_matFromWorld);
	}
	else
	{
		m_currentSpeed = 0.0f;
	}
}
//---------------------------------------------------
void CGameRules::ProcessExplosionMaterialFX(const ExplosionInfo &explosionInfo)
{
	// if an effect was specified, don't use MFX
	if (explosionInfo.pParticleEffect)
		return;

	// impact stuff here
	SMFXRunTimeEffectParams params;
	params.soundSemantic = eSoundSemantic_Explosion;
	params.pos = params.decalPos = explosionInfo.pos;
	params.trg = 0;
	params.trgRenderNode = 0;

	Vec3 gravity;
	pe_params_buoyancy buoyancy;
	gEnv->pPhysicalWorld->CheckAreas(params.pos, gravity, &buoyancy);

	// 0 for water, 1 for air
	Vec3 pos=params.pos;
	params.inWater = (buoyancy.waterPlane.origin.z > params.pos.z) && (gEnv->p3DEngine->GetWaterLevel(&pos)>=params.pos.z);
	params.inZeroG = (gravity.len2() < 0.0001f);
	params.trgSurfaceId = 0;

	static const int objTypes = ent_all;    
	static const unsigned int flags = rwi_stop_at_pierceable|rwi_colltype_any;

	ray_hit ray;

	if (explosionInfo.impact)
	{
		params.dir[0] = explosionInfo.impact_velocity.normalized();
		params.normal = explosionInfo.impact_normal;

		if (gEnv->pPhysicalWorld->RayWorldIntersection(params.pos-params.dir[0]*0.0125f, params.dir[0]*0.25f, objTypes, flags, &ray, 1))
		{
			params.trgSurfaceId = ray.surface_idx;
			if (ray.pCollider->GetiForeignData()==PHYS_FOREIGN_ID_STATIC)
				params.trgRenderNode = (IRenderNode*)ray.pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC);
		}
	}
	else
	{
		params.dir[0] = gravity;
		params.normal = -gravity.normalized();

		if (gEnv->pPhysicalWorld->RayWorldIntersection(params.pos, gravity, objTypes, flags, &ray, 1))
		{
			params.trgSurfaceId = ray.surface_idx;
			if (ray.pCollider->GetiForeignData()==PHYS_FOREIGN_ID_STATIC)
				params.trgRenderNode = (IRenderNode*)ray.pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC);
		}
	}

	string effectClass = explosionInfo.effect_class;
	if (effectClass.empty())
		effectClass = "generic";

	string query = effectClass + "_explode";
	if(gEnv->p3DEngine->GetWaterLevel(&explosionInfo.pos)>explosionInfo.pos.z)
		query = query + "_underwater";

	IMaterialEffects* pMaterialEffects = gEnv->pGame->GetIGameFramework()->GetIMaterialEffects();
	TMFXEffectId effectId = pMaterialEffects->GetEffectId(query.c_str(), params.trgSurfaceId);

	if (effectId == InvalidEffectId)
		effectId = pMaterialEffects->GetEffectId(query.c_str(), pMaterialEffects->GetDefaultSurfaceIndex());

	if (effectId != InvalidEffectId)
		pMaterialEffects->ExecuteEffect(effectId, params);
}
//------------------------------------------------------------------------
float CGameRulesCommonDamageHandling::GetCollisionEnergy( const IEntity *pVictim, const CGameRules::SCollisionHitInfo& colHitInfo ) const
{
	float m1 = colHitInfo.target_mass;
	float m0 = 0.f;

	IPhysicalEntity *phys = pVictim->GetPhysics();
	if(phys)
	{
		pe_status_dynamics	dyn;
		phys->GetStatus(&dyn);
		m0 = dyn.mass;
	}

	IEntity *pOffender = gEnv->pEntitySystem->GetEntity(colHitInfo.targetId);
	bool bCollider = (pOffender || m1 > 0.001f);

	const bool debugColl = DebugCollisions();
	if (debugColl)
	{
		CryLog("GetCollisionEnergy %s (%.1f) <-> %s (%.1f)", pVictim?pVictim->GetName():"[no entity]", m0, pOffender?pOffender->GetName():"[no entity]", m1);
	}

	float v0Sq = 0.f, v1Sq = 0.f;

	if (bCollider)	// non-static
	{
		m0 = min(m0, m1);

		Vec3 v0normal, v1normal, vrel;
		Vec3 tempNormal = colHitInfo.normal;

		float v0dotN = colHitInfo.velocity.dot(colHitInfo.normal);
		v0normal = tempNormal.scale(v0dotN);

		float v1dotN = colHitInfo.target_velocity.dot(colHitInfo.normal);;  // "target" is the offender
		v1normal = tempNormal.scale(v1dotN);

		vrel = v0normal.sub(v1normal);
		float vrelSq = vrel.len2();

		v0Sq = min( sqr(v0dotN), vrelSq );
		v1Sq = min( sqr(v1dotN), vrelSq );

		if (debugColl)
		{
			IPersistantDebug* pPD = g_pGame->GetIGameFramework()->GetIPersistantDebug();

			pPD->Begin("CollDamage", false);
			pPD->AddSphere(colHitInfo.pos, 0.15f, Col_Red, 5.f);
			pPD->AddDirection(colHitInfo.pos, 1.5f, tempNormal.scale(sgn(v0dotN)), Col_Green, 5.f);
			pPD->AddDirection(colHitInfo.pos, 1.5f, tempNormal.scale(sgn(v1dotN)), Col_Red, 5.f);

			if ((v0Sq > 2*2) || (v1Sq > 2*2))
			{
				CryLog("normal velocities: rel %.1f, <%s> %.1f / <%s> %.1f", sqrt(vrelSq), pVictim?pVictim->GetName():"none", v0dotN, pOffender?pOffender->GetName():"none", v1dotN); 
				CryLog("target_type: %i, target_velocity: %.2f %.2f %.2f", colHitInfo.target_type, colHitInfo.target_velocity.x, colHitInfo.target_velocity.y, colHitInfo.target_velocity.z);
			}
		}
	}
	else
	{
		v0Sq = sqr(colHitInfo.velocity.dot(colHitInfo.normal));

		if (debugColl && v0Sq>5*5)
		{
			IPersistantDebug* pPD = g_pGame->GetIGameFramework()->GetIPersistantDebug();

			pPD->Begin("CollDamage", false);
			pPD->AddDirection(colHitInfo.pos, 1.5f, colHitInfo.normal, Col_Green, 5.f);
			string debugText;
			debugText.Format("z: %f", colHitInfo.velocity.z);
			pPD->Add2DText(debugText.c_str(), 1.5f, Col_White, 5.f);
		}
	}

	float colliderEnergyScale = 1.f;
	if (pVictim != NULL && pOffender != NULL)
	{
		if(IActor* pVictimActor = g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pVictim->GetId()))
		{
			colliderEnergyScale = !pVictimActor->IsPlayer() ?	GetAIPlayerAgainstColliderEnergyScale(*pOffender) :
																GetPlayerAgainstColliderEnergyScale(*pOffender);
			
			if (debugColl)
			{
				CryLog("colliderEnergyScale: %.1f", colliderEnergyScale);
			}
		}
	}

	const float energy0 = 0.5f * m0 * v0Sq;
	const float energy1 = 0.5f * m1 * v1Sq * colliderEnergyScale;

	return energy0 + energy1;
}
//------------------------------------------------------------------------
void CVehicleMovementVTOL::ProcessActions(const float deltaTime)
{
	FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );
	UpdateDamages(deltaTime);
	UpdateEngine(deltaTime);
	m_velDamp = 0.25f;
	m_playerControls.ProcessActions(deltaTime);
	Limit(m_forwardAction, -1.0f, 1.0f);
	Limit(m_strafeAction, -1.0f, 1.0f);
	m_actionYaw = 0.0f;
	Vec3 worldPos = m_pEntity->GetWorldPos();
	IPhysicalEntity *pPhysics = GetPhysics();
	// get the current state
	// roll pitch + yaw
	Matrix34 worldTM = m_pRotorPart ? m_pRotorPart->GetWorldTM() : m_pEntity->GetWorldTM();
	//	if (m_pRotorPart)
	//		worldTM = m_pRotorPart->GetWorldTM();
	//	else
	//		worldTM = m_pEntity->GetWorldTM();
	Vec3 specialPos = worldTM.GetTranslation();
	Ang3 angles = Ang3::GetAnglesXYZ(Matrix33(worldTM));
	Matrix33 tm;
	tm.SetRotationXYZ((angles));
	// +ve pitch means nose up
	const float &currentPitch = angles.x;
	// +ve roll means to the left
	const float &currentRoll = angles.y;
	// +ve direction mean rotation anti-clockwise about the z axis - 0 means along y
	float currentDir = angles.z;
	const float maxPitchAngle = 60.0f;
	float pitchDeg = RAD2DEG(currentPitch);

	if (pitchDeg >= (maxPitchAngle * 0.75f))
	{
		float mult = pitchDeg / (maxPitchAngle);

		if (mult > 1.0f && m_desiredPitch < 0.0f)
		{
			m_desiredPitch *= 0.0f;
			m_actionPitch *= 0.0f;
			m_desiredPitch += 0.2f * mult;
		}
		else if (m_desiredPitch < 0.0f)
		{
			m_desiredPitch *= (1.0f - mult);
			m_desiredPitch += 0.05f;
		}
	}
	else if (pitchDeg <= (-maxPitchAngle * 0.75f))
	{
		float mult = abs(pitchDeg) / (maxPitchAngle);

		if (mult > 1.0f && m_desiredPitch > 0.0f)
		{
			m_desiredPitch *= 0.0f;
			m_actionPitch *= 0.0f;
			m_desiredPitch += 0.2f * mult;
		}
		else if (m_desiredPitch > 0.0f)
		{
			m_desiredPitch *= (1.0f - mult);
			m_desiredPitch -= 0.05f;
		}
	}

	if (currentRoll >= DEG2RAD(m_maxRollAngle * 0.7f) && m_desiredRoll > 0.001f)
	{
		float r = currentRoll / DEG2RAD(m_maxRollAngle);
		r = min(1.0f, r * 1.0f);
		r = 1.0f - r;
		m_desiredRoll *= r;
		m_desiredRoll = min(1.0f, m_desiredRoll);
	}
	else if (currentRoll <= DEG2RAD(-m_maxRollAngle * 0.7f) && m_desiredRoll < 0.001f)
	{
		float r = abs(currentRoll) / DEG2RAD(m_maxRollAngle);
		r = min(1.0f, r * 1.0f);
		r = 1.0f - r;
		m_desiredRoll *= r;
		m_desiredRoll = max(-1.0f, m_desiredRoll);
	}

	Vec3 currentFwdDir2D = m_currentFwdDir;
	currentFwdDir2D.z = 0.0f;
	currentFwdDir2D.NormalizeSafe();
	Vec3 currentLeftDir2D(-currentFwdDir2D.y, currentFwdDir2D.x, 0.0f);
	Vec3 currentVel = m_PhysDyn.v;
	Vec3 currentVel2D = currentVel;
	currentVel2D.z = 0.0f;
	float currentHeight = worldPos.z;
	float currentFwdSpeed = currentVel.Dot(currentFwdDir2D);
	ProcessActions_AdjustActions(deltaTime);
	float inputMult = m_basicSpeedFraction;
	// desired things
	float turnDecreaseScale = m_yawDecreaseWithSpeed / (m_yawDecreaseWithSpeed + fabs(currentFwdSpeed));
	Vec3 desired_vel2D =
		currentFwdDir2D * m_forwardAction * m_maxFwdSpeed * inputMult +
		currentLeftDir2D * m_strafeAction * m_maxLeftSpeed * inputMult;
	// calculate the angle changes
	Vec3 desiredVelChange2D = desired_vel2D - currentVel2D;
	float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength();
	Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle);
	float goal = abs(m_desiredPitch) + abs(m_desiredRoll);
	goal *= 1.5f;
	Interpolate(m_playerAcceleration, goal, 0.25f, deltaTime);
	Limit(m_playerAcceleration, 0.0f, 5.0f);

	//static float g_angleLift = 4.0f;

	if (abs(m_liftAction) > 0.001f && abs(m_forwardAction) < 0.001)
	{
		//		float pitch = RAD2DEG(currentPitch);
		if (m_liftPitchAngle < 0.0f && m_liftAction > 0.0f)
		{
			m_liftPitchAngle = 0.0f;
		}
		else if (m_liftPitchAngle > 0.0f && m_liftAction < 0.0f)
		{
			m_liftPitchAngle = 0.0f;
		}

		Interpolate(m_liftPitchAngle, 1.25f * m_liftAction, 0.75f, deltaTime);

		if (m_liftPitchAngle < 1.0f && m_liftPitchAngle > -1.0f)
		{
			m_desiredPitch += 0.05f * m_liftAction;
		}
	}
	else if (m_liftAction < 0.001f && abs(m_liftPitchAngle) > 0.001)
	{
		Interpolate(m_liftPitchAngle, 0.0f, 1.0f, deltaTime);
		m_desiredPitch += 0.05f * -m_liftPitchAngle;
	}

	/* todo
	else if (m_liftAction < -0.001f)
	{
		m_desiredPitch += min(0.0f, (DEG2RAD(-5.0f) - currentPitch)) * 0.5f * m_liftAction;
	}*/

	if (!iszero(m_desiredPitch))
	{
		m_actionPitch -= m_desiredPitch * m_pitchInputConst;
		Limit(m_actionPitch, -m_maxYawRate, m_maxYawRate);
	}

	float rollAccel = 1.0f;

	if (abs(currentRoll + m_desiredRoll) < abs(currentRoll))
	{
		rollAccel *= 1.25f;
	}

	m_actionRoll += m_pitchActionPerTilt * m_desiredRoll * rollAccel * (m_playerAcceleration + 1.0f);
	Limit(m_actionRoll, -10.0f, 10.0f);
	Limit(m_actionPitch, -10.0f, 10.0f);

	// roll as we turn
	if (!m_strafeAction)
	{
		m_actionYaw += m_yawPerRoll * currentRoll;
	}

	if (abs(m_strafeAction) > 0.001f)
	{
		float side = 0.0f;
		side = min(1.0f, max(-1.0f, m_strafeAction));
		float roll = DEG2RAD(m_extraRollForTurn * 0.25f * side) - (currentRoll);
		m_actionRoll += max(0.0f, abs(roll)) * side * 1.0f;
	}

	float relaxRollTolerance = 0.0f;

	if (abs(m_turnAction) > 0.01f || abs(m_PhysDyn.w.z) > DEG2RAD(3.0f))
	{
		m_actionYaw += -m_turnAction * m_yawInputConst * GetDamageMult();
		float side = 0.0f;

		if (abs(m_turnAction) > 0.01f)
		{
			side = min(1.0f, max(-1.0f, m_turnAction));
		}

		float roll = DEG2RAD(m_extraRollForTurn * side) - (currentRoll);
		m_actionRoll += max(0.0f, abs(roll)) * side * m_rollForTurnForce;
		roll *= max(1.0f, abs(m_PhysDyn.w.z));
		m_actionRoll += roll;
		Limit(m_actionYaw, -m_maxYawRate, m_maxYawRate);
	}

	m_desiredDir = currentDir;
	m_lastDir = currentDir;
	float boost = Boosting() ? m_boostMult : 1.0f;
	float liftActionMax = 1.0f;

	if (m_pAltitudeLimitVar)
	{
		float altitudeLimit = m_pAltitudeLimitVar->GetFVal();

		if (!iszero(altitudeLimit))
		{
			float altitudeLowerOffset;

			if (m_pAltitudeLimitLowerOffsetVar)
			{
				float r = 1.0f - min(1.0f, max(0.0f, m_pAltitudeLimitLowerOffsetVar->GetFVal()));
				altitudeLowerOffset = r * altitudeLimit;
			}
			else
			{
				altitudeLowerOffset = altitudeLimit;
			}

			float mult = 1.0f;

			if (currentHeight >= altitudeLimit)
			{
				if (m_liftAction > 0.f)
				{
					mult = 0.0f;
				}
			}
			else if (currentHeight >= altitudeLowerOffset)
			{
				float zone = altitudeLimit - altitudeLowerOffset;
				mult = (altitudeLimit - currentHeight) / (zone);
			}

			m_liftAction *= mult;

			if (currentPitch > DEG2RAD(0.0f))
			{
				if (m_forwardAction > 0.0f)
				{
					m_forwardAction *= mult;
				}

				if (m_actionPitch > 0.0f)
				{
					m_actionPitch *= mult;
					m_actionPitch += -currentPitch;
				}
			}

			m_desiredHeight = min(altitudeLowerOffset, currentHeight);
		}
	}
	else
	{
		m_desiredHeight = currentHeight;
	}

	if (abs(m_liftAction) > 0.001f)
	{
		m_liftAction = min(liftActionMax, max(-0.2f, m_liftAction));
		m_hoveringPower = (m_powerInputConst * m_liftAction) * boost;
		m_noHoveringTimer = 0.0f;
	}
	else if (!m_isTouchingGround)
	{
		if (m_noHoveringTimer <= 0.0f)
		{
			float gravity;
			pe_simulation_params paramsSim;

			if (pPhysics->GetParams(&paramsSim))
			{
				gravity = abs(paramsSim.gravity.z);
			}
			else
			{
				gravity = 9.2f;
			}

			float upDirZ = m_workingUpDir.z;

			if (abs(m_forwardAction) > 0.01 && upDirZ > 0.0f)
			{
				upDirZ = 1.0f;
			}
			else if (upDirZ > 0.8f)
			{
				upDirZ = 1.0f;
			}

			float upPower = upDirZ;
			upPower -= min(1.0f, abs(m_forwardAction) * abs(angles.x));
			float turbulenceMult = 1.0f - min(m_turbulenceMultMax, m_turbulence);
			Vec3 &impulse = m_control.impulse;
			impulse += Vec3(0.0f, 0.0f, upPower) * gravity * turbulenceMult * GetDamageMult();
			impulse.z -= m_PhysDyn.v.z * turbulenceMult;
		}
		else
		{
			m_noHoveringTimer -= deltaTime;
		}
	}

	if (m_pStabilizeVTOL)
	{
		float stabilizeTime = m_pStabilizeVTOL->GetFVal();

		if (stabilizeTime > 0.0f)
		{
			if (m_relaxTimer < 6.0f)
			{
				m_relaxTimer += deltaTime;
			}
			else
			{
				float r = currentRoll - relaxRollTolerance;
				r = min(1.0f, max(-1.0f, r));
				m_actionRoll += -r * m_relaxForce * (m_relaxTimer / 6.0f);
			}
		}
	}

	if (m_netActionSync.PublishActions( CNetworkMovementHelicopter(this) ))
	{
		m_pVehicle->GetGameObject()->ChangedNetworkState(eEA_GameClientDynamic);
	}
}
bool CIntersectionAssistanceUnit::IsPositionWithinAcceptedLimits(const Vec3& vTestPos, const Vec3& vOrigin, const float fTolerance) const
{
	const Vec3 vDiff = vTestPos - vOrigin; 
	return (vDiff.GetLengthSquared() < (fTolerance * fTolerance)); 
}
//////////////////////////////////////////////////////////////////////////
// NOTE: This function must be thread-safe. Before adding stuff contact MarcoC.
void CVehicleMovementVTOL::ProcessAI(const float deltaTime)
{
	FUNCTION_PROFILER( GetISystem(), PROFILE_GAME );

	if (!m_isVTOLMovement)
	{
		CVehicleMovementHelicopter::ProcessAI(deltaTime);
		return;
	}

	m_velDamp = 0.15f;
	const float maxDirChange = 15.0f;

	// it's useless to progress further if the engine has yet to be turned on
	if (!m_isEnginePowered)
	{
		return;
	}

	m_movementAction.Clear();
	m_movementAction.isAI = true;
	ResetActions();
	// Our current state
	const Vec3 worldPos =  m_PhysPos.pos;
	const Matrix33 worldMat( m_PhysPos.q);
	Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat);
	const Vec3 currentVel = m_PhysDyn.v;
	const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f);
	// +ve direction mean rotation anti-clocwise about the z axis - 0 means along y
	float currentDir = worldAngles.z;
	// to avoid singularity
	const Vec3 vWorldDir = worldMat * FORWARD_DIRECTION;
	const Vec3 vWorldDir2D =  Vec3( vWorldDir.x,  vWorldDir.y, 0.0f ).GetNormalizedSafe();
	// Our inputs
	const float desiredSpeed = m_aiRequest.HasDesiredSpeed() ? m_aiRequest.GetDesiredSpeed() : 0.0f;
	const Vec3 desiredMoveDir = m_aiRequest.HasMoveTarget() ? (m_aiRequest.GetMoveTarget() - worldPos).GetNormalizedSafe() : vWorldDir;
	const Vec3 desiredMoveDir2D = Vec3(desiredMoveDir.x, desiredMoveDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D);
	const Vec3 desiredVel = desiredMoveDir * desiredSpeed;
	const Vec3 desiredVel2D(desiredVel.x, desiredVel.y, 0.0f);
	const Vec3 desiredLookDir = m_aiRequest.HasLookTarget() ? (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe() : desiredMoveDir;
	const Vec3 desiredLookDir2D = Vec3(desiredLookDir.x, desiredLookDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D);
	// Calculate the desired 2D velocity change
	Vec3 desiredVelChange2D = desiredVel2D - currentVel2D;
	float velChangeLength = desiredVelChange2D.GetLength2D();
	bool isLandingMode = false;

	if (m_pLandingGears && m_pLandingGears->AreLandingGearsOpen())
	{
		isLandingMode = true;
	}

	bool isHorizontal = (desiredSpeed >= 5.0f) && (desiredMoveDir.GetLength2D() > desiredMoveDir.z);
	float desiredPitch = 0.0f;
	float desiredRoll = 0.0f;
	float desiredDir = atan2f(-desiredLookDir2D.x, desiredLookDir2D.y);

	while (currentDir < desiredDir - gf_PI)
	{
		currentDir += 2.0f * gf_PI;
	}

	while (currentDir > desiredDir + gf_PI)
	{
		currentDir -= 2.0f * gf_PI;
	}

	float diffDir = (desiredDir - currentDir);
	m_actionYaw = diffDir * m_yawInputConst;
	m_actionYaw += m_yawInputDamping * (currentDir - m_lastDir) / deltaTime;
	m_lastDir = currentDir;

	if (isHorizontal && !isLandingMode)
	{
		float desiredFwdSpeed = desiredVelChange2D.GetLength();
		desiredFwdSpeed *= min(1.0f, diffDir / DEG2RAD(maxDirChange));

		if (!iszero(desiredFwdSpeed))
		{
			const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f);
			const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis;
			m_forwardAction = m_fwdPID.Update(currentVel.y, desiredLocalTiltAxis.GetLength(), -1.0f, 1.0f);
			float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength();
			Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle);

			if (desiredTiltAngle > 0.0001f)
			{
				const Vec3 desiredWorldTiltAxis2 = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe();
				const Vec3 desiredLocalTiltAxis2 = worldMat.GetTransposed() * desiredWorldTiltAxis2;
				Vec3 vVelLocal = worldMat.GetTransposed() * desiredVel;
				vVelLocal.NormalizeSafe();
				float dotup = vVelLocal.Dot(Vec3( 0.0f, 0.0f, 1.0f ) );
				float currentSpeed = currentVel.GetLength();
				desiredPitch = dotup * currentSpeed / 100.0f;
				desiredRoll = desiredTiltAngle * desiredLocalTiltAxis2.y * currentSpeed / 30.0f;
			}
		}
	}
	else
	{
		float desiredTiltAngle = m_tiltPerVelDifference * desiredVelChange2D.GetLength();
		Limit(desiredTiltAngle, -m_maxTiltAngle, m_maxTiltAngle);

		if (desiredTiltAngle > 0.0001f)
		{
			const Vec3 desiredWorldTiltAxis = Vec3(-desiredVelChange2D.y, desiredVelChange2D.x, 0.0f).GetNormalizedSafe();
			const Vec3 desiredLocalTiltAxis = worldMat.GetTransposed() * desiredWorldTiltAxis;
			desiredPitch = desiredTiltAngle * desiredLocalTiltAxis.x;
			desiredRoll = desiredTiltAngle * desiredLocalTiltAxis.y;
		}
	}

	float currentHeight = m_PhysPos.pos.z;

	if ( m_aiRequest.HasMoveTarget() )
	{
		m_hoveringPower = m_powerPID.Update(currentVel.z, desiredVel.z, -1.0f, 4.0f);

		//m_hoveringPower = (m_desiredHeight - currentHeight) * m_powerInputConst;
		//m_hoveringPower += m_powerInputDamping * (currentHeight - m_lastHeight) / deltaTime;

		if (isHorizontal)
		{
			if (desiredMoveDir.z > 0.6f || desiredMoveDir.z < -0.85f)
			{
				desiredPitch = max(-0.5f, min(0.5f, desiredMoveDir.z)) * DEG2RAD(35.0f);
				m_forwardAction += abs(desiredMoveDir.z);
			}

			m_liftAction = min(2.0f, max(m_liftAction, m_hoveringPower * 2.0f));
		}
		else
		{
			m_liftAction = 0.0f;
		}
	}
	else
	{
		// to keep hovering at the same place
		m_hoveringPower = m_powerPID.Update(currentVel.z, m_desiredHeight - currentHeight, -1.0f, 1.0f);
		m_liftAction = 0.0f;

		if (m_pVehicle->GetAltitude() > 10.0f)	//TODO: this line is not MTSafe
		{
			m_liftAction = m_forwardAction;
		}
	}

	m_actionPitch += m_pitchActionPerTilt * (desiredPitch - worldAngles.x);
	m_actionRoll += m_pitchActionPerTilt * (desiredRoll - worldAngles.y);
	Limit(m_actionPitch, -1.0f, 1.0f);
	Limit(m_actionRoll, -1.0f, 1.0f);
	Limit(m_actionYaw, -1.0f, 1.0f);

	if (m_horizontal > 0.0001f)
	{
		m_desiredHeight = m_PhysPos.pos.z;
	}

	Limit(m_forwardAction, -1.0f, 1.0f);
}
Example #21
0
    /** Returns the 2d coordinates of a point when drawn on the mini map
     *  texture.
     *  \param xyz Coordinates of the point to map.
     *  \param draw_at The coordinates in pixel on the mini map of the point,
     *         only the first two coordinates will be used.
     */
void QuadGraph::mapPoint2MiniMap(const Vec3 &xyz,Vec3 *draw_at) const
{
    draw_at->setX((xyz.getX()-m_min_coord.getX())*m_scaling);
    draw_at->setY((xyz.getZ()-m_min_coord.getZ())*m_scaling);

}   // mapPoint
Example #22
0
void 
OpenSteer::
SphereObstacle::
findIntersectionWithVehiclePath (const AbstractVehicle& vehicle,
                                 PathIntersection& pi) const
{
    // This routine is based on the Paul Bourke's derivation in:
    //   Intersection of a Line and a Sphere (or circle)
    //   http://www.swin.edu.au/astronomy/pbourke/geometry/sphereline/
    // But the computation is done in the vehicle's local space, so
    // the line in question is the Z (Forward) axis of the space which
    // simplifies some of the calculations.

    float b, c, d, p, q, s;
    Vec3 lc;

    // initialize pathIntersection object to "no intersection found"
    pi.intersect = false;

    // find sphere's "local center" (lc) in the vehicle's coordinate space
    lc = vehicle.localizePosition (center);
    pi.vehicleOutside = lc.length () > radius;

	// if obstacle is seen from inside, but vehicle is outside, must avoid
	// (noticed once a vehicle got outside it ignored the obstacle 2008-5-20)
	if (pi.vehicleOutside && (seenFrom () == inside))
	{
		pi.intersect = true;
		pi.distance = 0.0f;
		pi.steerHint = (center - vehicle.position()).normalize();
		return;
	}
	
    // compute line-sphere intersection parameters
    const float r = radius + vehicle.radius();
    b = -2 * lc.z;
    c = square (lc.x) + square (lc.y) + square (lc.z) - square (r);
    d = (b * b) - (4 * c);

    // when the path does not intersect the sphere
    if (d < 0) return;

    // otherwise, the path intersects the sphere in two points with
    // parametric coordinates of "p" and "q".  (If "d" is zero the two
    // points are coincident, the path is tangent)
    s = sqrtXXX (d);
    p = (-b + s) / 2;
    q = (-b - s) / 2;

    // both intersections are behind us, so no potential collisions
    if ((p < 0) && (q < 0)) return; 

    // at least one intersection is in front, so intersects our forward
    // path
    pi.intersect = true;
    pi.obstacle = this;
    pi.distance =
        ((p > 0) && (q > 0)) ?
        // both intersections are in front of us, find nearest one
        ((p < q) ? p : q) :
        // otherwise one is ahead and one is behind: we are INSIDE obstacle
        (seenFrom () == outside ?
         // inside a solid obstacle, so distance to obstacle is zero
         0.0f :
         // hollow obstacle (or "both"), pick point that is in front
         ((p > 0) ? p : q));
    pi.surfacePoint =
        vehicle.position() + (vehicle.forward() * pi.distance);
    pi.surfaceNormal = (pi.surfacePoint-center).normalize();
    switch (seenFrom ())
    {
    case outside:
        pi.steerHint = pi.surfaceNormal;
        break;
    case inside:
        pi.steerHint = -pi.surfaceNormal;
        break;
    case both:
        pi.steerHint = pi.surfaceNormal * (pi.vehicleOutside ? 1.0f : -1.0f);
        break;
    }
}
Example #23
0
/** Takes a snapshot of the driveline quads so they can be used as minimap.
 */
void QuadGraph::makeMiniMap(const core::dimension2du &dimension,
                            const std::string &name,
                            const video::SColor &fill_color,
                            video::ITexture** oldRttMinimap,
                            FrameBuffer** newRttMinimap)
{
    const SColor oldClearColor = World::getWorld()->getClearColor();
    World::getWorld()->setClearbackBufferColor(SColor(0, 255, 255, 255));
    World::getWorld()->forceFogDisabled(true);
    *oldRttMinimap = NULL;
    *newRttMinimap = NULL;

    RTT* newRttProvider = NULL;
    IrrDriver::RTTProvider* oldRttProvider = NULL;
    if (irr_driver->isGLSL())
    {
        newRttProvider = new RTT(dimension.Width, dimension.Height);
    }
    else
    {
        oldRttProvider = new IrrDriver::RTTProvider(dimension, name, true);
    }

    irr_driver->getSceneManager()->setAmbientLight(video::SColor(255, 255, 255, 255));

    video::SColor red(128, 255, 0, 0);
    createMesh(/*show_invisible part of the track*/ false,
               /*enable_transparency*/ false,
               /*track_color*/    &fill_color,
               /*lap line color*/  &red                       );

    m_node = irr_driver->addMesh(m_mesh);
#ifdef DEBUG
    m_node->setName("minimap-mesh");
#endif

    m_node->setAutomaticCulling(0);
    m_node->setMaterialFlag(video::EMF_LIGHTING, false);

    // Add the camera:
    // ---------------
    scene::ICameraSceneNode *camera = irr_driver->addCameraSceneNode();
    Vec3 bb_min, bb_max;
    QuadSet::get()->getBoundingBox(&bb_min, &bb_max);
    Vec3 center = (bb_max+bb_min)*0.5f;

    float dx = bb_max.getX()-bb_min.getX();
    float dz = bb_max.getZ()-bb_min.getZ();

    // Set the scaling correctly. Also the center point (which is used
    // as the camera position) needs to be adjusted: the track must
    // be aligned to the left/top of the texture which is used (otherwise
    // mapPoint2MiniMap doesn't work), so adjust the camera position
    // that the track is properly aligned (view from the side):
    //          c        camera
    //         / \       .
    //        /   \     <--- camera angle
    //       /     \     .
    //      {  [-]  }   <--- track flat (viewed from the side)
    // If [-] is the shorter side of the track, then the camera will
    // actually render the area in { } - which is the length of the
    // longer side of the track.
    // To align the [-] side to the left, the camera must be moved
    // the distance betwwen '{' and '[' to the right. This distance
    // is exacly (longer_side - shorter_side) / 2.
    // So, adjust the center point by this amount:
    if(dz > dx)
    {
        center.setX(center.getX() + (dz-dx)*0.5f);
        m_scaling = dimension.Width / dz;
    }
    else
    {
        center.setZ(center.getZ() + (dx-dz)*0.5f);
        m_scaling = dimension.Width / dx;
    }

    float range = (dx>dz) ? dx : dz;

    core::matrix4 projection;
    projection.buildProjectionMatrixOrthoLH(range /* width */,
                                            range /* height */,
                                            -1, bb_max.getY()-bb_min.getY()+1);
    camera->setProjectionMatrix(projection, true);

    irr_driver->suppressSkyBox();
    irr_driver->clearLights();

    // Adjust Y position by +1 for max, -1 for min - this helps in case that
    // the maximum Y coordinate is negative (otherwise the minimap is mirrored)
    // and avoids problems for tracks which have a flat (max Y = min Y) minimap.
    camera->setPosition(core::vector3df(center.getX(), bb_min.getY() + 1.0f, center.getZ()));
    //camera->setPosition(core::vector3df(center.getX() - 5.0f, bb_min.getY() - 1 - 5.0f, center.getZ() - 15.0f));
    camera->setUpVector(core::vector3df(0, 0, 1));
    camera->setTarget(core::vector3df(center.getX(),bb_min.getY()-1,center.getZ()));
    //camera->setAspectRatio(1.0f);
    camera->updateAbsolutePosition();

    video::ITexture* texture = NULL;
    FrameBuffer* frame_buffer = NULL;

    if (irr_driver->isGLSL())
    {
        frame_buffer = newRttProvider->render(camera, GUIEngine::getLatestDt());

        // TODO: leak
        //delete newRttProvider;
    }
    else
    {
        texture = oldRttProvider->renderToTexture();
        delete oldRttProvider;
    }

    cleanupDebugMesh();
    irr_driver->removeCameraSceneNode(camera);
    m_min_coord = bb_min;


    if (texture == NULL && frame_buffer == NULL)
    {
        Log::error("Quad Graph", "[makeMiniMap] WARNING: RTT does not appear to work,"
                        "mini-map will not be available.");
    }

    *oldRttMinimap = texture;
    *newRttMinimap = frame_buffer;
    World::getWorld()->setClearbackBufferColor(oldClearColor);
    World::getWorld()->forceFogDisabled(false);
}   // makeMiniMap
Example #24
0
//void testvec(Vec3& a)
//{
	//a.print("inside testvec Vec3&, a= ");
//}
void testvec(Vec3 a)
{
	a.print("inside testvec Vec3, a= ");
}
//-----------------------------------------------------------------------
void PUBillboardChain::updateVertexBuffer(const Mat4 &camMat)
{
    setupBuffers();

    // The contents of the vertex buffer are correct if they are not dirty
    // and the camera used to build the vertex buffer is still the current 
    // camera.
    if (!_vertexContentDirty)
        return;

    VertexInfo vi = {Vec3(0.0f, 0.0f, 0.0f), Vec2(0.0f, 0.0f), Vec4::ONE};
    _vertices.assign(_vertices.size(), vi);
    //HardwareVertexBufferSharedPtr pBuffer =
    //	_vertexData->vertexBufferBinding->getBuffer(0);
    //void* pBufferStart = pBuffer->lock(HardwareBuffer::HBL_DISCARD);

    //const Vector3& camPos = cam->getDerivedPosition();
    //Vector3 eyePos = mParentNode->_getDerivedOrientation().Inverse() *
    //	(camPos - mParentNode->_getDerivedPosition()) / mParentNode->_getDerivedScale();

    Vec3 eyePos(camMat.m[12], camMat.m[13], camMat.m[14]);

    Vec3 chainTangent;
    for (ChainSegmentList::iterator segi = _chainSegmentList.begin();
        segi != _chainSegmentList.end(); ++segi)
    {
        ChainSegment& seg = *segi;

        // Skip 0 or 1 element segment counts
        if (seg.head != SEGMENT_EMPTY && seg.head != seg.tail)
        {
            size_t laste = seg.head;
            for (size_t e = seg.head; ; ++e) // until break
            {
                // Wrap forwards
                if (e == _maxElementsPerChain)
                    e = 0;

                Element& elem = _chainElementList[e + seg.start];
                CCASSERT (((e + seg.start) * 2) < 65536, "Too many elements!");
                unsigned short vertexIndex = static_cast<unsigned short>((e + seg.start) * 2);
                //// Determine base pointer to vertex #1
                //void* pBase = static_cast<void*>(
                //	static_cast<char*>(pBufferStart) +
                //	pBuffer->getVertexSize() * baseIdx);

                // Get index of next item
                size_t nexte = e + 1;
                if (nexte == _maxElementsPerChain)
                    nexte = 0;

                if (e == seg.head)
                {
                    // No laste, use next item
                    chainTangent = _chainElementList[nexte + seg.start].position - elem.position;
                }
                else if (e == seg.tail)
                {
                    // No nexte, use only last item
                    chainTangent = elem.position - _chainElementList[laste + seg.start].position;
                }
                else
                {
                    // A mid position, use tangent across both prev and next
                    chainTangent = _chainElementList[nexte + seg.start].position - _chainElementList[laste + seg.start].position;

                }

                Vec3 vP1ToEye;

                //if( _faceCamera )
                    vP1ToEye = eyePos - elem.position;
                //else
                //	vP1ToEye = elem.orientation * _normalBase;

                Vec3 vPerpendicular;
                Vec3::cross(chainTangent, vP1ToEye, &vPerpendicular);
                vPerpendicular.normalize();
                vPerpendicular *= (elem.width * 0.5f);

                Vec3 pos0 = elem.position - vPerpendicular;
                Vec3 pos1 = elem.position + vPerpendicular;

                //float* pFloat = static_cast<float*>(pBase);
                //// pos1
                //*pFloat++ = pos0.x;
                //*pFloat++ = pos0.y;
                //*pFloat++ = pos0.z;
                _vertices[vertexIndex + 0].position = pos0;


                //pBase = static_cast<void*>(pFloat);

                if (_useVertexColour)
                {
                    //RGBA* pCol = static_cast<RGBA*>(pBase);
                    //Root::getSingleton().convertColourValue(elem.colour, pCol);
                    //pCol++;
                    //pBase = static_cast<void*>(pCol);
                    _vertices[vertexIndex + 0].color = elem.color;
                }

                if (_useTexCoords)
                {
                    //pFloat = static_cast<float*>(pBase);
                    if (_texCoordDir == TCD_U)
                    {
                        //*pFloat++ = elem.texCoord;
                        //*pFloat++ = _otherTexCoordRange[0];
                        _vertices[vertexIndex + 0].uv.x = elem.texCoord;
                        _vertices[vertexIndex + 0].uv.y = _otherTexCoordRange[0];
                    }
                    else
                    {
                        //*pFloat++ = _otherTexCoordRange[0];
                        //*pFloat++ = elem.texCoord;
                        _vertices[vertexIndex + 0].uv.x = _otherTexCoordRange[0];
                        _vertices[vertexIndex + 0].uv.y = elem.texCoord;
                    }
                    //pBase = static_cast<void*>(pFloat);
                }

                // pos2
                //pFloat = static_cast<float*>(pBase);
                //*pFloat++ = pos1.x;
                //*pFloat++ = pos1.y;
                //*pFloat++ = pos1.z;
                //pBase = static_cast<void*>(pFloat);
                _vertices[vertexIndex + 1].position = pos1;

                if (_useVertexColour)
                {
                    //RGBA* pCol = static_cast<RGBA*>(pBase);
                    //Root::getSingleton().convertColourValue(elem.colour, pCol);
                    //pCol++;
                    //pBase = static_cast<void*>(pCol);
                    _vertices[vertexIndex + 1].color = elem.color;
                }

                if (_useTexCoords)
                {
                    //pFloat = static_cast<float*>(pBase);
                    if (_texCoordDir == TCD_U)
                    {
                        //*pFloat++ = elem.texCoord;
                        //*pFloat++ = _otherTexCoordRange[1];
                        _vertices[vertexIndex + 1].uv.x = elem.texCoord;
                        _vertices[vertexIndex + 1].uv.y = _otherTexCoordRange[1];
                    }
                    else
                    {
                        //*pFloat++ = _otherTexCoordRange[1];
                        //*pFloat++ = elem.texCoord;
                        _vertices[vertexIndex + 1].uv.x = _otherTexCoordRange[1];
                        _vertices[vertexIndex + 1].uv.y = elem.texCoord;
                    }
                }

                if (e == seg.tail)
                    break; // last one

                laste = e;
                //vertexIndex += 2;
            } // element
        } // segment valid?

    } // each segment


    _vertexBuffer->updateVertices(&_vertices[0], (int)_vertices.size(), 0);;
    //pBuffer->unlock();
    //_vertexCameraUsed = cam;
    _vertexContentDirty = false;

}
Example #26
0
Vec3::Vec3(Vec3& vec)
{
    this->vec[0] = vec.x();
    this->vec[1] = vec.y();
    this->vec[2] = vec.z();
}
Example #27
0
	bool TMMesh::Normalize()
    {
        size_t nV = m_vertices.GetSize();
		if (nV == 0)
		{
			return false;
		}
        m_barycenter = m_vertices.GetHead()->GetData().m_pos;
		Vec3<Real> min = m_barycenter;
		Vec3<Real> max = m_barycenter;
		Real x, y, z;
        for(size_t v = 1; v < nV; v++)
        {
			m_barycenter +=  m_vertices.GetHead()->GetData().m_pos;
            x = m_vertices.GetHead()->GetData().m_pos.X();
            y = m_vertices.GetHead()->GetData().m_pos.Y();
            z = m_vertices.GetHead()->GetData().m_pos.Z();
            if ( x < min.X()) min.X() = x;
			else if ( x > max.X()) max.X() = x;
            if ( y < min.Y()) min.Y() = y;
			else if ( y > max.Y()) max.Y() = y;
            if ( z < min.Z()) min.Z() = z;
			else if ( z > max.Z()) max.Z() = z;
			m_vertices.Next();
        }
		m_barycenter /= static_cast<Real>(nV);
        m_diag = static_cast<Real>(0.001 * (max-min).GetNorm());
        const Real invDiag = static_cast<Real>(1.0 / m_diag);
		if (m_diag != 0.0)
		{
	        for(size_t v = 0; v < nV; v++)
		    {
				m_vertices.GetHead()->GetData().m_pos = (m_vertices.GetHead()->GetData().m_pos - m_barycenter) * invDiag;
				m_vertices.Next();
		    }
		}
		return true;
	}
	virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo )
	{
		switch (event)
		{
		case eFE_Initialize:
			break;
		case eFE_Activate:
			if (IsPortActive(pActInfo, EIP_Trigger))
			{
				const Vec3& dir = GetPortVec3(pActInfo, EIP_LimitDir);
				const bool localSpace = GetPortBool(pActInfo, EIP_LocalSpace);
				const float rangeH = GetPortFloat(pActInfo, EIP_LimitYaw);
				const float rangeV = GetPortFloat(pActInfo, EIP_LimitPitch);
				CActor *pPlayerActor = static_cast<CActor *>(gEnv->pGame->GetIGameFramework()->GetClientActor());
				if (pPlayerActor)
				{
					CPlayer::SStagingParams stagingParams;
					CPlayer* pPlayer = static_cast<CPlayer*> (pPlayerActor);
					if (dir.len2()>0.01f)
					{
						if (localSpace)
						{
							const Quat& viewQuat = pPlayer->GetViewQuatFinal(); // WC
							Vec3 dirWC = viewQuat * dir;
							stagingParams.vLimitDir = dirWC.GetNormalizedSafe(ZERO);
						}
						else
							stagingParams.vLimitDir = dir.GetNormalizedSafe(ZERO);
					}

					stagingParams.vLimitRangeH = DEG2RAD(rangeH);
					stagingParams.vLimitRangeV = DEG2RAD(rangeV);
					stagingParams.bLocked = GetPortBool(pActInfo, EIP_Lock);
					int stance = GetPortInt(pActInfo, EIP_Stance);
					if (stance < STANCE_NULL || stance >= STANCE_LAST)
					{
						stance = STANCE_NULL;
						GameWarning("[flow] PlayerStaging: stance=%d invalid", stance);
					}
					stagingParams.stance = (EStance) stance;

					bool bActive = (stagingParams.bLocked ||
						(!stagingParams.vLimitDir.IsZero() && 
						!iszero(stagingParams.vLimitRangeH) && 
						!iszero(stagingParams.vLimitRangeV)) );
					pPlayer->StagePlayer(bActive, &stagingParams);

					/*
					SActorParams* pActorParams = pPlayerActor->GetActorParams();
					if (pActorParams)
					{
						CPlayer* pPlayer = static_cast<CPlayer*> (pPlayerActor);
						if (dir.len2()>0.01f)
						{
							if (localSpace)
							{
								const Quat& viewQuat = pPlayer->GetViewQuatFinal(); // WC
								Vec3 dirWC = viewQuat * dir;
								pActorParams->vLimitDir = dirWC.GetNormalizedSafe(ZERO);
							}
							else
								pActorParams->vLimitDir = dir.GetNormalizedSafe(ZERO);
						}
						else 
							pActorParams->vLimitDir.zero();

						pActorParams->vLimitRangeH = DEG2RAD(rangeH);
						pActorParams->vLimitRangeV = DEG2RAD(rangeV);
						const bool bLock = GetPortBool(pActInfo, EIP_Lock);

						// AlexL 23/01/2007: disable this until we have a working solution to lock player movement (action filter)
						// SPlayerStats* pActorStats = static_cast<SPlayerStats*> (pPlayer->GetActorStats());
						// if (pActorStats)
						//	pActorStats->spectatorMode = bLock ? CActor::eASM_Cutscene : 0;
						IActionMapManager* pAmMgr = g_pGame->GetIGameFramework()->GetIActionMapManager();
						if (pAmMgr)
							pAmMgr->EnableFilter("no_move", bLock);

						if (bLock)
						{
							// CPlayerMovementController* pMC = static_cast<CPlayerMovementController*> (pPlayer->GetMovementController());
							// pMC->Reset();
							if(pPlayer->GetPlayerInput())
								pPlayer->GetPlayerInput()->Reset();
						}
					}
					*/
				}
				ActivateOutput(pActInfo, EOP_Done, false);
			}
			break;
		}
	}
Example #29
0
MineEffect::MineEffect(EyeCandy* _base, bool* _dead, Vec3* _pos,
                       const MineType _type, const Uint16 _LOD)
{
    if (EC_DEBUG)
        std::cout << "MineEffect (" << this << ") created (" << type
                  << ")." << std::endl;
    base = _base;
    dead = _dead;
    pos = _pos;
    effect_center = *pos;
    type = _type;
    LOD = base->last_forced_LOD;
    desired_LOD = _LOD;
    spawner = NULL;
    bounds = NULL;
    mover = NULL;
    spawner2 = NULL;
    mover2 = NULL;

    switch (type)
    {
    case DETONATE_MAGIC_IMMUNITY_REMOVAL:
    {
        spawner = new FilledSphereSpawner(0.1);
        mover = new ParticleMover(this);
        while ((int)particles.size() < LOD * 150)
        {
            const Vec3 coords = spawner->get_new_coords()
                                + effect_center;
            Vec3 velocity;
            velocity.randomize(0.5);
            velocity.y = 0.2;
            Particle
            * p =
#ifdef	NEW_TEXTURES
                new MineParticle(this, mover, coords, velocity, 0.2, 1.0, 3.0, 3.0, 3.0, EC_SIMPLE, LOD, type);
#else	/* NEW_TEXTURES */
                new MineParticle(this, mover, coords, velocity, 0.2, 1.0, 3.0, 3.0, 3.0, &(base->TexSimple), LOD, type);
#endif	/* NEW_TEXTURES */
            if (!base->push_back_particle(p))
                break;
        }
        break;
    }
    case DETONATE_UNINVIZIBILIZER:
    {
        effect_center.y += 1.8;
        spawner = new HollowDiscSpawner(0.3);
        mover = new ParticleMover(this);
        while ((int)particles.size() < LOD * 200)
        {
            Vec3 coords = spawner->get_new_coords();
            Vec3 velocity;
            velocity.randomize();
            velocity.normalize(0.2);
            coords += effect_center;
            coords.y = randfloat(1.8);
            Particle
            * p =
#ifdef	NEW_TEXTURES
                new MineParticle(this, mover, coords, velocity, 1.2, 1.0, 3.0, 3.0, 3.0, EC_SIMPLE, LOD, type);
#else	/* NEW_TEXTURES */
                new MineParticle(this, mover, coords, velocity, 1.2, 1.0, 3.0, 3.0, 3.0, &(base->TexSimple), LOD, type);
#endif	/* NEW_TEXTURES */
            if (!base->push_back_particle(p))
                break;
        }
        break;
    }
    case DETONATE_MANA_DRAINER:
    {
        effect_center.y += 1.6;
        spawner = new HollowDiscSpawner(0.3);
        mover = new SimpleGravityMover(this);
        while ((int)particles.size() < LOD * 50)
        {
            const Vec3 coords = spawner->get_new_coords()
                                + effect_center;
            Vec3 velocity;
            velocity.randomize();
            velocity.normalize(0.2);
            Particle
            * p =
#ifdef	NEW_TEXTURES
                new MineParticle(this, mover, coords, velocity, 0.3, 1.0, 0.8, 0.35, 0.7, EC_SIMPLE, LOD, type);
#else	/* NEW_TEXTURES */
                new MineParticle(this, mover, coords, velocity, 0.3, 1.0, 0.8, 0.35, 0.7, &(base->TexSimple), LOD, type);
#endif	/* NEW_TEXTURES */
            if (!base->push_back_particle(p))
                break;
        }
        break;
    }
    case DETONATE_MANA_BURNER:
    {
        effect_center.y += 1.0;
        spawner = new FilledSphereSpawner(0.5);
        mover = new GravityMover(this, &effect_center, 8e9);
        while ((int)particles.size() < LOD * 100)
        {
            const Vec3 coords = spawner->get_new_coords()
                                + effect_center;
            Vec3 velocity;
            velocity.randomize();
            velocity.normalize(0.9);
            Particle
            * p =
#ifdef	NEW_TEXTURES
                new MineParticle(this, mover, coords, velocity, 0.5, 0.5, 0.8, 0.35, 0.7, EC_TWINFLARE, LOD, type);
#else	/* NEW_TEXTURES */
                new MineParticle(this, mover, coords, velocity, 0.5, 0.5, 0.8, 0.35, 0.7, &(base->TexTwinflare), LOD, type);
#endif	/* NEW_TEXTURES */
            if (!base->push_back_particle(p))
                break;
        }
        break;
    }
    case DETONATE_CALTROP:
    case DETONATE_CALTROP_POISON:
    {
        effect_center.y += 0.05;
        mover = new SimpleGravityMover(this);
        spawner = new HollowSphereSpawner(0.1);

        for (int i = 0; i < LOD * 10; i++)
        {
            const Vec3 coords = spawner->get_new_coords()
                                + effect_center;
            const Vec3 velocity(0.0, 5.0, 0.0);
#ifdef	NEW_TEXTURES
            Particle* p = new MineParticle(this, mover, coords, velocity, 0.75, 0.6, 0.4, (type == DETONATE_CALTROP ? 0.3 : 0.5), 0.3, EC_TWINFLARE, LOD, type);
#else	/* NEW_TEXTURES */
            Particle* p = new MineParticle(this, mover, coords, velocity, 0.75, 0.6, 0.4, (type == DETONATE_CALTROP ? 0.3 : 0.5), 0.3, &(base->TexTwinflare), LOD, type);
#endif	/* NEW_TEXTURES */
            p->state = 1;
            if (!base->push_back_particle(p))
                break;
        }

        break;
    }
    case DETONATE_TRAP:
    {
        effect_center.y += 1.25;
        mover = new OrbitalMover(this, effect_center);
        spawner = new HollowSphereSpawner(1.25);
        Particle* p;

        for (int i = 0; i < LOD * 100; i++)
        {
            Vec3 c = effect_center;
            c.y = -0.3 + (i * 0.05);
            Vec3 vel;
            vel.randomize();
            vel.normalize(2.0);
            vel *= randfloat() * 4.0;
#ifdef	NEW_TEXTURES
            p = new MineParticle(this, mover, c, vel, 0.2, 1.0, 1.0, 1.0, 1.0, EC_VOID, LOD, type);
#else	/* NEW_TEXTURES */
            p = new MineParticle(this, mover, c, vel, 0.2, 1.0, 1.0, 1.0, 1.0, &(base->TexVoid), LOD, type);
#endif	/* NEW_TEXTURES */
            if (!base->push_back_particle(p))
                break;

            dynamic_cast<OrbitalMover*>(mover)->setParticleData(p, OrbitalParticleData(i, 10,
                    0.45, 10) );
        }

        break;
    }
    case DETONATE_TYPE1_SMALL:
    case DETONATE_TYPE1_MEDIUM:
    case DETONATE_TYPE1_LARGE:
    {
        spawner = new FilledSphereSpawner(0.1);
        mover = new ParticleMover(this);
        const float scale = (type == DETONATE_TYPE1_SMALL ? 0.75 : type
                             == DETONATE_TYPE1_MEDIUM ? 1.25 : 2.0);
        Vec3 wind;
        wind.randomize();
        wind.normalize(0.25);
        wind.y = 0;
        for (int i = 0; i < LOD * 100 * scale; i++)
        {
            Vec3 coords = spawner->get_new_coords();
            Vec3 velocity = coords * 10.0 * sqrt(scale);
            velocity.y = fabs(velocity.y) * 3.0f;
            coords += effect_center;
            coords.y -= 0.1;
#ifdef	NEW_TEXTURES
            Particle * p = new MineParticleFire(this, mover, coords, velocity, 0.5, 1.0, 1.0, randcolor(0.75), 0.0, EC_FLARE, LOD);
#else	/* NEW_TEXTURES */
            Particle * p = new MineParticleFire(this, mover, coords, velocity, 0.5, 1.0, 1.0, randcolor(0.75), 0.0, &(base->TexFlare), LOD);
#endif	/* NEW_TEXTURES */
            if (!base->push_back_particle(p))
                break;
        }
        spawner = new FilledSphereSpawner(0.5 * std::sqrt(scale));
        for (int i = 0; i < LOD * 32 * scale; i++)
        {
            Vec3 coords = spawner->get_new_coords();
            Vec3 velocity;
            coords += effect_center;
            float grey = randcolor(0.5);
            velocity.randomize();
            velocity.normalize(0.25 * scale);
            velocity.y = fabs(velocity.y) * 6.0f;
            velocity += wind;
#ifdef	NEW_TEXTURES
            Particle *p = new MineParticleSmoke(this, mover, coords, velocity, 3.0 + randcoord(3.0 * scale), 0.0, grey, grey, grey, EC_SIMPLE, LOD);
#else	/* NEW_TEXTURES */
            Particle *p = new MineParticleSmoke(this, mover, coords, velocity, 3.0 + randcoord(3.0 * scale), 0.0, grey, grey, grey, &(base->TexSimple), LOD);
#endif	/* NEW_TEXTURES */
            if (!base->push_back_particle(p))
                break;
        }
        break;
    }
    }
}
Example #30
0
bool CCameraTracking::IdentifyObstacle(const Vec3 &vCamDir, const CPlayer &hero)
{
	//check player direction
	Vec3 newDir = -hero.GetEntity()->GetForwardDir();
	newDir.z += vCamDir.z;
	newDir.normalize();

	//compute rotation speed
	const float fHeroSpeedModifier = clamp(hero.GetActorStats()->speedFlat / 4.0f, 0.3f, 1.0f);
	const float fNewSpeed = g_pGameCVars->cl_cam_tracking_rotation_speed * m_fFrameTime * fHeroSpeedModifier;
	m_fSpeed = InterpolateTo(m_fSpeed, fNewSpeed, (fNewSpeed>m_fSpeed)?0.1f:0.3f);
	//m_fSpeed = (g_fInterpolationRate * m_fSpeed + speed) * g_fInterpolationWeight;

	//get ray data from camera ray tests
	ray_hit *pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_RIGHT);

	if(!pRayHit || pRayHit->dist == 0.0f)
		pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_RIGHT);

	bool bHitsRight = (pRayHit && pRayHit->dist > 0.0f);
	Vec3 dirRight = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_RIGHT)):Vec3(ZERO);

	//ray data left side
	pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_LEFT);

	if(!pRayHit || pRayHit->dist == 0.0f)
		pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_LEFT);

	bool bHitsLeft = (pRayHit && pRayHit->dist > 0.0f);
	Vec3 dirLeft = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_LEFT)):Vec3(ZERO);

	//left or right
	if(bHitsRight ^ bHitsLeft)
	{
		//find rotation direction
		if(!bHitsRight && !bHitsLeft)
		{
			if(m_eLastDirYaw == eTD_LEFT) //continue last direction
				newDir = dirLeft;
			else
				newDir = dirRight;
		}
		else if(!bHitsRight)
		{
			m_eLastDirYaw = eTD_RIGHT;
			newDir = dirRight;
		}
		else
		{
			m_eLastDirYaw = eTD_LEFT;
			newDir = dirLeft;
		}

		//compute yaw/pitch for target position
		float newYaw = 0.0f;
		float newPitch = 0.0f;
		float newDist = 0.0f;
		CartesianToSpherical(newDir * m_curCamOrientation.m_fDist, newYaw, newPitch, newDist);

		newYaw += gf_PI;

		//now interpolate to target

		//compute delta yaw
		m_fYawDelta = (newYaw - m_curCamOrientation.m_fYaw) * m_fSpeed;

		if(m_eLastDirYaw == eTD_RIGHT && m_fYawDelta < 0.0f || m_eLastDirYaw == eTD_LEFT && m_fYawDelta > 0.0f)
			m_fYawDelta *= -1.0f;
	}

	//compute top/bottom rotation

	//ray data top side
	pRayHit = m_pCamRayScan->GetHit(eRAY_TOP_CENTER);
	bool bHitsTop = (pRayHit && pRayHit->dist > 0.0f)?true:false;
	Vec3 vDirTop = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_TOP_CENTER)):Vec3(ZERO);

	//ray data bottom side
	pRayHit = m_pCamRayScan->GetHit(eRAY_BOTTOM_CENTER);
	bool bHitsBottom = (pRayHit && pRayHit->dist > 0.0f)?true:false;
	Vec3 vDirBottom = (pRayHit)?-(m_pCamRayScan->GetRayDir(eRAY_BOTTOM_CENTER)):Vec3(ZERO);

	//top or bottom (if not left or right)
	if(g_pGameCVars->cl_cam_tracking_allow_pitch && (bHitsTop ^ bHitsBottom) && !(bHitsRight ^ bHitsLeft))
	{
		//find rotation direction
		if(!bHitsTop && !bHitsBottom)
		{
			if(m_eLastDirPitch == eTD_TOP) //continue last direction
				newDir = vDirTop;
			else
				newDir = vDirBottom;
		}
		else if(!bHitsBottom)
		{
			m_eLastDirPitch = eTD_BOTTOM;
			newDir = vDirBottom;
		}
		else
		{
			m_eLastDirPitch = eTD_TOP;
			newDir = vDirTop;
		}

		//compute yaw/pitch for target position
		float newYaw = 0.0f;
		float newPitch = 0.0f;
		float newDist = 0.0f; //newdist (raydist) will be ignored
		CartesianToSpherical(newDir, newYaw, newPitch, newDist);

		//compute delta pitch
		m_fPitchDelta = (newPitch - m_curCamOrientation.m_fPitch) * m_fSpeed * 10.0f;
	}

	//if all rays hit - don't bother!
	//this is a termination condition when the camera is pulled through geometry
	if(bHitsLeft & bHitsRight & bHitsBottom & bHitsTop)
	{
		if(m_bViewCovered)
		{
			//if obstacle behind player
			//if(g_rHit.dist > 0.0f)
			//this is a strange fix, but it's working better and is much cheaper than a raycast
			if(fabsf(m_fYawDelta) < 0.01f && fabsf(m_fPitchDelta) > 0.001f)
				return false;
		}

		m_bViewCovered = true;
	}
	else
		m_bViewCovered = false;

	return true;
}