Point2F BiQuadToSqr::transform( const Point2F &p ) const
{
    Point2F kA = m_kP00 - p;

    F32 fAB = mDotPerp( kA, m_kB );
    F32 fAC = mDotPerp( kA, m_kC);

    // 0 = ac*bc+(bc^2+ac*bd-ab*cd)*s+bc*bd*s^2 = k0 + k1*s + k2*s^2
    F32 fK0 = fAC*m_fBC;
    F32 fK1 = m_fBC*m_fBC + fAC*m_fBD - fAB*m_fCD;
    F32 fK2 = m_fBC*m_fBD;

    if (mFabs(fK2) > POINT_EPSILON)
    {
        // s-equation is quadratic
        F32 fInv = 0.5f/fK2;
        F32 fDiscr = fK1*fK1 - 4.0f*fK0*fK2;
        F32 fRoot = mSqrt( mFabs(fDiscr) );

        Point2F kResult0( 0, 0 );
        kResult0.x = (-fK1 - fRoot)*fInv;
        kResult0.y = fAB/(m_fBC + m_fBD*kResult0.x);
        F32 fDeviation0 = deviation(kResult0);
        if ( fDeviation0 == 0.0f )
            return kResult0;

        Point2F kResult1( 0, 0 );
        kResult1.x = (-fK1 + fRoot)*fInv;
        kResult1.y = fAB/(m_fBC + m_fBD*kResult1.x);
        F32 fDeviation1 = deviation(kResult1);
        if ( fDeviation1 == 0.0f )
            return kResult1;

        if (fDeviation0 <= fDeviation1)
        {
            if ( fDeviation0 < POINT_EPSILON )
                return kResult0;
        }
        else
        {
            if ( fDeviation1 < POINT_EPSILON )
                return kResult1;
        }
    }
    else
    {
        // s-equation is linear
        Point2F kResult( 0, 0 );

        kResult.x = -fK0/fK1;
        kResult.y = fAB/(m_fBC + m_fBD*kResult.x);
        F32 fDeviation = deviation(kResult);
        if ( fDeviation < POINT_EPSILON )
            return kResult;
    }

    // point is outside the quadrilateral, return invalid
    return Point2F(F32_MAX,F32_MAX);
}
void VideoCapture::capture()
{   
   // If this is the first frame, capture and encode it right away   
   if (mNextFramePosition == 0.0f)
   {
      mVideoCaptureStartTime = Platform::getVirtualMilliseconds();
      mCapturedFramePos = -1.0f;
   }

   // Calculate the frame position for this captured frame
   U32 frameTimeMs = Platform::getVirtualMilliseconds() - mVideoCaptureStartTime;
   F32 framePosition = (F32)frameTimeMs / mMsPerFrame;

   // Repeat until the current frame is captured
   while (framePosition > mCapturedFramePos)
   {
      // If the frame position is closer to the next frame position 
      // than the previous one capture it
      if ( mFabs(framePosition - mNextFramePosition) < mFabs(mCapturedFramePos - mNextFramePosition) )
      {
         mFrameGrabber->captureBackBuffer();      
         mCapturedFramePos  = framePosition;
      }
      
      // If the new frame position is greater or equal than the next frame time
      // tell the framegrabber to make bitmaps out from the last captured backbuffer until the video catches up
      while ( framePosition >= mNextFramePosition )
      {
         mFrameGrabber->makeBitmap();        
         mNextFramePosition++;
      }
   }

   // Fetch bitmaps from the framegrabber and encode them
   GBitmap *bitmap = NULL;
   while ( (bitmap = mFrameGrabber->fetchBitmap()) != NULL )
   {     
      //mEncoder->pushProcessedBitmap(bitmap);                 
      if (!mEncoder->pushFrame(bitmap))
      {
          Con::errorf("VideoCapture: an error occurred while encoding a frame. Recording aborted.");
          end();
          break;
      }
   }

   // Garbage collect the processed bitmaps
   deleteProcessedBitmaps();
}
예제 #3
0
void TimeOfDay::_updatePosition()
{
   //// Full azimuth/elevation calculation.
   //// calculate sun decline and meridian angle (in radians)
   //F32 sunDecline = mSin( M_2PI * mTimeOfYear ) * mDegToRad( mAxisTilt );
   //F32 meridianAngle = mTimeOfDay * M_2PI - mDegToRad( mLongitude );

   //// calculate the elevation and azimuth (in radians)
   //mElevation = _calcElevation( mDegToRad( mLatitude ), sunDecline, meridianAngle );
   //mAzimuth = _calcAzimuth( mDegToRad( mLatitude ), sunDecline, meridianAngle );

   // Simplified azimuth/elevation calculation.
   // calculate sun decline and meridian angle (in radians)
   F32 sunDecline = mDegToRad( mAxisTilt );
   F32 meridianAngle = mTimeOfDay * M_2PI;

   mPrevElevation = mNextElevation;

   // calculate the elevation and azimuth (in radians)
   mElevation = _calcElevation( 0.0f, sunDecline, meridianAngle );
   mAzimuth = _calcAzimuth( 0.0f, sunDecline, meridianAngle );

   if ( mFabs( mAzimuthOverride ) )
   {
      mElevation = mDegToRad( mTimeOfDay * 360.0f );
      mAzimuth = mAzimuthOverride;
   }

   mNextElevation = mElevation;

   // Only the client updates the sun position!
   if ( isClientObject() )
      smTimeOfDayUpdateSignal.trigger( this, mTimeOfDay );
}
예제 #4
0
U32 OptimizedPolyList::insertPlane(const PlaneF& plane)
{
   S32 retIdx = -1;

   // Apply the transform
   PlaneF transPlane;
   mPlaneTransformer.transform(plane, transPlane);

   for (U32 i = 0; i < mPlaneList.size(); i++)
   {
      if (mPlaneList[i].equal(transPlane) &&
          mFabs( mPlaneList[i].d - transPlane.d ) < POINT_EPSILON)
      {
         retIdx = i;
         break;
      }
   }

   if (retIdx == -1)
   {
      retIdx = mPlaneList.size();
      mPlaneList.push_back(transPlane);
   }

   return (U32)retIdx;
}
예제 #5
0
//-----------------------------------------------------------------------------
// This function based on code originally written for the book:
// 3D Game Engine Design, by David H. Eberly
//
F32 sqrDistanceEdges(const Point3F& start0, const Point3F& end0,
   const Point3F& start1, const Point3F& end1,
   Point3F* is, Point3F* it)
{
   Point3F direction0 = end0 - start0;
   F32 fA00 = direction0.lenSquared();

   Point3F direction1 = end1 - start1;
   F32 fA11 = direction1.lenSquared();
   F32 fA01 = -mDot(direction0, direction1);

   Point3F kDiff = start0 - start1;
   F32 fC   = kDiff.lenSquared();
   F32 fB0  = mDot(kDiff, direction0);
   F32 fDet = mFabs(fA00*fA11 - fA01*fA01);

   // Since the endpoints are tested as vertices, we're not interested
   // in parallel lines, and intersections that don't involve end-points.
   if (fDet >= 0.00001) {

      // Calculate time of intersection for each line
      F32 fB1 = -mDot(kDiff, direction1);
      F32 fS  = fA01*fB1-fA11*fB0;
      F32 fT  = fA01*fB0-fA00*fB1;

      // Only interested in collisions that don't involve the end points
      if (fS >= 0.0 && fS <= fDet && fT >= 0.0 && fT <= fDet) {
         F32 fInvDet = 1.0 / fDet;
         fS *= fInvDet;
         fT *= fInvDet;
         F32 fSqrDist = (fS*(fA00*fS + fA01*fT + 2.0*fB0) +
            fT*(fA01*fS + fA11*fT + 2.0*fB1) + fC);

         // Intersection points.
         *is = start0 + direction0 * fS;
         *it = start1 + direction1 * fT;
         return mFabs(fSqrDist);
      }
   }

   // Return a large number in the cases where endpoints are involved.
   return 1e10f;
}
BiQuadToSqr::BiQuadToSqr(  const Point2F &p00,
                           const Point2F &p10,
                           const Point2F &p11,
                           const Point2F &p01 )
    : m_kP00( p00 )
{
    m_kB = p10 - p00 ;   // width
    m_kC = p01 - p00;   // height
    m_kD = p11 + p00 - p10 - p01; // diagonal dist

    if(mFabs(m_kD.x) < POINT_EPSILON)
        m_kD.x = 0.f;
    if(mFabs(m_kD.y) < POINT_EPSILON)
        m_kD.y = 0.f;

    m_fBC = mDotPerp( m_kB, m_kC );
    m_fBD = mDotPerp( m_kB, m_kD );
    m_fCD = mDotPerp( m_kC, m_kD );
}
예제 #7
0
bool OrientedBox3F::isContained( const Point3F& point ) const
{
   Point3F distToCenter = point - getCenter();
   for( U32 i = 0; i < 3; ++ i )
   {
      F32 coeff = mDot( distToCenter, getAxis( i ) );
      if( mFabs( coeff ) > getHalfExtents()[ i ] )
         return false;
   }

   return true;
}
예제 #8
0
// Perform inverse on full 4x4 matrix.  Used in special cases only, so not at all optimized.
bool MatrixF::fullInverse()
{
   Point4F a,b,c,d;
   getRow(0,&a);
   getRow(1,&b);
   getRow(2,&c);
   getRow(3,&d);

   // det = a0*b1*c2*d3 - a0*b1*c3*d2 - a0*c1*b2*d3 + a0*c1*b3*d2 + a0*d1*b2*c3 - a0*d1*b3*c2 -
   //       b0*a1*c2*d3 + b0*a1*c3*d2 + b0*c1*a2*d3 - b0*c1*a3*d2 - b0*d1*a2*c3 + b0*d1*a3*c2 +
   //       c0*a1*b2*d3 - c0*a1*b3*d2 - c0*b1*a2*d3 + c0*b1*a3*d2 + c0*d1*a2*b3 - c0*d1*a3*b2 -
   //       d0*a1*b2*c3 + d0*a1*b3*c2 + d0*b1*a2*c3 - d0*b1*a3*c2 - d0*c1*a2*b3 + d0*c1*a3*b2
   F32 det = a.x*b.y*c.z*d.w - a.x*b.y*c.w*d.z - a.x*c.y*b.z*d.w + a.x*c.y*b.w*d.z + a.x*d.y*b.z*c.w - a.x*d.y*b.w*c.z
           - b.x*a.y*c.z*d.w + b.x*a.y*c.w*d.z + b.x*c.y*a.z*d.w - b.x*c.y*a.w*d.z - b.x*d.y*a.z*c.w + b.x*d.y*a.w*c.z
           + c.x*a.y*b.z*d.w - c.x*a.y*b.w*d.z - c.x*b.y*a.z*d.w + c.x*b.y*a.w*d.z + c.x*d.y*a.z*b.w - c.x*d.y*a.w*b.z
           - d.x*a.y*b.z*c.w + d.x*a.y*b.w*c.z + d.x*b.y*a.z*c.w - d.x*b.y*a.w*c.z - d.x*c.y*a.z*b.w + d.x*c.y*a.w*b.z;

   if (mFabs(det)<0.00001f)
      return false;

   Point4F aa,bb,cc,dd;
   aa.x =  b.y*c.z*d.w - b.y*c.w*d.z - c.y*b.z*d.w + c.y*b.w*d.z + d.y*b.z*c.w - d.y*b.w*c.z;
   aa.y = -a.y*c.z*d.w + a.y*c.w*d.z + c.y*a.z*d.w - c.y*a.w*d.z - d.y*a.z*c.w + d.y*a.w*c.z;
   aa.z =  a.y*b.z*d.w - a.y*b.w*d.z - b.y*a.z*d.w + b.y*a.w*d.z + d.y*a.z*b.w - d.y*a.w*b.z;
   aa.w = -a.y*b.z*c.w + a.y*b.w*c.z + b.y*a.z*c.w - b.y*a.w*c.z - c.y*a.z*b.w + c.y*a.w*b.z;

   bb.x = -b.x*c.z*d.w + b.x*c.w*d.z + c.x*b.z*d.w - c.x*b.w*d.z - d.x*b.z*c.w + d.x*b.w*c.z;
   bb.y =  a.x*c.z*d.w - a.x*c.w*d.z - c.x*a.z*d.w + c.x*a.w*d.z + d.x*a.z*c.w - d.x*a.w*c.z;
   bb.z = -a.x*b.z*d.w + a.x*b.w*d.z + b.x*a.z*d.w - b.x*a.w*d.z - d.x*a.z*b.w + d.x*a.w*b.z;
   bb.w =  a.x*b.z*c.w - a.x*b.w*c.z - b.x*a.z*c.w + b.x*a.w*c.z + c.x*a.z*b.w - c.x*a.w*b.z;

   cc.x =  b.x*c.y*d.w - b.x*c.w*d.y - c.x*b.y*d.w + c.x*b.w*d.y + d.x*b.y*c.w - d.x*b.w*c.y;
   cc.y = -a.x*c.y*d.w + a.x*c.w*d.y + c.x*a.y*d.w - c.x*a.w*d.y - d.x*a.y*c.w + d.x*a.w*c.y;
   cc.z =  a.x*b.y*d.w - a.x*b.w*d.y - b.x*a.y*d.w + b.x*a.w*d.y + d.x*a.y*b.w - d.x*a.w*b.y;
   cc.w = -a.x*b.y*c.w + a.x*b.w*c.y + b.x*a.y*c.w - b.x*a.w*c.y - c.x*a.y*b.w + c.x*a.w*b.y;

   dd.x = -b.x*c.y*d.z + b.x*c.z*d.y + c.x*b.y*d.z - c.x*b.z*d.y - d.x*b.y*c.z + d.x*b.z*c.y;
   dd.y =  a.x*c.y*d.z - a.x*c.z*d.y - c.x*a.y*d.z + c.x*a.z*d.y + d.x*a.y*c.z - d.x*a.z*c.y;
   dd.z = -a.x*b.y*d.z + a.x*b.z*d.y + b.x*a.y*d.z - b.x*a.z*d.y - d.x*a.y*b.z + d.x*a.z*b.y;
   dd.w =  a.x*b.y*c.z - a.x*b.z*c.y - b.x*a.y*c.z + b.x*a.z*c.y + c.x*a.y*b.z - c.x*a.z*b.y;

   setRow(0,aa);
   setRow(1,bb);
   setRow(2,cc);
   setRow(3,dd);

   mul(1.0f/det);

   return true;
}
예제 #9
0
//----------------------------------------------------------------------------
// Create ring
//----------------------------------------------------------------------------
SplashRing Splash::createRing()
{
   SplashRing ring;
   U32 numPoints = mDataBlock->numSegments + 1;

   Point3F ejectionAxis( 0.0, 0.0, 1.0 );

   Point3F axisx;
   if (mFabs(ejectionAxis.z) < 0.999f)
      mCross(ejectionAxis, Point3F(0, 0, 1), &axisx);
   else
      mCross(ejectionAxis, Point3F(0, 1, 0), &axisx);
   axisx.normalize();

   for( U32 i=0; i<numPoints; i++ )
   {
      F32 t = F32(i) / F32(numPoints);

      AngAxisF thetaRot( axisx, mDataBlock->ejectionAngle * (M_PI / 180.0));
      AngAxisF phiRot(   ejectionAxis, t * (M_PI * 2.0));

      Point3F pointAxis = ejectionAxis;

      MatrixF temp;
      thetaRot.setMatrix(&temp);
      temp.mulP(pointAxis);
      phiRot.setMatrix(&temp);
      temp.mulP(pointAxis);

      Point3F startOffset = axisx;
      temp.mulV( startOffset );
      startOffset *= mDataBlock->startRadius;

      SplashRingPoint point;
      point.position = getPosition() + startOffset;
      point.velocity = pointAxis * mDataBlock->velocity;

      ring.points.push_back( point );
   }

   ring.color = mDataBlock->colors[0];
   ring.lifetime = mDataBlock->ringLifetime;
   ring.elapsedTime = 0.0;
   ring.v = mDataBlock->texFactor * mFmod( mElapsedTime, 1.0 );

   return ring;
}
예제 #10
0
bool MatrixF::isAffine() const
{
   // An affine transform is defined by the following structure
   //
   // [ X X X P ]
   // [ X X X P ]
   // [ X X X P ]
   // [ 0 0 0 1 ]
   //
   //  Where X is an orthonormal 3x3 submatrix and P is an arbitrary translation
   //  We'll check in the following order:
   //   1: [3][3] must be 1
   //   2: Shear portion must be zero
   //   3: Dot products of rows and columns must be zero
   //   4: Length of rows and columns must be 1
   //
   if (m[idx(3,3)] != 1.0f)
      return false;

   if (m[idx(0,3)] != 0.0f ||
       m[idx(1,3)] != 0.0f ||
       m[idx(2,3)] != 0.0f)
      return false;

   Point3F one, two, three;
   getColumn(0, &one);
   getColumn(1, &two);
   getColumn(2, &three);
   if (mDot(one, two)   > 0.0001f ||
       mDot(one, three) > 0.0001f ||
       mDot(two, three) > 0.0001f)
      return false;

   if (mFabs(1.0f - one.lenSquared()) > 0.0001f ||
       mFabs(1.0f - two.lenSquared()) > 0.0001f ||
       mFabs(1.0f - three.lenSquared()) > 0.0001f)
      return false;

   getRow(0, &one);
   getRow(1, &two);
   getRow(2, &three);
   if (mDot(one, two)   > 0.0001f ||
       mDot(one, three) > 0.0001f ||
       mDot(two, three) > 0.0001f)
      return false;

   if (mFabs(1.0f - one.lenSquared()) > 0.0001f ||
       mFabs(1.0f - two.lenSquared()) > 0.0001f ||
       mFabs(1.0f - three.lenSquared()) > 0.0001f)
      return false;

   // We're ok.
   return true;
}
예제 #11
0
void ConvexShape::resizePlanes( const Point3F &size )
{
   //Point3F nSize;
   //mWorldToObj.mulV( nSize );

   for ( S32 i = 0; i < mSurfaces.size(); i++ )
   {
      MatrixF objToPlane( mSurfaces[i] );
      objToPlane.inverse();

      Point3F lim;
      objToPlane.mulV( size, &lim );

      F32 sign = ( mPlanes[i].d > 0.0f ) ? 1.0f : -1.0f;
      mPlanes[i].d = mFabs(lim.z) * 0.5f * sign;
      
      //mPlanes[i].d = -lim.z * 0.5f;      

      mSurfaces[i].setPosition( mPlanes[i].getPosition() );
   }   
}
예제 #12
0
   virtual btScalar addSingleResult(   btCollisionWorld::LocalConvexResult &convexResult, 
                                       bool normalInWorldSpace )
   {
      // NOTE: I shouldn't have to do any of this, but Bullet 
      // has some weird bugs.
      //
      // For one the plane type will return hits on a Z up surface
      // for sweeps that have no Z sweep component.
      //
      // Second the normal returned here is sometimes backwards
      // to the sweep direction... no clue why.
      //
      F32 dotN = mMoveVec.dot( convexResult.m_hitNormalLocal );
	   if ( mFabs( dotN ) < 0.1f )
         return 1.0f;

      //.logicking (commented - sometimes we need to collide with NO_CONTACT_RESPONSE, i.e. invisible walls)
      //if ( convexResult.m_hitCollisionObject->getCollisionFlags() & btCollisionObject::CF_NO_CONTACT_RESPONSE )
      //   return 1.0f;

	   return Parent::addSingleResult( convexResult, normalInWorldSpace );
   }
예제 #13
0
파일: gjk.cpp 프로젝트: Adhdcrazzy/Torque3D
F32 GjkCollisionState::distance(const MatrixF& a2w, const MatrixF& b2w,
   const F32 dontCareDist, const MatrixF* _w2a, const MatrixF* _w2b)
{
   num_iterations = 0;
   MatrixF w2a,w2b;

   if (_w2a == NULL || _w2b == NULL) {
      w2a = a2w;
      w2b = b2w;
      w2a.inverse();
      w2b.inverse();
   }
   else {
      w2a = *_w2a;
      w2b = *_w2b;
   }

   reset(a2w,b2w);
   bits = 0;
   all_bits = 0;
   F32 mu = 0;

   do {
      nextBit();

      VectorF va,sa;
      w2a.mulV(-v,&va);
      p[last] = a->support(va);
      a2w.mulP(p[last],&sa);

      VectorF vb,sb;
      w2b.mulV(v,&vb);
      q[last] = b->support(vb);
      b2w.mulP(q[last],&sb);

      VectorF w = sa - sb;
      F32 nm = mDot(v, w) / dist;
      if (nm > mu)
         mu = nm;
      if (mu > dontCareDist)
         return mu;
      if (mFabs(dist - mu) <= dist * rel_error)
         return dist;

      ++num_iterations;
      if (degenerate(w) || num_iterations > sIteration) {
         ++num_irregularities;
         return dist;
      }

      y[last] = w;
      all_bits = bits | last_bit;

      if (!closest(v)) {
         ++num_irregularities;
         return dist;
      }

      dist = v.len();
   }
   while (bits < 15 && dist > sTolerance) ;

   if (bits == 15 && mu <= 0)
      dist = 0;
   return dist;
}
예제 #14
0
void FlyingVehicle::updateJet(F32 dt)
{
   // Thrust Animation threads
   //  Back
   if (mJetSeq[BackActivate] >=0 ) {
      if(!mBackMaintainOn || mThrustDirection != ThrustForward) {
         if(mBackMaintainOn) {
            mShapeInstance->setPos(mJetThread[BackActivate], 1);
            mShapeInstance->destroyThread(mJetThread[BackMaintain]);
            mBackMaintainOn = false;
         }
         mShapeInstance->setTimeScale(mJetThread[BackActivate],
            (mThrustDirection == ThrustForward)? 1.0f : -1.0f);
         mShapeInstance->advanceTime(dt,mJetThread[BackActivate]);
      }
      if(mJetSeq[BackMaintain] >= 0 && !mBackMaintainOn &&
            mShapeInstance->getPos(mJetThread[BackActivate]) >= 1.0) {
         mShapeInstance->setPos(mJetThread[BackActivate], 0);
         mShapeInstance->setTimeScale(mJetThread[BackActivate], 0);
         mJetThread[BackMaintain] = mShapeInstance->addThread();
         mShapeInstance->setSequence(mJetThread[BackMaintain],mJetSeq[BackMaintain],0);
         mShapeInstance->setTimeScale(mJetThread[BackMaintain],1);
         mBackMaintainOn = true;
      }
      if(mBackMaintainOn)
         mShapeInstance->advanceTime(dt,mJetThread[BackMaintain]);
   }

   // Thrust Animation threads
   //   Bottom
   if (mJetSeq[BottomActivate] >=0 ) {
      if(!mBottomMaintainOn || mThrustDirection != ThrustDown || !mJetting) {
         if(mBottomMaintainOn) {
            mShapeInstance->setPos(mJetThread[BottomActivate], 1);
            mShapeInstance->destroyThread(mJetThread[BottomMaintain]);
            mBottomMaintainOn = false;
         }
         mShapeInstance->setTimeScale(mJetThread[BottomActivate],
            (mThrustDirection == ThrustDown && mJetting)? 1.0f : -1.0f);
         mShapeInstance->advanceTime(dt,mJetThread[BottomActivate]);
      }
      if(mJetSeq[BottomMaintain] >= 0 && !mBottomMaintainOn &&
            mShapeInstance->getPos(mJetThread[BottomActivate]) >= 1.0) {
         mShapeInstance->setPos(mJetThread[BottomActivate], 0);
         mShapeInstance->setTimeScale(mJetThread[BottomActivate], 0);
         mJetThread[BottomMaintain] = mShapeInstance->addThread();
         mShapeInstance->setSequence(mJetThread[BottomMaintain],mJetSeq[BottomMaintain],0);
         mShapeInstance->setTimeScale(mJetThread[BottomMaintain],1);
         mBottomMaintainOn = true;
      }
      if(mBottomMaintainOn)
         mShapeInstance->advanceTime(dt,mJetThread[BottomMaintain]);
   }

   // Jet particles
   for (S32 j = 0; j < NumThrustDirections; j++) {
      JetActivation& jet = sJetActivation[j];
      updateEmitter(mJetting && j == mThrustDirection,dt,mDataBlock->jetEmitter[jet.emitter],
                    jet.node,FlyingVehicleData::MaxDirectionJets);
   }

   // Trail jets
   Point3F yv;
   mObjToWorld.getColumn(1,&yv);
   F32 speed = mFabs(mDot(yv,mRigid.linVelocity));
   F32 trail = 0;
   if (speed > mDataBlock->minTrailSpeed) {
      trail = dt;
      if (speed < mDataBlock->maxSpeed)
         trail *= (speed - mDataBlock->minTrailSpeed) / mDataBlock->maxSpeed;
   }
   updateEmitter(trail,trail,mDataBlock->jetEmitter[FlyingVehicleData::TrailEmitter],
                 FlyingVehicleData::TrailNode,FlyingVehicleData::MaxTrails);

   // Allocate/Deallocate voice on demand.
   if ( !mJetSound )
      return;

   if ( !mJetting ) 
      mJetSound->stop();
   else 
   {
      if ( !mJetSound->isPlaying() )
         mJetSound->play();

      mJetSound->setTransform( getTransform() );
      mJetSound->setVelocity( getVelocity() );
   }
}
예제 #15
0
/**
 * This method gets the move list for an object, in the case
 * of the AI, it actually calculates the moves, and then
 * sends them down the pipe.
 *
 * @param movePtr Pointer to move the move list into
 * @param numMoves Number of moves in the move list
 */
U32 AIClient::getMoveList( Move **movePtr,U32 *numMoves ) {
   //initialize the move structure and return pointers
   mMove = NullMove;
   *movePtr = &mMove;
   *numMoves = 1;

   // Check if we got a player
   mPlayer = NULL;
   mPlayer = dynamic_cast<Player *>( getControlObject() );

   // We got a something controling us?
   if( !mPlayer )
      return 1;

   
   // What is The Matrix?
   MatrixF moveMatrix;
   moveMatrix.set( EulerF( 0, 0, 0 ) );
   moveMatrix.setColumn( 3, Point3F( 0, 0, 0 ) );
   moveMatrix.transpose();
      
   // Position / rotation variables
   F32 curYaw, curPitch;
   F32 newYaw, newPitch;
   F32 xDiff, yDiff;

   
   F32 moveSpeed = mMoveSpeed;

   switch( mMoveMode ) {

   case ModeStop:
      return 1;     // Stop means no action
      break;

   case ModeStuck:
      // Fall through, so we still try to move
   case ModeMove:
   
      // Get my location
      MatrixF const& myTransform = mPlayer->getTransform();
      myTransform.getColumn( 3, &mLocation );
   
      // Set rotation variables
      Point3F rotation = mPlayer->getRotation();
      Point3F headRotation = mPlayer->getHeadRotation();
      curYaw = rotation.z;
      curPitch = headRotation.x;
      xDiff = mAimLocation.x - mLocation.x;
      yDiff = mAimLocation.y - mLocation.y;
   
      // first do Yaw
      if( !mIsZero( xDiff ) || !mIsZero( yDiff ) ) {
         // use the cur yaw between -Pi and Pi
         while( curYaw > M_2PI_F )
            curYaw -= M_2PI_F;
         while( curYaw < -M_2PI_F )
            curYaw += M_2PI_F;
      
         // find the new yaw
         newYaw = mAtan2( xDiff, yDiff );
      
         // find the yaw diff 
         F32 yawDiff = newYaw - curYaw;
      
         // make it between 0 and 2PI
         if( yawDiff < 0.0f )
            yawDiff += M_2PI_F;
         else if( yawDiff >= M_2PI_F )
            yawDiff -= M_2PI_F;
      
         // now make sure we take the short way around the circle
         if( yawDiff > M_2PI_F )
            yawDiff -= M_2PI_F;
         else if( yawDiff < -M_2PI_F )
            yawDiff += M_2PI_F;
      
         mMove.yaw = yawDiff;
      
         // set up the movement matrix
         moveMatrix.set( EulerF( 0.0f, 0.0f, newYaw ) );
      }
      else
         moveMatrix.set( EulerF( 0.0f, 0.0f, curYaw ) );
   
      // next do pitch
      F32 horzDist = Point2F( mAimLocation.x, mAimLocation.y ).len();

      if( !mIsZero( horzDist ) ) {
         //we shoot from the gun, not the eye...
         F32 vertDist = mAimLocation.z;
      
         newPitch = mAtan2( horzDist, vertDist ) - ( M_2PI_F / 2.0f );
      
         F32 pitchDiff = newPitch - curPitch;
         mMove.pitch = pitchDiff;
      }
   
      // finally, mMove towards mMoveDestination
      xDiff = mMoveDestination.x - mLocation.x;
      yDiff = mMoveDestination.y - mLocation.y;


      // Check if we should mMove, or if we are 'close enough'
      if( ( ( mFabs( xDiff ) > mMoveTolerance ) || 
            ( mFabs( yDiff ) > mMoveTolerance ) ) && ( !mIsZero( mMoveSpeed ) ) )
      {
         if( mIsZero( xDiff ) )
            mMove.y = ( mLocation.y > mMoveDestination.y ? -moveSpeed : moveSpeed );
         else if( mIsZero( yDiff ) )
            mMove.x = ( mLocation.x > mMoveDestination.x ? -moveSpeed : moveSpeed );
         else if( mFabs( xDiff ) > mFabs( yDiff ) ) {
            F32 value = mFabs( yDiff / xDiff ) * mMoveSpeed;
            mMove.y = ( mLocation.y > mMoveDestination.y ? -value : value );
            mMove.x = ( mLocation.x > mMoveDestination.x ? -moveSpeed : moveSpeed );
         }
         else {
            F32 value = mFabs( xDiff / yDiff ) * mMoveSpeed;
            mMove.x = ( mLocation.x > mMoveDestination.x ? -value : value );
            mMove.y = ( mLocation.y > mMoveDestination.y ? -moveSpeed : moveSpeed );
         }
      
         //now multiply the mMove vector by the transpose of the object rotation matrix
         moveMatrix.transpose();
         Point3F newMove;
         moveMatrix.mulP( Point3F( mMove.x, mMove.y, 0.0f ), &newMove );
      
         //and sub the result back in the mMove structure
         mMove.x = newMove.x;
         mMove.y = newMove.y;

         // We should check to see if we are stuck...
         if( mLocation.x == mLastLocation.x && 
             mLocation.y == mLastLocation.y &&
             mLocation.z == mLastLocation.z ) {

            // We're stuck...probably
            setMoveMode( ModeStuck );
         }
         else
            setMoveMode( ModeMove );
      }
      else {
         // Ok, we are close enough, lets stop

         // setMoveMode( ModeStop ); // DON'T use this, it'll throw the wrong callback
         mMoveMode = ModeStop;
         throwCallback(  "onReachDestination" ); // Callback

      }
      break;
   }

   // Test for target location in sight
   RayInfo dummy;
   Point3F targetLoc = mMoveDestination; // Change this

   if( mPlayer ) {
      if( !mPlayer->getContainer()->castRay( mLocation, targetLoc, 
                                                StaticShapeObjectType | StaticObjectType |
                                                TerrainObjectType, &dummy ) ) {
         if( !mTargetInLOS )
            throwCallback( "onTargetEnterLOS" );
      }
      else {
         if( mTargetInLOS )
            throwCallback( "onTargetExitLOS" );
            
      }
   }
   
   // Copy over the trigger status
   for( int i = 0; i < MaxTriggerKeys; i++ ) {
      mMove.trigger[i] = mTriggers[i];
      mTriggers[i] = false;
   }

   return 1;
}
예제 #16
0
void AITurretShape::_trackTarget(F32 dt)
{
   // Only on server
   if (isClientObject())
      return;

   // We can only track a target if we have one
   if (!mTarget.isValid())
      return;

   Point3F targetPos = mTarget.target->getBoxCenter();

   // Can we see the target?
   MatrixF aimMat;
   getAimTransform(aimMat);
   Point3F start;
   aimMat.getColumn(3, &start);
   RayInfo ri;

   Point3F sightPoint;

   disableCollision();
   bool los = _testTargetLineOfSight(start, mTarget.target, sightPoint);
   enableCollision();

   if (!los)
   {
      // Target is blocked.  Should we try to track from its last
      // known position and velocity?
      SimTime curTime = Sim::getCurrentTime();
      if ( (curTime - mTarget.lastSightTime) > (mDataBlock->trackLostTargetTime * 1000.0f) )
      {
         // Time's up.  Stop tracking.
         _cleanupTargetAndTurret();
         return;
      }
      
      // Use last known information to attempt to
      // continue to track target for a while.
      targetPos = mTarget.lastPos + mTarget.lastVel * F32(curTime - mTarget.lastSightTime) / 1000.0f;
   }
   else
   {
      // Target is visible

      // We only track targets that are alive
      if (mTarget.target->getDamageState() != Enabled)
      {
         // We can't track any more
         _cleanupTargetAndTurret();
         return;
      }

      targetPos = sightPoint;

      // Store latest target info
      mTarget.lastPos = targetPos;
      mTarget.lastVel = mTarget.target->getVelocity();
      mTarget.lastSightTime = Sim::getCurrentTime();
   }

   // Calculate angles to face the target, specifically the part that we can see
   VectorF toTarget;
   MatrixF mat;
   S32 node = mDataBlock->aimNode;
   if (node != -1)
   {
      // Get the current position of our node
      MatrixF* nodeTrans = &mShapeInstance->mNodeTransforms[node];
      Point3F currentPos;
      nodeTrans->getColumn(3, &currentPos);

      // Turn this into a matrix we can use to put the target
      // position into our space.
      MatrixF nodeMat(true);
      nodeMat.setColumn(3, currentPos);
      mat.mul(mObjToWorld, nodeMat);
      mat.affineInverse();
   }
   else
   {
      mat = mWorldToObj;
   }
   mat.mulP(targetPos, &toTarget);

   // lead the target
   F32 timeToTargetSquared = (mWeaponLeadVelocitySquared > 0) ? toTarget.lenSquared() / mWeaponLeadVelocitySquared : 0;
   if (timeToTargetSquared > 1.0)
   {
      targetPos = targetPos + (mTarget.lastVel * mSqrt(timeToTargetSquared));
      mat.mulP(targetPos, &toTarget);
   }

   F32 yaw, pitch;
   MathUtils::getAnglesFromVector(toTarget, yaw, pitch);
   if (yaw > M_PI_F)
      yaw = yaw - M_2PI_F;
   //if (pitch > M_PI_F)
   //   pitch = -(pitch - M_2PI_F);

   Point3F rot(-pitch, 0.0f, yaw);

   // If we have a rotation rate make sure we follow it
   if (mHeadingRate > 0)
   {
      F32 rate = mHeadingRate * dt;
      F32 rateCheck = mFabs(rot.z - mRot.z);
      if (rateCheck > rate)
      {
         // This will clamp the new value to the rate regardless if it
         // is increasing or decreasing.
         rot.z = mClampF(rot.z, mRot.z-rate, mRot.z+rate);
      }
   }
   if (mPitchRate > 0)
   {
      F32 rate = mPitchRate * dt;
      F32 rateCheck = mFabs(rot.x - mRot.x);
      if (rateCheck > rate)
      {
         // This will clamp the new value to the rate regardless if it
         // is increasing or decreasing.
         rot.x = mClampF(rot.x, mRot.x-rate, mRot.x+rate);
      }
   }

   // Test if the rotation to the target is outside of our limits
   if (_outsideLimits(rot))
   {
      // We can't track any more
      _cleanupTargetAndTurret();
      return;
   }

   // Test if the target is out of weapons range
   if (toTarget.lenSquared() > mWeaponRangeSquared)
   {
      // We can't track any more
      _cleanupTargetAndTurret();
      return;
   }

   mRot = rot;

   _setRotation( mRot );
   setMaskBits(TurretUpdateMask);
}
예제 #17
0
void FlyingVehicle::updateForces(F32 /*dt*/)
{
   PROFILE_SCOPE( FlyingVehicle_UpdateForces );

   MatrixF currPosMat;
   mRigid.getTransform(&currPosMat);
   mRigid.atRest = false;

   Point3F massCenter;
   currPosMat.mulP(mDataBlock->massCenter,&massCenter);

   Point3F xv,yv,zv;
   currPosMat.getColumn(0,&xv);
   currPosMat.getColumn(1,&yv);
   currPosMat.getColumn(2,&zv);
   F32 speed = mRigid.linVelocity.len();

   Point3F force  = Point3F(0, 0, sFlyingVehicleGravity * mRigid.mass * mGravityMod);
   Point3F torque = Point3F(0, 0, 0);

   // Drag at any speed
   force  -= mRigid.linVelocity * mDataBlock->minDrag;
   torque -= mRigid.angMomentum * mDataBlock->rotationalDrag;

   // Auto-stop at low speeds
   if (speed < mDataBlock->maxAutoSpeed) {
      F32 autoScale = 1 - speed / mDataBlock->maxAutoSpeed;

      // Gyroscope
      F32 gf = mDataBlock->autoAngularForce * autoScale;
      torque -= xv * gf * mDot(yv,Point3F(0,0,1));

      // Manuevering jets
      F32 sf = mDataBlock->autoLinearForce * autoScale;
      force -= yv * sf * mDot(yv, mRigid.linVelocity);
      force -= xv * sf * mDot(xv, mRigid.linVelocity);
   }

   // Hovering Jet
   F32 vf = -sFlyingVehicleGravity * mRigid.mass * mGravityMod;
   F32 h  = getHeight();
   if (h <= 1) {
      if (h > 0) {
         vf -= vf * h * 0.1;
      } else {
         vf += mDataBlock->jetForce * -h;
      }
   }
   force += zv * vf;

   // Damping "surfaces"
   force -= xv * mDot(xv,mRigid.linVelocity) * mDataBlock->horizontalSurfaceForce;
   force -= zv * mDot(zv,mRigid.linVelocity) * mDataBlock->verticalSurfaceForce;

   // Turbo Jet
   if (mJetting) {
      if (mThrustDirection == ThrustForward)
         force += yv * mDataBlock->jetForce * mCeilingFactor;
      else if (mThrustDirection == ThrustBackward)
         force -= yv * mDataBlock->jetForce * mCeilingFactor;
      else
         force += zv * mDataBlock->jetForce * mDataBlock->vertThrustMultiple * mCeilingFactor;
   }

   // Maneuvering jets
   force += yv * (mThrust.y * mDataBlock->maneuveringForce * mCeilingFactor);
   force += xv * (mThrust.x * mDataBlock->maneuveringForce * mCeilingFactor);

   // Steering
   Point2F steering;
   steering.x = mSteering.x / mDataBlock->maxSteeringAngle;
   steering.x *= mFabs(steering.x);
   steering.y = mSteering.y / mDataBlock->maxSteeringAngle;
   steering.y *= mFabs(steering.y);
   torque -= xv * steering.y * mDataBlock->steeringForce;
   torque -= zv * steering.x * mDataBlock->steeringForce;

   // Roll
   torque += yv * steering.x * mDataBlock->steeringRollForce;
   F32 ar = mDataBlock->autoAngularForce * mDot(xv,Point3F(0,0,1));
   ar -= mDataBlock->rollForce * mDot(xv, mRigid.linVelocity);
   torque += yv * ar;

   // Add in force from physical zones...
   force += mAppliedForce;

   // Container buoyancy & drag
   force -= Point3F(0, 0, 1) * (mBuoyancy * sFlyingVehicleGravity * mRigid.mass * mGravityMod);
   force -= mRigid.linVelocity * mDrag;

   //
   mRigid.force  = force;
   mRigid.torque = torque;
}
예제 #18
0
void TimeOfDay::_getSunColor( ColorF *outColor ) const
{
	  const COLOR_TARGET *ct = NULL;

   F32 ele = mClampF( M_2PI_F - mElevation, 0.0f, M_PI_F );
	  F32 phase = -1.0f;
	  F32 div;

   if (!mColorTargets.size())
   {
      outColor->set(1.0f,1.0f,1.0f);
      return;
   }

   if (mColorTargets.size() == 1)
   {
      ct = &mColorTargets[0];
      outColor->set(ct->color.red, ct->color.green, ct->color.blue);
      return;
   }

   //simple check
   if ( mColorTargets[0].elevation != 0.0f )
   {
      AssertFatal(0, "TimeOfDay::GetColor() - First elevation must be 0.0 radians")
      outColor->set(1.0f, 1.0f, 1.0f);
      //mBandMod = 1.0f;
      //mCurrentBandColor = color;
      return;
   }

   if ( mColorTargets[mColorTargets.size()-1].elevation != M_PI_F )
   {
      AssertFatal(0, "Celestails::GetColor() - Last elevation must be PI")
      outColor->set(1.0f, 1.0f, 1.0f);
      //mBandMod = 1.0f;
      //mCurrentBandColor = color;
      return;
   }

   //we need to find the phase and interp... also loop back around
   U32 count=0;
   for (;count < mColorTargets.size() - 1; count++)
   {
      const COLOR_TARGET *one = &mColorTargets[count];
      const COLOR_TARGET *two = &mColorTargets[count+1];

      if (ele >= one->elevation && ele <= two->elevation)
      {
			      div = two->elevation - one->elevation;
			
         //catch bad input divide by zero
         if ( mFabs( div ) < 0.01f )
            div = 0.01f;
			
			      phase = (ele - one->elevation) / div;
			      outColor->interpolate( one->color, two->color, phase );

			      //mCurrentBandColor.interpolate(one->bandColor, two->bandColor, phase);
			      //mBandMod = one->bandMod * (1.0f - phase) + two->bandMod * phase;

			      return;
		    }
	  }

	  AssertFatal(0,"This isn't supposed to happen");
}
예제 #19
0
F32 ScatterSky::_getMiePhase( F32 fCos, F32 fCos2, F32 g, F32 g2)
{
   return 1.5f * ((1.0f - g2) / (2.0f + g2)) * (1.0f + fCos2) / mPow(mFabs(1.0f + g2 - 2.0f*g*fCos), 1.5f);
}
예제 #20
0
/**
 * This method calculates the moves for the AI player
 *
 * @param movePtr Pointer to move the move list into
 */
bool AIPlayer::getAIMove(Move *movePtr)
{
   *movePtr = NullMove;

   // Use the eye as the current position.
   MatrixF eye;
   getEyeTransform(&eye);
   Point3F location = eye.getPosition();
   Point3F rotation = getRotation();

   // Orient towards the aim point, aim object, or towards
   // our destination.
   if (mAimObject || mAimLocationSet || mMoveState != ModeStop) 
   {
      // Update the aim position if we're aiming for an object
      if (mAimObject)
         mAimLocation = mAimObject->getPosition() + mAimOffset;
      else
         if (!mAimLocationSet)
            mAimLocation = mMoveDestination;

      F32 xDiff = mAimLocation.x - location.x;
      F32 yDiff = mAimLocation.y - location.y;

      if (!mIsZero(xDiff) || !mIsZero(yDiff)) 
      {
         // First do Yaw
         // use the cur yaw between -Pi and Pi
         F32 curYaw = rotation.z;
         while (curYaw > M_2PI_F)
            curYaw -= M_2PI_F;
         while (curYaw < -M_2PI_F)
            curYaw += M_2PI_F;

         // find the yaw offset
         F32 newYaw = mAtan2( xDiff, yDiff );
         F32 yawDiff = newYaw - curYaw;

         // make it between 0 and 2PI
         if( yawDiff < 0.0f )
            yawDiff += M_2PI_F;
         else if( yawDiff >= M_2PI_F )
            yawDiff -= M_2PI_F;

         // now make sure we take the short way around the circle
         if( yawDiff > M_PI_F )
            yawDiff -= M_2PI_F;
         else if( yawDiff < -M_PI_F )
            yawDiff += M_2PI_F;

         movePtr->yaw = yawDiff;

         // Next do pitch.
         if (!mAimObject && !mAimLocationSet) 
         {
            // Level out if were just looking at our next way point.
            Point3F headRotation = getHeadRotation();
            movePtr->pitch = -headRotation.x;
         }
         else 
         {
            // This should be adjusted to run from the
            // eye point to the object's center position. Though this
            // works well enough for now.
            F32 vertDist = mAimLocation.z - location.z;
            F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff);
            F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f );
            if (mFabs(newPitch) > 0.01f) 
            {
               Point3F headRotation = getHeadRotation();
               movePtr->pitch = newPitch - headRotation.x;
            }
         }
      }
   }
   else 
   {
      // Level out if we're not doing anything else
      Point3F headRotation = getHeadRotation();
      movePtr->pitch = -headRotation.x;
   }

   // Move towards the destination
   if (mMoveState != ModeStop) 
   {
      F32 xDiff = mMoveDestination.x - location.x;
      F32 yDiff = mMoveDestination.y - location.y;

      // Check if we should mMove, or if we are 'close enough'
      if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance) 
      {
         mMoveState = ModeStop;
         throwCallback("onReachDestination");
      }
      else 
      {
         // Build move direction in world space
         if (mIsZero(xDiff))
            movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f;
         else
            if (mIsZero(yDiff))
               movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f;
            else
               if (mFabs(xDiff) > mFabs(yDiff)) 
               {
                  F32 value = mFabs(yDiff / xDiff);
                  movePtr->y = (location.y > mMoveDestination.y) ? -value : value;
                  movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f;
               }
               else 
               {
                  F32 value = mFabs(xDiff / yDiff);
                  movePtr->x = (location.x > mMoveDestination.x) ? -value : value;
                  movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f;
               }

         // Rotate the move into object space (this really only needs
         // a 2D matrix)
         Point3F newMove;
         MatrixF moveMatrix;
         moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw)));
         moveMatrix.mulV( Point3F( movePtr->x, movePtr->y, 0.0f ), &newMove );
         movePtr->x = newMove.x;
         movePtr->y = newMove.y;

         // Set movement speed.  We'll slow down once we get close
         // to try and stop on the spot...
         if (mMoveSlowdown) 
         {
            F32 speed = mMoveSpeed;
            F32 dist = mSqrt(xDiff*xDiff + yDiff*yDiff);
            F32 maxDist = 5.0f;
            if (dist < maxDist)
               speed *= dist / maxDist;
            movePtr->x *= speed;
            movePtr->y *= speed;

            mMoveState = ModeSlowing;
         }
         else 
         {
            movePtr->x *= mMoveSpeed;
            movePtr->y *= mMoveSpeed;

            mMoveState = ModeMove;
         }

         if (mMoveStuckTestCountdown > 0)
            --mMoveStuckTestCountdown;
         else
         {
            // We should check to see if we are stuck...
            F32 locationDelta = (location - mLastLocation).len();
            if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled) 
            {
               // If we are slowing down, then it's likely that our location delta will be less than
               // our move stuck tolerance. Because we can be both slowing and stuck
               // we should TRY to check if we've moved. This could use better detection.
               if ( mMoveState != ModeSlowing || locationDelta == 0 )
               {
                  mMoveState = ModeStuck;
                  throwCallback("onMoveStuck");
               }
            }
         }
      }
   }

   // Test for target location in sight if it's an object. The LOS is
   // run from the eye position to the center of the object's bounding,
   // which is not very accurate.
   if (mAimObject) {
      MatrixF eyeMat;
      getEyeTransform(&eyeMat);
      eyeMat.getColumn(3,&location);
      Point3F targetLoc = mAimObject->getBoxCenter();

      // This ray ignores non-static shapes. Cast Ray returns true
      // if it hit something.
      RayInfo dummy;
      if (getContainer()->castRay( location, targetLoc,
            StaticShapeObjectType | StaticObjectType |
            TerrainObjectType, &dummy)) {
         if (mTargetInLOS) {
            throwCallback( "onTargetExitLOS" );
            mTargetInLOS = false;
         }
      }
      else
         if (!mTargetInLOS) {
            throwCallback( "onTargetEnterLOS" );
            mTargetInLOS = true;
         }
   }

   // Replicate the trigger state into the move so that
   // triggers can be controlled from scripts.
   for( int i = 0; i < MaxTriggerKeys; i++ )
      movePtr->trigger[i] = getImageTriggerState(i);

   mLastLocation = location;

   return true;
}
예제 #21
0
Point2I GuiColorPickerCtrl::findColor(const ColorF & color, const Point2I& offset, const Point2I& resolution, GBitmap& bmp)
{
   RectI rect;
   Point2I ext = getExtent();
   if (mDisplayMode != pDropperBackground)
   {
      ext.x -= 3;
      ext.y -= 2;
      rect = RectI(Point2I(1, 1), ext);
   }
   else
   {
      rect = RectI(Point2I(0, 0), ext);
   }

   Point2I closestPos(-1, -1);

   /* Debugging
   char filename[256];
   dSprintf( filename, 256, "%s.%s", "colorPickerTest", "png" );

   // Open up the file on disk.
   FileStream fs;
   if ( !fs.open( filename, Torque::FS::File::Write ) )
   Con::errorf( "GuiObjectView::saveAsImage() - Failed to open output file '%s'!", filename );
   else
   {
   // Write it and close.
   bmp.writeBitmap( "png", fs );

   fs.close();
   }
   */

   ColorI tmp;
   U32 buf_x;
   U32 buf_y;
   ColorF curColor;
   F32 val(10000.0f);
   F32 closestVal(10000.0f);
   bool closestSet = false;

   for (S32 x = rect.point.x; x <= rect.extent.x; x++)
   {
      for (S32 y = rect.point.y; y <= rect.extent.y; y++)
      {
         buf_x = offset.x + x + 1;
         buf_y = (resolution.y - (offset.y + y + 1));
         buf_y = resolution.y - buf_y;

         //Get the color at that position
         bmp.getColor(buf_x, buf_y, tmp);
         curColor = (ColorF)tmp;

         //Evaluate how close the color is to our desired color
         val = mFabs(color.red - curColor.red) + mFabs(color.green - curColor.green) + mFabs(color.blue - curColor.blue);

         if (!closestSet)
         {
            closestVal = val;
            closestPos.set(x, y);
            closestSet = true;
         }
         else if (val < closestVal)
         {
            closestVal = val;
            closestPos.set(x, y);
         }
      }
   }

   return closestPos;
}
예제 #22
0
AtlasDiscreteMesh *AtlasDiscreteMesh::decimate(U32 target)
{
#ifndef ENABLE_DECIMATION
   Con::errorf("AtlasDiscreteMesh::decimate - decimation not enabled, define ENABLE_DECIMATION!");
   return NULL;
#else

// collapse rules:
// 
// side to top, to what vert (if any)
//
//	        center	edge	corner	never
// center  	any	edge	corner	never
// edge	   -	   line	corner	-
// corner	-	   -	   -	      -
// never  	-	   -	   -	      -

   // First, copy ourselves into a MxStdModel
   MxStdModel sm(mVertexCount, mIndexCount/3);

   sm.texcoord_binding(MX_PERVERTEX);
   sm.normal_binding(MX_PERVERTEX);

   for(U32 i=0; i<mVertexCount; i++)
   {
      sm.add_texcoord(mTex[i].x, mTex[i].y);
      sm.add_vertex(mPos[i].x, mPos[i].y, mPos[i].z);
      sm.add_normal(mNormal[i].x, mNormal[i].y, mNormal[i].z);
   }

   for(U32 i=0; i<mIndexCount; i+=3)
      sm.add_face(mIndex[i+0],mIndex[i+1],mIndex[i+2]);

   Con::printf("AtlasDiscreteMesh::decimate - starting with %d verts, %d indices, %d faces allocated.", 
                     sm.vert_count(), mIndexCount, sm.face_count());

   // Run it through the decimator.
   MxEdgeQSlim qslim(sm);

   qslim.placement_policy = MX_PLACE_ENDORMID; //MX_PLACE_OPTIMAL; <-- optimal causes f'ed up results!
   qslim.weighting_policy = MX_WEIGHT_AREA_AVG;
   qslim.compactness_ratio = 0.0;
   qslim.meshing_penalty = 1.0;
   qslim.will_join_only = false;

   // Now, calculate our constraints - basically take everything that's within
   // 0.1 meters of a bounding plane and mark it with that plane's IDs. Our
   // bounding planes are the 4 vertical faces of the bounding box.
   PlaneF planes[4];
   Box3F bounds = calcBounds();

   // Generate planes from three points... Up is z+, and the normal for the
   // plane should face towards the center (but it doesn't really matter, we
   // only ever take absolute distance).
   {
      Point3F a,b,c;
      a.x = bounds.minExtents.x;
      a.y = bounds.minExtents.y;
      a.z = bounds.minExtents.z;

      b.x = bounds.maxExtents.x;
      b.y = bounds.minExtents.y;
      b.z = bounds.minExtents.z;

      c = a + Point3F(0, 0, 10);

      planes[0].set(a,b,c);
   }
   {
      Point3F a,b,c;
      a.x = bounds.maxExtents.x;
      a.y = bounds.minExtents.y;
      a.z = bounds.minExtents.z;

      b.x = bounds.maxExtents.x;
      b.y = bounds.maxExtents.y;
      b.z = bounds.minExtents.z;

      c = a + Point3F(0, 0, 10);

      planes[1].set(a,b,c);
   }
   {
      Point3F a,b,c;
      a.x = bounds.maxExtents.x;
      a.y = bounds.maxExtents.y;
      a.z = bounds.minExtents.z;

      b.x = bounds.minExtents.x;
      b.y = bounds.maxExtents.y;
      b.z = bounds.minExtents.z;

      c = a + Point3F(0, 0, 10);

      planes[2].set(a,b,c);
   }
   {
      Point3F a,b,c;
      a.x = bounds.minExtents.x;
      a.y = bounds.maxExtents.y;
      a.z = bounds.minExtents.z;

      b.x = bounds.minExtents.x;
      b.y = bounds.minExtents.y;
      b.z = bounds.minExtents.z;

      c = a + Point3F(0, 0, 10);

      planes[3].set(a,b,c);
   }

   // Now categorize everything w/ constraints.
   for(U32 i=0; i<mVertexCount; i++)
   {
      U8 bits=0;
      for(S32 j=0; j<4; j++)
      {
         F32 d = mFabs(planes[j].distToPlane(mPos[i]));

         if(d < .1)
            bits |= BIT(j);
      }

      qslim.planarConstraints(i) = bits;
   }

   // Now we initialize and constrain...
   qslim.initialize();
   qslim.decimate(target);

   // Copy everything out to a new ADM
   AtlasDiscreteMesh *admOut = new AtlasDiscreteMesh();

   // First, mark stray vertices for removal
   for(U32 i=0; i<sm.vert_count(); i++)
      if(sm.vertex_is_valid(i) && sm.neighbors(i).length() == 0 )
         sm.vertex_mark_invalid(i);

   // Compact vertex array so only valid vertices remain
   sm.compact_vertices();

   // Copy verts out. Get a count, first.
   U32 vertCount = 0;

   for(U32 i=0; i<sm.vert_count(); i++)
      if(sm.vertex_is_valid(i))
         vertCount++;

   admOut->mVertexCount = vertCount;
   admOut->mPos         = new Point3F[vertCount];
   admOut->mTex         = new Point2F[vertCount];
   admOut->mNormal      = new Point3F[vertCount];

   for(S32 i=0; i<vertCount; i++)
   {
      if(!sm.vertex_is_valid(i))
         continue;

      const MxVertex   &v = qslim.model().vertex(i);
      const MxTexCoord &t = qslim.model().texcoord(i);
      const MxNormal   &n = qslim.model().normal(i);

      admOut->mPos[i].x    = v[0];
      admOut->mPos[i].y    = v[1];
      admOut->mPos[i].z    = v[2];

      admOut->mTex[i].x    = t[0];
      admOut->mTex[i].y    = t[1];
      
      admOut->mNormal[i].x = n[0];
      admOut->mNormal[i].y = n[1];
      admOut->mNormal[i].z = n[2];
   }

   // We have to ignore non-valid faces, so let's recount our idxCount.
   U32 idxCount = 0;

   for(U32 i=0; i < sm.face_count(); i++)
      if(sm.face_is_valid(i))
         idxCount += 3;

   Con::printf("AtlasDiscreteMesh::decimate - %d out of %d verts, %d out of %d indices.", 
      vertCount, sm.vert_count(), idxCount, sm.face_count() * 3);

   admOut->mIndexCount = idxCount;
   admOut->mIndex = new U16[idxCount];

   U16 *idx = admOut->mIndex;

   for(S32 i=0; i < sm.face_count(); i++)
   {
      // Skip invalid.
      if(!sm.face_is_valid(i))
         continue;

      const MxFace &f = sm.face(i);

      idx[0] = f[0];
      idx[1] = f[1];
      idx[2] = f[2];

      //Con::printf("                 face #%d (%d, %d, %d)", i, f[0], f[1], f[2]);

      idx += 3;
   }

   // Make sure our vert and index counts are accurate.
   admOut->mIndexCount = idx - admOut->mIndex;

   return admOut;
#endif
}
예제 #23
0
void TSShapeInstance::renderDebugNormals( F32 normalScalar, S32 dl )
{
   if ( dl < 0 )
      return;

   AssertFatal( dl >= 0 && dl < mShape->details.size(),
      "TSShapeInstance::renderDebugNormals() - Bad detail level!" );

   static GFXStateBlockRef sb;
   if ( sb.isNull() )
   {
      GFXStateBlockDesc desc;
      desc.setCullMode( GFXCullNone );
      desc.setZReadWrite( true );
      desc.zWriteEnable = false;
      desc.vertexColorEnable = true;

      sb = GFX->createStateBlock( desc );
   }
   GFX->setStateBlock( sb );

   const TSDetail *detail = &mShape->details[dl];
   const S32 ss = detail->subShapeNum;
   if ( ss < 0 )
      return;

   const S32 start = mShape->subShapeFirstObject[ss];
   const S32 end   = start + mShape->subShapeNumObjects[ss];

   for ( S32 i = start; i < end; i++ )
   {
      MeshObjectInstance *meshObj = &mMeshObjects[i];
      if ( !meshObj )
         continue;

      const MatrixF &meshMat = meshObj->getTransform();

      // Then go through each TSMesh...
      U32 m = 0;
      for( TSMesh *mesh = meshObj->getMesh(m); mesh != NULL; mesh = meshObj->getMesh(m++) )
      {
         // and pull out the list of normals.
         const U32 numNrms = mesh->mNumVerts;
         PrimBuild::begin( GFXLineList, 2 * numNrms );
         for ( U32 n = 0; n < numNrms; n++ )
         {
            Point3F norm = mesh->mVertexData[n].normal();
            Point3F vert = mesh->mVertexData[n].vert();

            meshMat.mulP( vert );
            meshMat.mulV( norm );

            // Then render them.
            PrimBuild::color4f( mFabs( norm.x ), mFabs( norm.y ), mFabs( norm.z ), 1.0f );
            PrimBuild::vertex3fv( vert );
            PrimBuild::vertex3fv( vert + (norm * normalScalar) );
         }

         PrimBuild::end();
      }
   }
}
예제 #24
0
   "@brief Find objects matching the bitmask type within a box centered at point, with extents x, y, z.\n\n"
   "@returns The first object found, or an empty string if nothing was found.  Thereafter, you can get more "
   "results using containerFindNext()."
   "@see containerFindNext\n"
   "@ingroup Game")
{
   //find out what we're looking for
   U32 typeMask = U32(dAtoi(argv[1]));

   //find the center of the container volume
   Point3F origin(0.0f, 0.0f, 0.0f);
   dSscanf(argv[2], "%g %g %g", &origin.x, &origin.y, &origin.z);

   //find the box dimensions
   Point3F size(0.0f, 0.0f, 0.0f);
   size.x = mFabs(dAtof(argv[3]));
   size.y = mFabs(dAtof(argv[4]));
   size.z = mFabs(dAtof(argv[5]));

   //build the container volume
   Box3F queryBox;
   queryBox.minExtents = origin;
   queryBox.maxExtents = origin;
   queryBox.minExtents -= size;
   queryBox.maxExtents += size;

   //initialize the list, and do the query
   sgServerQueryList.mList.clear();
   gServerContainer.findObjects(queryBox, typeMask, SimpleQueryList::insertionCallback, &sgServerQueryList);

   //return the first element
예제 #25
0
파일: mBox.cpp 프로젝트: jamesu/libDTShape
bool Box3F::collideOrientedBox(const Point3F & bRadii, const MatrixF & toA) const
{
   Point3F p;
   toA.getColumn(3,&p);
   Point3F aCenter = minExtents + maxExtents;
   aCenter *= 0.5f;
   p -= aCenter; // this essentially puts origin of toA target space on the center of the current box
   Point3F aRadii = maxExtents - minExtents;
   aRadii *= 0.5f;

	F32 absXX,absXY,absXZ;
	F32 absYX,absYY,absYZ;
	F32 absZX,absZY,absZZ;

   const F32 * f = toA;

   absXX = mFabs(f[0]);
   absYX = mFabs(f[1]);
   absZX = mFabs(f[2]);

	if (aRadii.x + bRadii.x * absXX + bRadii.y * absYX + bRadii.z * absZX - mFabs(p.x)<0.0f)
		return false;

   absXY = mFabs(f[4]);
   absYY = mFabs(f[5]);
   absZY = mFabs(f[6]);
	if (aRadii.y + bRadii.x * absXY +	bRadii.y * absYY +	bRadii.z * absZY - mFabs(p.y)<0.0f)
		return false;
	
   absXZ = mFabs(f[8]);
   absYZ = mFabs(f[9]);
   absZZ = mFabs(f[10]);
	if (aRadii.z + bRadii.x * absXZ + bRadii.y * absYZ +	bRadii.z * absZZ - mFabs(p.z)<0.0f)
		return false;

	if (aRadii.x*absXX + aRadii.y*absXY + aRadii.z*absXZ + bRadii.x - mFabs(p.x*f[0] + p.y*f[4] + p.z*f[8])<0.0f)
		return false;

	if (aRadii.x*absYX + aRadii.y*absYY + aRadii.z*absYZ + bRadii.y - mFabs(p.x*f[1] + p.y*f[5] + p.z*f[9])<0.0f)
		return false;		
	
	if (aRadii.x*absZX + aRadii.y*absZY + aRadii.z*absZZ + bRadii.z - mFabs(p.x*f[2] + p.y*f[6] + p.z*f[10])<0.0f)
		return false;		
	
	if (mFabs(p.z*f[4] - p.y*f[8]) >
				aRadii.y * absXZ + aRadii.z * absXY +
				bRadii.y * absZX + bRadii.z * absYX)
		return false;
	
	if (mFabs(p.z*f[5] - p.y*f[9]) >
				aRadii.y * absYZ + aRadii.z * absYY +
				bRadii.x * absZX + bRadii.z * absXX)
		return false;
	
	if (mFabs(p.z*f[6] - p.y*f[10]) >
				aRadii.y * absZZ + aRadii.z * absZY +
				bRadii.x * absYX + bRadii.y * absXX)
		return false;
	
	if (mFabs(p.x*f[8] - p.z*f[0]) >
				aRadii.x * absXZ + aRadii.z * absXX +
				bRadii.y * absZY + bRadii.z * absYY)
		return false;
	
	if (mFabs(p.x*f[9] - p.z*f[1]) >
				aRadii.x * absYZ + aRadii.z * absYX +
				bRadii.x * absZY + bRadii.z * absXY)
		return false;
	
	if (mFabs(p.x*f[10] - p.z*f[2]) >
				aRadii.x * absZZ + aRadii.z * absZX +
				bRadii.x * absYY + bRadii.y * absXY)
		return false;
	
	if (mFabs(p.y*f[0] - p.x*f[4]) >
				aRadii.x * absXY + aRadii.y * absXX +
				bRadii.y * absZZ + bRadii.z * absYZ)
		return false;
	
	if (mFabs(p.y*f[1] - p.x*f[5]) >
				aRadii.x * absYY + aRadii.y * absYX +
				bRadii.x * absZZ + bRadii.z * absXZ)
		return false;
	
	if (mFabs(p.y*f[2] - p.x*f[6]) >
				aRadii.x * absZY + aRadii.y * absZX +
				bRadii.x * absYZ + bRadii.y * absXZ)
		return false;
	
	return true;
}
예제 #26
0
//-----------------------------------------------------------------------------
// Mouse Events
//-----------------------------------------------------------------------------
void WindowInputGenerator::handleMouseMove( WindowId did, U32 modifier, S32 x, S32 y, bool isRelative )
{
    if( !mInputController || !mFocused )
        return;

    // jddTODO : Clean this up
    // CodeReview currently the Torque GuiCanvas deals with mouse input
    //  as relative movement, even when the cursor is visible.  Because
    //  of this there is an asinine bit of code in there that manages
    //  updating the cursor position on the class based on relative movement.
    //  Because of this we always have to generate and send off for processing
    //  relative events, even if the mouse is not locked.
    //  I'm considering removing this in the Canvas refactor, thoughts? [7/6/2007 justind]

    // Generate a base Movement along and Axis event
    InputEventInfo event;
    event.deviceType = MouseDeviceType;
    event.deviceInst = 0;
    event.objType    = SI_AXIS;
    event.modifier   = convertModifierBits(modifier);
    event.ascii      = 0;

    // Generate delta movement along each axis
    Point2F cursDelta;
    if(isRelative)
    {
        cursDelta.x = F32(x) * mPixelsPerMickey;
        cursDelta.y = F32(y) * mPixelsPerMickey;
    }
    else
    {
        cursDelta.x = F32(x - mLastCursorPos.x);
        cursDelta.y = F32(y - mLastCursorPos.y);
    }

    // If X axis changed, generate a relative event
    if(mFabs(cursDelta.x) > 0.1)
    {
        event.objInst    = SI_XAXIS;
        event.action     = SI_MOVE;
        event.fValue     = cursDelta.x;
        generateInputEvent(event);
    }

    // If Y axis changed, generate a relative event
    if(mFabs(cursDelta.y) > 0.1)
    {
        event.objInst    = SI_YAXIS;
        event.action     = SI_MOVE;
        event.fValue     = cursDelta.y;
        generateInputEvent(event);
    }

    //  CodeReview : If we're not relative, pass along a positional update
    //  so that the canvas can update it's internal cursor tracking
    //  point. [7/6/2007 justind]
    if( !isRelative )
    {
        if( mClampToWindow )
        {
            Point2I winExtent = mWindow->getClientExtent();
            x = mClampF(x, 0.0f, F32(winExtent.x  - 1));
            y = mClampF(y, 0.0f, F32(winExtent.y  - 1));

        }

        // When the window gains focus, we send a cursor position event
        if( mNotifyPosition )
        {
            mNotifyPosition = false;

            // We use SI_MAKE to signify that the position is being set, not relatively moved.
            event.action     = SI_MAKE;

            // X Axis
            event.objInst    = SI_XAXIS;
            event.fValue     = (F32)x;
            generateInputEvent(event);

            // Y Axis
            event.objInst = SI_YAXIS;
            event.fValue     = (F32)y;
            generateInputEvent(event);
        }

        mLastCursorPos = Point2I(x,y);

    }
    else
    {
        mLastCursorPos += Point2I(x,y);
        mNotifyPosition = true;
    }
}
예제 #27
0
bool DecalManager::clipDecal( DecalInstance *decal, Vector<Point3F> *edgeVerts, const Point2F *clipDepth )
{
   PROFILE_SCOPE( DecalManager_clipDecal );

   // Free old verts and indices.
   _freeBuffers( decal );

   ClippedPolyList clipper;

   clipper.mNormal.set( Point3F( 0, 0, 0 ) );
   clipper.mPlaneList.setSize(6);

   F32 halfSize = decal->mSize * 0.5f;
   
   // Ugly hack for ProjectedShadow!
   F32 halfSizeZ = clipDepth ? clipDepth->x : halfSize;
   F32 negHalfSize = clipDepth ? clipDepth->y : halfSize;
   Point3F decalHalfSize( halfSize, halfSize, halfSize );
   Point3F decalHalfSizeZ( halfSizeZ, halfSizeZ, halfSizeZ );

   MatrixF projMat( true );
   decal->getWorldMatrix( &projMat );

   const VectorF &crossVec = decal->mNormal;
   const Point3F &decalPos = decal->mPosition;

   VectorF newFwd, newRight;
   projMat.getColumn( 0, &newRight );
   projMat.getColumn( 1, &newFwd );   

   VectorF objRight( 1.0f, 0, 0 );
   VectorF objFwd( 0, 1.0f, 0 );
   VectorF objUp( 0, 0, 1.0f );

   // See above re: decalHalfSizeZ hack.
   clipper.mPlaneList[0].set( ( decalPos + ( -newRight * halfSize ) ), -newRight );
   clipper.mPlaneList[1].set( ( decalPos + ( -newFwd * halfSize ) ), -newFwd );
   clipper.mPlaneList[2].set( ( decalPos + ( -crossVec * decalHalfSizeZ ) ), -crossVec );
   clipper.mPlaneList[3].set( ( decalPos + ( newRight * halfSize ) ), newRight );
   clipper.mPlaneList[4].set( ( decalPos + ( newFwd * halfSize ) ), newFwd );
   clipper.mPlaneList[5].set( ( decalPos + ( crossVec * negHalfSize ) ), crossVec );

   clipper.mNormal = -decal->mNormal;

   Box3F box( -decalHalfSizeZ, decalHalfSizeZ );

   projMat.mul( box );

   DecalData *decalData = decal->mDataBlock;

   PROFILE_START( DecalManager_clipDecal_buildPolyList );
   getContainer()->buildPolyList( box, decalData->clippingMasks, &clipper );   
   PROFILE_END();

   clipper.cullUnusedVerts();
   clipper.triangulate();
   clipper.generateNormals();
   
   if ( clipper.mVertexList.empty() )
      return false;

#ifdef DECALMANAGER_DEBUG
   mDebugPlanes.clear();
   mDebugPlanes.merge( clipper.mPlaneList );
#endif

   decal->mVertCount = clipper.mVertexList.size();
   decal->mIndxCount = clipper.mIndexList.size();
   
   Vector<Point3F> tmpPoints;

   tmpPoints.push_back(( objFwd * decalHalfSize ) + ( objRight * decalHalfSize ));
   tmpPoints.push_back(( objFwd * decalHalfSize ) + ( -objRight * decalHalfSize ));
   tmpPoints.push_back(( -objFwd * decalHalfSize ) + ( -objRight * decalHalfSize ));
   
   Point3F lowerLeft(( -objFwd * decalHalfSize ) + ( objRight * decalHalfSize ));

   projMat.inverse();

   _generateWindingOrder( lowerLeft, &tmpPoints );

   BiQuadToSqr quadToSquare( Point2F( lowerLeft.x, lowerLeft.y ),
                             Point2F( tmpPoints[0].x, tmpPoints[0].y ), 
                             Point2F( tmpPoints[1].x, tmpPoints[1].y ), 
                             Point2F( tmpPoints[2].x, tmpPoints[2].y ) );  

   Point2F uv( 0, 0 );
   Point3F vecX(0.0f, 0.0f, 0.0f);

   // Allocate memory for vert and index arrays
   _allocBuffers( decal );  
   
   Point3F vertPoint( 0, 0, 0 );

   for ( U32 i = 0; i < clipper.mVertexList.size(); i++ )
   {
      const ClippedPolyList::Vertex &vert = clipper.mVertexList[i];
      vertPoint = vert.point;

      // Transform this point to
      // object space to look up the
      // UV coordinate for this vertex.
      projMat.mulP( vertPoint );

      // Clamp the point to be within the quad.
      vertPoint.x = mClampF( vertPoint.x, -decalHalfSize.x, decalHalfSize.x );
      vertPoint.y = mClampF( vertPoint.y, -decalHalfSize.y, decalHalfSize.y );

      // Get our UV.
      uv = quadToSquare.transform( Point2F( vertPoint.x, vertPoint.y ) );

      const RectF &rect = decal->mDataBlock->texRect[decal->mTextureRectIdx];

      uv *= rect.extent;
      uv += rect.point;      

      // Set the world space vertex position.
      decal->mVerts[i].point = vert.point;
      
      decal->mVerts[i].texCoord.set( uv.x, uv.y );
      
      decal->mVerts[i].normal = clipper.mNormalList[i];
      
      decal->mVerts[i].normal.normalize();

      if( mFabs( decal->mVerts[i].normal.z ) > 0.8f ) 
         mCross( decal->mVerts[i].normal, Point3F( 1.0f, 0.0f, 0.0f ), &vecX );
      else if ( mFabs( decal->mVerts[i].normal.x ) > 0.8f )
         mCross( decal->mVerts[i].normal, Point3F( 0.0f, 1.0f, 0.0f ), &vecX );
      else if ( mFabs( decal->mVerts[i].normal.y ) > 0.8f )
         mCross( decal->mVerts[i].normal, Point3F( 0.0f, 0.0f, 1.0f ), &vecX );
   
      decal->mVerts[i].tangent = mCross( decal->mVerts[i].normal, vecX );
   }

   U32 curIdx = 0;
   for ( U32 j = 0; j < clipper.mPolyList.size(); j++ )
   {
      // Write indices for each Poly
      ClippedPolyList::Poly *poly = &clipper.mPolyList[j];                  

      AssertFatal( poly->vertexCount == 3, "Got non-triangle poly!" );

      decal->mIndices[curIdx] = clipper.mIndexList[poly->vertexStart];         
      curIdx++;
      decal->mIndices[curIdx] = clipper.mIndexList[poly->vertexStart + 1];            
      curIdx++;
      decal->mIndices[curIdx] = clipper.mIndexList[poly->vertexStart + 2];                
      curIdx++;
   } 

   if ( !edgeVerts )
      return true;

   Point3F tmpHullPt( 0, 0, 0 );
   Vector<Point3F> tmpHullPts;

   for ( U32 i = 0; i < clipper.mVertexList.size(); i++ )
   {
      const ClippedPolyList::Vertex &vert = clipper.mVertexList[i];
      tmpHullPt = vert.point;
      projMat.mulP( tmpHullPt );
      tmpHullPts.push_back( tmpHullPt );
   }

   edgeVerts->clear();
   U32 verts = _generateConvexHull( tmpHullPts, edgeVerts );
   edgeVerts->setSize( verts );

   projMat.inverse();
   for ( U32 i = 0; i < edgeVerts->size(); i++ )
      projMat.mulP( (*edgeVerts)[i] );

   return true;
}
예제 #28
0
/**
 * This method calculates the moves for the AI player
 *
 * @param movePtr Pointer to move the move list into
 */
bool AIPlayer::getAIMove(Move *movePtr)
{
   *movePtr = NullMove;

   // Use the eye as the current position.
   MatrixF eye;
   getEyeTransform(&eye);
   Point3F location = eye.getPosition();
   Point3F rotation = getRotation();

#ifdef TORQUE_NAVIGATION_ENABLED
   if(mDamageState == Enabled)
   {
      if(mMoveState != ModeStop)
         updateNavMesh();
      if(!mFollowData.object.isNull())
      {
         if(mPathData.path.isNull())
         {
            if((getPosition() - mFollowData.object->getPosition()).len() > mFollowData.radius)
               followObject(mFollowData.object, mFollowData.radius);
         }
         else
         {
            if((mPathData.path->mTo - mFollowData.object->getPosition()).len() > mFollowData.radius)
               repath();
            else if((getPosition() - mFollowData.object->getPosition()).len() < mFollowData.radius)
            {
               clearPath();
               mMoveState = ModeStop;
            throwCallback("onTargetInRange");
            }
            else if((getPosition() - mFollowData.object->getPosition()).len() < mAttackRadius)
            {
            throwCallback("onTargetInFiringRange");
            }
         }
      }
   }
#endif // TORQUE_NAVIGATION_ENABLED

   // Orient towards the aim point, aim object, or towards
   // our destination.
   if (mAimObject || mAimLocationSet || mMoveState != ModeStop) 
   {
      // Update the aim position if we're aiming for an object
      if (mAimObject)
         mAimLocation = mAimObject->getPosition() + mAimOffset;
      else
         if (!mAimLocationSet)
            mAimLocation = mMoveDestination;

      F32 xDiff = mAimLocation.x - location.x;
      F32 yDiff = mAimLocation.y - location.y;

      if (!mIsZero(xDiff) || !mIsZero(yDiff)) 
      {
         // First do Yaw
         // use the cur yaw between -Pi and Pi
         F32 curYaw = rotation.z;
         while (curYaw > M_2PI_F)
            curYaw -= M_2PI_F;
         while (curYaw < -M_2PI_F)
            curYaw += M_2PI_F;

         // find the yaw offset
         F32 newYaw = mAtan2( xDiff, yDiff );
         F32 yawDiff = newYaw - curYaw;

         // make it between 0 and 2PI
         if( yawDiff < 0.0f )
            yawDiff += M_2PI_F;
         else if( yawDiff >= M_2PI_F )
            yawDiff -= M_2PI_F;

         // now make sure we take the short way around the circle
         if( yawDiff > M_PI_F )
            yawDiff -= M_2PI_F;
         else if( yawDiff < -M_PI_F )
            yawDiff += M_2PI_F;

         movePtr->yaw = yawDiff;

         // Next do pitch.
         if (!mAimObject && !mAimLocationSet) 
         {
            // Level out if were just looking at our next way point.
            Point3F headRotation = getHeadRotation();
            movePtr->pitch = -headRotation.x;
         }
         else 
         {
            // This should be adjusted to run from the
            // eye point to the object's center position. Though this
            // works well enough for now.
            F32 vertDist = mAimLocation.z - location.z;
            F32 horzDist = mSqrt(xDiff * xDiff + yDiff * yDiff);
            F32 newPitch = mAtan2( horzDist, vertDist ) - ( M_PI_F / 2.0f );
            if (mFabs(newPitch) > 0.01f) 
            {
               Point3F headRotation = getHeadRotation();
               movePtr->pitch = newPitch - headRotation.x;
            }
         }
      }
   }
   else 
   {
      // Level out if we're not doing anything else
      Point3F headRotation = getHeadRotation();
      movePtr->pitch = -headRotation.x;
   }

   // Move towards the destination
   if (mMoveState != ModeStop) 
   {
      F32 xDiff = mMoveDestination.x - location.x;
      F32 yDiff = mMoveDestination.y - location.y;

      // Check if we should mMove, or if we are 'close enough'
      if (mFabs(xDiff) < mMoveTolerance && mFabs(yDiff) < mMoveTolerance) 
      {
         mMoveState = ModeStop;
         onReachDestination();
      }
      else 
      {
         // Build move direction in world space
         if (mIsZero(xDiff))
            movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f;
         else
            if (mIsZero(yDiff))
               movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f;
            else
               if (mFabs(xDiff) > mFabs(yDiff)) 
               {
                  F32 value = mFabs(yDiff / xDiff);
                  movePtr->y = (location.y > mMoveDestination.y) ? -value : value;
                  movePtr->x = (location.x > mMoveDestination.x) ? -1.0f : 1.0f;
               }
               else 
               {
                  F32 value = mFabs(xDiff / yDiff);
                  movePtr->x = (location.x > mMoveDestination.x) ? -value : value;
                  movePtr->y = (location.y > mMoveDestination.y) ? -1.0f : 1.0f;
               }

         // Rotate the move into object space (this really only needs
         // a 2D matrix)
         Point3F newMove;
         MatrixF moveMatrix;
         moveMatrix.set(EulerF(0.0f, 0.0f, -(rotation.z + movePtr->yaw)));
         moveMatrix.mulV( Point3F( movePtr->x, movePtr->y, 0.0f ), &newMove );
         movePtr->x = newMove.x;
         movePtr->y = newMove.y;

         // Set movement speed.  We'll slow down once we get close
         // to try and stop on the spot...
         if (mMoveSlowdown) 
         {
            F32 speed = mMoveSpeed;
            F32 dist = mSqrt(xDiff*xDiff + yDiff*yDiff);
            F32 maxDist = mMoveTolerance*2;
            if (dist < maxDist)
               speed *= dist / maxDist;
            movePtr->x *= speed;
            movePtr->y *= speed;

            mMoveState = ModeSlowing;
         }
         else 
         {
            movePtr->x *= mMoveSpeed;
            movePtr->y *= mMoveSpeed;

            mMoveState = ModeMove;
         }

         if (mMoveStuckTestCountdown > 0)
            --mMoveStuckTestCountdown;
         else
         {
            // We should check to see if we are stuck...
            F32 locationDelta = (location - mLastLocation).len();
            if (locationDelta < mMoveStuckTolerance && mDamageState == Enabled) 
            {
               // If we are slowing down, then it's likely that our location delta will be less than
               // our move stuck tolerance. Because we can be both slowing and stuck
               // we should TRY to check if we've moved. This could use better detection.
               if ( mMoveState != ModeSlowing || locationDelta == 0 )
               {
                  mMoveState = ModeStuck;
                  onStuck();
               }
            }
         }
      }
   }

   // Test for target location in sight if it's an object. The LOS is
   // run from the eye position to the center of the object's bounding,
   // which is not very accurate.
   if (mAimObject)
   {
      if (checkInLos(mAimObject.getPointer()))
      {
         if (!mTargetInLOS)
         {
            throwCallback( "onTargetEnterLOS" );
            mTargetInLOS = true;
         }
   }
      else if (mTargetInLOS)
      {
            throwCallback( "onTargetExitLOS" );
            mTargetInLOS = false;
         }
      }

   Pose desiredPose = mPose;

   if ( mSwimming )  
      desiredPose = SwimPose;   
   else if ( mAiPose == 1 && canCrouch() )   
      desiredPose = CrouchPose;  
   else if ( mAiPose == 2 && canProne() )  
      desiredPose = PronePose;  
   else if ( mAiPose == 3 && canSprint() )  
      desiredPose = SprintPose;  
   else if ( canStand() )  
      desiredPose = StandPose;  
  
   setPose( desiredPose );
   
   // Replicate the trigger state into the move so that
   // triggers can be controlled from scripts.
   for( U32 i = 0; i < MaxTriggerKeys; i++ )
      movePtr->trigger[ i ] = getImageTriggerState( i );

#ifdef TORQUE_NAVIGATION_ENABLED
   if(mJump == Now)
   {
      movePtr->trigger[2] = true;
      mJump = None;
   }
   else if(mJump == Ledge)
   {
      // If we're not touching the ground, jump!
      RayInfo info;
      if(!getContainer()->castRay(getPosition(), getPosition() - Point3F(0, 0, 0.4f), StaticShapeObjectType, &info))
      {
         movePtr->trigger[2] = true;
         mJump = None;
      }
   }
#endif // TORQUE_NAVIGATION_ENABLED

   mLastLocation = location;

   return true;
}
예제 #29
0
//--------------------------------------------------------
//--------------------------------------------------------
// JK: faster ray->convexHull test - taken from TSMesh...
//
// Used by lighting system...
//
bool castRayBrush(const Point3F &start, const Point3F &end,
				  PlaneF *planes, U32 planeCount)
{
   //   F32 startTime = -0.01f;
   F32 startNum = -0.01f;
   F32 startDen =  1.00f;
   //   F32 endTime   = 1.01f;
   F32 endNum = 1.01f;
   F32 endDen = 1.00f;

   S32 curPlane = 0;
   U32 curMaterial = 0;
   bool found = false;

   bool tmpFound;
   S32 tmpPlane;
   F32 sgn = -1.0f;
   F32 * pnum = &startNum;
   F32 * pden = &startDen;
   S32 * pplane = &curPlane;
   bool * pfound = &found;

   for (S32 i=0; i<planeCount; i++)
   {
      // if start & end outside, no collision
      // if start & end inside, continue
      // if start outside, end inside, or visa versa, find intersection of line with plane
      //    then update intersection of line with hull (using startTime and endTime)
      F32 dot1 = mDot(planes[i],start) + planes[i].d;
      F32 dot2 = mDot(planes[i],end) + planes[i].d;
      if (dot1*dot2>0.0f)
      {
         // same side of the plane...which side -- dot==0 considered inside
         if (dot1>0.0f)
            // start and end outside of this plane, no collision
            return false;
         // start and end inside plane, continue
         continue;
      }

      AssertFatal(dot1/(dot1-dot2)>=0.0f && dot1/(dot1-dot2)<=1.0f,"TSMesh::castRay (1)");

      // find intersection (time) with this plane...
      // F32 time = dot1 / (dot1-dot2);
      F32 num = mFabs(dot1);
      F32 den = mFabs(dot1-dot2);

      if (sgn*dot1>=0)
      {
         sgn *= -1.0f;
         pnum = (F32*) ((dsize_t)pnum ^ (dsize_t)&endNum ^ (dsize_t)&startNum);
         pden = (F32*) ((dsize_t)pden ^ (dsize_t)&endDen ^ (dsize_t)&startDen);
         pplane = (S32*) ((dsize_t)pplane ^ (dsize_t)&tmpPlane ^ (dsize_t)&curPlane);
         pfound = (bool*) ((dsize_t)pfound ^ (dsize_t)&tmpFound ^ (dsize_t)&found);
      }
      bool noCollision = num*endDen*sgn<endNum*den*sgn && num*startDen*sgn<startNum*den*sgn;
      if (num * *pden * sgn < *pnum * den * sgn && !noCollision)
      {
         *pnum = num;
         *pden = den;
         *pplane = i;
         *pfound = true;
      }
      else if (noCollision)
         return false;
   }

   return found;
}
예제 #30
0
bool SceneCullingState::createCullingVolume( const Point3F* vertices, U32 numVertices, SceneCullingVolume::Type type, SceneCullingVolume& outVolume )
{
   const Point3F& viewPos = getCameraState().getViewPosition();
   const Point3F& viewDir = getCameraState().getViewDirection();
   const bool isOrtho = getCullingFrustum().isOrtho();

   //TODO: check if we need to handle penetration of the near plane for occluders specially

   // Allocate space for the clipping planes we generate.  Assume the worst case
   // of every edge generating a plane and, for includers, all edges meeting at
   // steep angles so we need to insert extra planes (the latter is not possible,
   // of course, but it makes things less complicated here).  For occluders, add
   // an extra plane for the near cap.

   const U32 maxPlanes = ( type == SceneCullingVolume::Occluder ? numVertices + 1 : numVertices * 2 );
   PlaneF* planes = allocateData< PlaneF >( maxPlanes );

   // Keep track of the world-space bounds of the polygon.  We use this later
   // to derive some metrics.

   Box3F wsPolyBounds;

   wsPolyBounds.minExtents = Point3F( TypeTraits< F32 >::MAX, TypeTraits< F32 >::MAX, TypeTraits< F32 >::MAX );
   wsPolyBounds.maxExtents = Point3F( TypeTraits< F32 >::MIN, TypeTraits< F32 >::MIN, TypeTraits< F32 >::MIN );

   // For occluders, also keep track of the nearest, and two farthest silhouette points.  We use
   // this later to construct a near capping plane.
   F32 minVertexDistanceSquared = TypeTraits< F32 >::MAX;
   U32 leastDistantVert = 0;

   F32 maxVertexDistancesSquared[ 2 ] = { TypeTraits< F32 >::MIN, TypeTraits< F32 >::MIN };
   U32 mostDistantVertices[ 2 ] = { 0, 0 };

   // Generate the extrusion volume.  For orthographic projections, extrude
   // parallel to the view direction whereas for parallel projections, extrude
   // from the viewpoint.

   U32 numPlanes = 0;
   U32 lastVertex = numVertices - 1;
   bool invert = false;

   for( U32 i = 0; i < numVertices; lastVertex = i, ++ i )
   {
      AssertFatal( numPlanes < maxPlanes, "SceneCullingState::createCullingVolume - Did not allocate enough planes!" );

      const Point3F& v1 = vertices[ i ];
      const Point3F& v2 = vertices[ lastVertex ];

      // Keep track of bounds.

      wsPolyBounds.minExtents.setMin( v1 );
      wsPolyBounds.maxExtents.setMax( v1 );

      // Skip the edge if it's length is really short.

      const Point3F edgeVector = v2 - v1;
      const F32 edgeVectorLenSquared = edgeVector.lenSquared();
      if( edgeVectorLenSquared < 0.025f )
         continue;

      //TODO: might need to do additional checks here for non-planar polygons used by occluders
      //TODO: test for colinearity of edge vector with view vector (occluders only)

      // Create a plane for the edge.

      if( isOrtho )
      {
         // Compute a plane through the two edge vertices and one
         // of the vertices extended along the view direction.

         if( !invert )
            planes[ numPlanes ] = PlaneF( v1, v1 + viewDir, v2 );
         else
            planes[ numPlanes ] = PlaneF( v2, v1 + viewDir, v1 );
      }
      else
      {
         // Compute a plane going through the viewpoint and the two
         // edge vertices.

         if( !invert )
            planes[ numPlanes ] = PlaneF( v1, viewPos, v2 );
         else
            planes[ numPlanes ] = PlaneF( v2, viewPos, v1 );
      }

      numPlanes ++;

      // If this is the first plane that we have created, find out whether
      // the vertex ordering is giving us the plane orientations that we want
      // (facing inside).  If not, invert vertex order from now on.

      if( numPlanes == 1 )
      {
         Point3F center( 0, 0, 0 );
         for( U32 n = 0; n < numVertices; ++ n )
            center += vertices[n];
         center /= numVertices;

         if( planes[numPlanes - 1].whichSide( center ) == PlaneF::Back )
         {
            invert = true;
            planes[ numPlanes - 1 ].invert();
         }
      }

      // For occluders, keep tabs of the nearest, and two farthest vertices.

      if( type == SceneCullingVolume::Occluder )
      {
         const F32 distSquared = ( v1 - viewPos ).lenSquared();
         if( distSquared < minVertexDistanceSquared )
         {
            minVertexDistanceSquared = distSquared;
            leastDistantVert = i;
         }
         if( distSquared > maxVertexDistancesSquared[ 0 ] )
         {
            // Move 0 to 1.
            maxVertexDistancesSquared[ 1 ] = maxVertexDistancesSquared[ 0 ];
            mostDistantVertices[ 1 ] = mostDistantVertices[ 0 ];

            // Replace 0.
            maxVertexDistancesSquared[ 0 ] = distSquared;
            mostDistantVertices[ 0 ] = i;
         }
         else if( distSquared > maxVertexDistancesSquared[ 1 ] )
         {
            // Replace 1.
            maxVertexDistancesSquared[ 1 ] = distSquared;
            mostDistantVertices[ 1 ] = i;
         }
      }
   }

   // If the extrusion produced no useful result, abort.

   if( numPlanes < 3 )
      return false;

   // For includers, test the angle of the edges at the current vertex.
   // If too steep, add an extra plane to improve culling efficiency.

   if( false )//type == SceneCullingVolume::Includer )
   {
      const U32 numOriginalPlanes = numPlanes;
      U32 lastPlaneIndex = numPlanes - 1;

      for( U32 i = 0; i < numOriginalPlanes; lastPlaneIndex = i, ++ i )
      {
         const PlaneF& currentPlane = planes[ i ];
         const PlaneF& lastPlane = planes[ lastPlaneIndex ];

         // Compute the cosine of the angle between the two plane normals.

         const F32 cosAngle = mFabs( mDot( currentPlane, lastPlane ) );

         // The planes meet at increasingly steep angles the more they point
         // in opposite directions, i.e the closer the angle of their normals
         // is to 180 degrees.  Skip any two planes that don't get near that.

         if( cosAngle > 0.1f )
            continue;

         //TODO

         const Point3F addNormals = currentPlane + lastPlane;
         const Point3F crossNormals = mCross( currentPlane, lastPlane );

         Point3F newNormal = currentPlane + lastPlane;//addNormals - mDot( addNormals, crossNormals ) * crossNormals;

         //

         planes[ numPlanes ] = PlaneF( currentPlane.getPosition(), newNormal );
         numPlanes ++;
      }
   }

   // Compute the metrics of the culling volume in relation to the view frustum.
   //
   // For this, we are short-circuiting things slightly.  The correct way (other than doing
   // full screen projections) would be to transform all the polygon points into camera
   // space, lay an AABB around those points, and then find the X and Z extents on the near plane.
   //
   // However, while not as accurate, a faster way is to just project the axial vectors
   // of the bounding box onto both the camera right and up vector.  This gives us a rough
   // estimate of the camera-space size of the polygon we're looking at.
   
   const MatrixF& cameraTransform = getCameraState().getViewWorldMatrix();
   const Point3F cameraRight = cameraTransform.getRightVector();
   const Point3F cameraUp = cameraTransform.getUpVector();

   const Point3F wsPolyBoundsExtents = wsPolyBounds.getExtents();
   
   F32 widthEstimate =
      getMax( mFabs( wsPolyBoundsExtents.x * cameraRight.x ),
         getMax( mFabs( wsPolyBoundsExtents.y * cameraRight.y ),
                 mFabs( wsPolyBoundsExtents.z * cameraRight.z ) ) );

   F32 heightEstimate =
      getMax( mFabs( wsPolyBoundsExtents.x * cameraUp.x ),
         getMax( mFabs( wsPolyBoundsExtents.y * cameraUp.y ),
                 mFabs( wsPolyBoundsExtents.z * cameraUp.z ) ) );

   // If the current camera is a perspective one, divide the two estimates
   // by the distance of the nearest bounding box vertex to the camera
   // to account for perspective distortion.

   if( !isOrtho )
   {
      const Point3F nearestVertex = wsPolyBounds.computeVertex(
         Box3F::getPointIndexFromOctant( - viewDir )
      );

      const F32 distance = ( nearestVertex - viewPos ).len();

      widthEstimate /= distance;
      heightEstimate /= distance;
   }

   // If we are creating an occluder, check to see if the estimates fit
   // our minimum requirements.

   if( type == SceneCullingVolume::Occluder )
   {
      const F32 widthEstimatePercentage = widthEstimate / getCullingFrustum().getWidth();
      const F32 heightEstimatePercentage = heightEstimate / getCullingFrustum().getHeight();

      if( widthEstimatePercentage < smOccluderMinWidthPercentage ||
          heightEstimatePercentage < smOccluderMinHeightPercentage )
         return false; // Reject.
   }

   // Use the area estimate as the volume's sort point.

   const F32 sortPoint = widthEstimate * heightEstimate;

   // Finally, if it's an occluder, compute a near cap.  The near cap prevents objects
   // in front of the occluder from testing positive.  The same could be achieved by
   // manually comparing distances before testing objects but since that would amount
   // to the same checks the plane/AABB tests do, it's easier to just add another plane.
   // Additionally, it gives the benefit of being able to create more precise culling
   // results by angling the plane.

   //NOTE: Could consider adding a near cap for includers too when generating a volume
   //  for the outdoor zone as that may prevent quite a bit of space from being included.
   //  However, given that this space will most likely just be filled with interior
   //  stuff anyway, it's probably not worth it.

   if( type == SceneCullingVolume::Occluder )
   {
      const U32 nearCapIndex = numPlanes;
      planes[ nearCapIndex ] = PlaneF(
         vertices[ mostDistantVertices[ 0 ] ],
         vertices[ mostDistantVertices[ 1 ] ],
         vertices[ leastDistantVert ] );

      // Invert the plane, if necessary.
      if( planes[ nearCapIndex ].whichSide( viewPos ) == PlaneF::Front )
         planes[ nearCapIndex ].invert();

      numPlanes ++;
   }

   // Create the volume from the planes.

   outVolume = SceneCullingVolume(
      type,
      PlaneSetF( planes, numPlanes )
   );
   outVolume.setSortPoint( sortPoint );

   // Done.

   return true;
}