Пример #1
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 );
}
void SFXXAudioVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume )
{
   // If the cone is set to 360 then the
   // cone is null and doesn't need to be
   // set on the voice.
   if ( mIsEqual( innerAngle, 360 ) )
   {
      SAFE_DELETE( mEmitter.pCone );
      return;
   }

   if ( !mEmitter.pCone )
   {
      mEmitter.pCone = new X3DAUDIO_CONE;

      // The inner volume is always 1... the overall
      // volume is what scales it.
      mEmitter.pCone->InnerVolume = 1.0f; 

      // We don't use these yet.
      mEmitter.pCone->InnerLPF = 0.0f; 
      mEmitter.pCone->OuterLPF = 0.0f; 
      mEmitter.pCone->InnerReverb = 0.0f; 
      mEmitter.pCone->OuterReverb = 0.0f; 
   }

   mEmitter.pCone->InnerAngle = mDegToRad( innerAngle );
   mEmitter.pCone->OuterAngle = mDegToRad( outerAngle );
   mEmitter.pCone->OuterVolume = outerVolume;
}
Пример #3
0
void LightAnimData::animate( LightInfo *lightInfo, LightAnimState *state )
{   
   PROFILE_SCOPE( LightAnimData_animate );

   // Calculate the input time for animation.
   F32 time =  state->animationPhase + 
               ( (F32)Sim::getCurrentTime() * 0.001f ) / 
               state->animationPeriod;

   MatrixF transform( state->transform );

   EulerF euler( Point3F::Zero );
   if ( mRot.animate( time, euler ) )
   {
      euler.x = mDegToRad( euler.x );
      euler.y = mDegToRad( euler.y );
      euler.z = mDegToRad( euler.z );
      MatrixF rot( euler );
      transform.mul( rot );
   }

   Point3F offset( Point3F::Zero );
   if ( mOffset.animate( time, offset ) )
      transform.displace( offset );

   lightInfo->setTransform( transform );

   ColorF color = state->color;
   mColor.animate( time, color );
   lightInfo->setColor( color );

   F32 brightness = state->brightness;
   mBrightness.animate( time, &brightness );
   lightInfo->setBrightness( brightness );
}
Пример #4
0
// GuiMaterialPreview
GuiMaterialPreview::GuiMaterialPreview()
:  mMouseState(None),
   mModel(NULL),
   runThread(0),
   lastRenderTime(0),
   mLastMousePoint(0, 0),
   mFakeSun(NULL),
   mMaxOrbitDist(5.0f),
   mMinOrbitDist(0.0f),
   mOrbitDist(5.0f)
{
   mActive = true;
   mCameraMatrix.identity();
   mCameraRot.set( mDegToRad(30.0f), 0, mDegToRad(-30.0f) );
   mCameraPos.set(0.0f, 1.75f, 1.25f);
   mCameraMatrix.setColumn(3, mCameraPos);
   mOrbitPos.set(0.0f, 0.0f, 0.0f);
   mTransStep = 0.01f;
   mTranMult = 4.0;
   mLightTransStep = 0.01f;
   mLightTranMult = 4.0;
   mOrbitRelPos = Point3F(0,0,0);

   // By default don't do dynamic reflection
   // updates for this viewport.
   mReflectPriority = 0.0f;
}
Пример #5
0
void afxZodiacData::convertGradientRangeFromDegrees(Point2F& gradrange, const Point2F& gradrange_deg)
{
  F32 x = mCos(mDegToRad(gradrange_deg.x));
  F32 y = mCos(mDegToRad(gradrange_deg.y));
  if (y > x)
    gradrange.set(x, y);
  else
    gradrange.set(y, x);
}
Пример #6
0
// This function is meant to be used with a button to put everything back to default settings.
void GuiMaterialPreview::resetViewport()
{
   // Reset the camera's orientation.
   mCameraRot.set( mDegToRad(30.0f), 0, mDegToRad(-30.0f) );
   mCameraPos.set(0.0f, 1.75f, 1.25f);
   mOrbitDist = 5.0f;
   mOrbitPos = mModel->getShape()->center;

   // Reset the viewport's lighting.
   GuiMaterialPreview::mFakeSun->setColor( ColorF( 1.0f, 1.0f, 1.0f ) );
   GuiMaterialPreview::mFakeSun->setAmbient( ColorF( 0.5f, 0.5f, 0.5f ) );
   GuiMaterialPreview::mFakeSun->setDirection( VectorF( 0.0f, 0.707f, -0.707f ) );
}
Пример #7
0
void PaintMaterialAction::process(Selection * sel, const Gui3DMouseEvent &, bool selChanged, Type)
{
   S32 mat = mTerrainEditor->getPaintMaterialIndex();
   if ( !selChanged || mat < 0 )
      return;

   const bool slopeLimit = mTerrainEditor->mSlopeMinAngle > 0.0f || mTerrainEditor->mSlopeMaxAngle < 90.0f;
   const F32 minSlope = mSin( mDegToRad( 90.0f - mTerrainEditor->mSlopeMinAngle ) );
   const F32 maxSlope = mSin( mDegToRad( 90.0f - mTerrainEditor->mSlopeMaxAngle ) );

   const TerrainBlock *terrain = mTerrainEditor->getActiveTerrain();
   const F32 squareSize = terrain->getSquareSize();

   Point2F p;
   Point3F norm;


   for( U32 i = 0; i < sel->size(); i++ )
   {
      GridInfo &inf = (*sel)[i];

      if ( slopeLimit )
      {
         p.x = inf.mGridPoint.gridPos.x * squareSize;
         p.y = inf.mGridPoint.gridPos.y * squareSize;
         if ( !terrain->getNormal( p, &norm, true ) )
            continue;

         if (  norm.z > minSlope ||
               norm.z < maxSlope )
            continue;  
      }

      // If grid is already set to our material, or it is an
      // empty grid spot, then skip painting.
      if ( inf.mMaterial == mat || inf.mMaterial == U8_MAX )
         continue;

      if ( mRandF() > mTerrainEditor->getBrushPressure() )
         continue;

      inf.mMaterialChanged = true;
      mTerrainEditor->getUndoSel()->add(inf);

      // Painting is really simple now... set the one mat index.
      inf.mMaterial = mat;
      mTerrainEditor->setGridInfo(inf, true);
   }

   mTerrainEditor->scheduleMaterialUpdate();
}
Пример #8
0
bool AITurretShape::onNewDataBlock(GameBaseData* dptr, bool reload)
{
   mDataBlock = dynamic_cast<AITurretShapeData*>(dptr);
   if (!mDataBlock || !Parent::onNewDataBlock(dptr, reload))
      return false;

   mScanHeading = mDegToRad(mDataBlock->maxScanHeading);
   if (mIsZero(mScanHeading))
      mScanHeading = M_PI_F;
   mScanPitch = mDegToRad(mDataBlock->maxScanPitch);
   if (mIsZero(mScanPitch))
      mScanPitch = M_PI_F;

   mScanDistance = mDataBlock->maxScanDistance;
   mScanDistanceSquared = mScanDistance * mScanDistance;

   mWeaponRangeSquared = mDataBlock->maxWeaponRange * mDataBlock->maxWeaponRange;
   mWeaponLeadVelocitySquared = (mDataBlock->weaponLeadVelocity > 0) ? (mDataBlock->weaponLeadVelocity * mDataBlock->weaponLeadVelocity) : 0;

   // The scan box is built such that the scanning origin is at (0,0,0) and the scanning distance
   // is out along the y axis.  When this is transformed to the turret's location is provides a
   // scanning volume in front of the turret.
   F32 scanX = mScanDistance*mSin(mScanHeading);
   F32 scanY = mScanDistance;
   F32 scanZ = mScanDistance*mSin(mScanPitch);
   mScanBox.set(-scanX, 0, -scanZ, scanX, scanY, scanZ);

   mScanTickFrequency = mDataBlock->scanTickFrequency;
   if (mScanTickFrequency < 1)
      mScanTickFrequency = 1;

   mScanTickFrequencyVariance = mDataBlock->scanTickFrequencyVariance;
   if (mScanTickFrequencyVariance < 0)
      mScanTickFrequencyVariance = 0;

   mTicksToNextScan = mScanTickFrequency;

   // For states
   mStateAnimThread = 0;
   if (mDataBlock->isAnimated)
   {
      mStateAnimThread = mShapeInstance->addThread();
      mShapeInstance->setTimeScale(mStateAnimThread,0);
   }

   scriptOnNewDataBlock();
   return true;
}
Пример #9
0
 virtual void interpolate(F32 t, afxXM_Params& params)
 {
   F32 theta = mDegToRad(lerp(t, a, b));
   AngAxisF rot_aa(axis, theta);
   MatrixF rot_xfm; rot_aa.setMatrix(&rot_xfm);
   params.ori.mul(rot_xfm);  
 }
Пример #10
0
void GFXDrawUtil::drawArrow( const GFXStateBlockDesc &desc, const Point3F &start, const Point3F &end, const ColorI &color )
{   
   GFXTransformSaver saver;

   // Direction and length of the arrow.
   VectorF dir = end - start;
   F32 len = dir.len();
   dir.normalize();   
   len *= 0.2f;      

   // Base of the cone will be a distance back from the end of the arrow
   // proportional to the total distance of the arrow... 0.3f looks about right.
   Point3F coneBase = end - dir * len * 0.3f;

   // Calculate the radius of the cone given that we want the cone to have
   // an angle of 25 degrees (just because it looks good).
   F32 coneLen = ( end - coneBase ).len();
   F32 coneDiameter = mTan( mDegToRad(25.0f) ) * coneLen;

   // Draw the cone on at the arrow's tip.
   drawCone( desc, coneBase, end, coneDiameter / 2.0f, color );

   // Get the difference in length from
   // the start of the cone to the end
   // of the cylinder so we can put the
   // end of the cylinder right against where
   // the cone starts.
   Point3F coneDiff = end - coneBase;

   // Draw the cylinder.
   F32 stickRadius = len * 0.025f;   
   drawCylinder( desc, start, end - coneDiff, stickRadius, color );
}
Пример #11
0
TurretShape::TurretShape()
{
   mTypeMask |= VehicleObjectType | DynamicShapeObjectType;
   mDataBlock = 0;

   allowManualRotation = true;
   allowManualFire = true;

   mTurretDelta.rot = Point3F(0.0f, 0.0f, 0.0f);
   mTurretDelta.rotVec = VectorF(0.0f, 0.0f, 0.0f);
   mTurretDelta.dt = 1;

   mRot = mTurretDelta.rot;

   mPitchAllowed = true;
   mHeadingAllowed = true;

   mPitchRate = -1;
   mHeadingRate = -1;

   mPitchUp = 0;
   mPitchDown = 0;
   mHeadingMax = mDegToRad(180.0f);

   mRespawn = false;

   mPitchThread = 0;
   mHeadingThread = 0;

   mSubclassTurretShapeHandlesScene = false;

   // For the Item class
   mSubclassItemHandlesScene = true;
}
Пример #12
0
void ScatterSky::_getFogColor( ColorF *outColor )
{
   PROFILE_SCOPE( ScatterSky_GetFogColor );

   VectorF scatterPos( 0, 0, 0 );

   F32 sunBrightness = mSkyBrightness;
   mSkyBrightness *= 0.25f;

   F32 yaw = 0, pitch = 0, originalYaw = 0;
   VectorF fwd( 0, 1.0f, 0 );
   MathUtils::getAnglesFromVector( fwd, yaw, pitch );
   originalYaw = yaw;
   pitch = mDegToRad( 10.0f );

   ColorF tmpColor( 0, 0, 0 );

   U32 i = 0;
   for ( i = 0; i < 10; i++ )
   {
      MathUtils::getVectorFromAngles( scatterPos, yaw, pitch );

      scatterPos.x *= smEarthRadius + smAtmosphereRadius;
      scatterPos.y *= smEarthRadius + smAtmosphereRadius;
      scatterPos.z *= smEarthRadius + smAtmosphereRadius;
      scatterPos.y -= smEarthRadius;

      _getColor( scatterPos, &tmpColor );
      (*outColor) += tmpColor;

      if ( i <= 5 )
         yaw += mDegToRad( 5.0f );
      else
      {
         originalYaw += mDegToRad( -5.0f );
         yaw = originalYaw;
      }

      yaw = mFmod( yaw, M_2PI_F );
   }

   if ( i > 0 )
      (*outColor) /= i;

   mSkyBrightness = sunBrightness;
}
Пример #13
0
void TurretShape::_applyLimits(Point3F& rot)
{
   rot.x = mClampF(rot.x, mPitchUp, mPitchDown);
   if (mHeadingMax < mDegToRad(180.0f))
   {
      rot.z = mClampF(rot.z, -mHeadingMax, mHeadingMax);
   }
}
Пример #14
0
void ScatterSky::_conformLights()
{
   _initCurves();

   F32 val = mCurves[0].getVal( mTimeOfDay );
   mNightInterpolant = 1.0f - val;

   VectorF lightDirection;
   F32 brightness;

   // Build the light direction from the azimuth and elevation.
   F32 yaw = mDegToRad(mClampF(mSunAzimuth,0,359));
   F32 pitch = mDegToRad(mClampF(mSunElevation,-360,+360));
   MathUtils::getVectorFromAngles(lightDirection, yaw, pitch);
   lightDirection.normalize();
   mSunDir = -lightDirection;

   yaw = mDegToRad(mClampF(mMoonAzimuth,0,359));
   pitch = mDegToRad(mClampF(mMoonElevation,-360,+360));
   MathUtils::getVectorFromAngles( mMoonLightDir, yaw, pitch );
   mMoonLightDir.normalize();
   mMoonLightDir = -mMoonLightDir;

   brightness = mCurves[2].getVal( mTimeOfDay );

   if ( mNightInterpolant >= 1.0f )
      lightDirection = -mMoonLightDir;

   mLight->setDirection( -lightDirection );
   mLight->setBrightness( brightness * mBrightness );
   mLightDir = lightDirection;

   // Have to do interpolation
   // after the light direction is set
   // otherwise the sun color will be invalid.
   _interpolateColors();

   mLight->setAmbient( mAmbientColor );
   mLight->setColor( mSunColor );
   mLight->setCastShadows( mCastShadows );

   FogData fog = getSceneManager()->getFogData();
   fog.color = mFogColor;
   getSceneManager()->setFogData( fog );
}
Пример #15
0
void EditTSCtrl::calcOrthoCamOffset(F32 mousex, F32 mousey, U8 modifier)
{
   F32 camScale = 0.01f;

   switch(mDisplayType)
   {
      case DisplayTypeTop:
         mOrthoCamTrans.x -= mousex * mOrthoFOV * camScale;
         mOrthoCamTrans.y += mousey * mOrthoFOV * camScale;
         break;

      case DisplayTypeBottom:
         mOrthoCamTrans.x -= mousex * mOrthoFOV * camScale;
         mOrthoCamTrans.y -= mousey * mOrthoFOV * camScale;
         break;

      case DisplayTypeFront:
         mOrthoCamTrans.x += mousex * mOrthoFOV * camScale;
         mOrthoCamTrans.z += mousey * mOrthoFOV * camScale;
         break;

      case DisplayTypeBack:
         mOrthoCamTrans.x -= mousex * mOrthoFOV * camScale;
         mOrthoCamTrans.z += mousey * mOrthoFOV * camScale;
         break;

      case DisplayTypeLeft:
         mOrthoCamTrans.y += mousex * mOrthoFOV * camScale;
         mOrthoCamTrans.z += mousey * mOrthoFOV * camScale;
         break;

      case DisplayTypeRight:
         mOrthoCamTrans.y -= mousex * mOrthoFOV * camScale;
         mOrthoCamTrans.z += mousey * mOrthoFOV * camScale;
         break;

      case DisplayTypeIsometric:
         if(modifier & SI_PRIMARY_CTRL)
         {
            // NOTE: Maybe move the center of rotation code to right mouse down to avoid compound errors?
            F32 rot = mDegToRad(mousex);

            Point3F campos = (mRawCamPos + mOrthoCamTrans) - mIsoCamRotCenter;
            MatrixF mat(EulerF(0, 0, rot));
            mat.mulP(campos);
            mOrthoCamTrans = (campos + mIsoCamRotCenter) - mRawCamPos;
            mIsoCamRot.z += rot;

         }
         else
         {
            mOrthoCamTrans.x -= mousex * mOrthoFOV * camScale * mCos(mIsoCamRot.z) - mousey * mOrthoFOV * camScale * mSin(mIsoCamRot.z);
            mOrthoCamTrans.y += mousex * mOrthoFOV * camScale * mSin(mIsoCamRot.z) + mousey * mOrthoFOV * camScale * mCos(mIsoCamRot.z);
         }
         break;
   }
}
Пример #16
0
   bool default_scan( const String &data, AngAxisF & result )
   {
      if(StringUnit::getUnitCount(data," ") < 4)
         return false;

      dSscanf(data.c_str(),"%g %g %g %g", &result.axis.x,&result.axis.y,&result.axis.z,&result.angle);
      result.angle = mDegToRad(result.angle);
      return true;
   }
Пример #17
0
void Sun::_conformLights()
{
   // Build the light direction from the azimuth and elevation.
   F32 yaw = mDegToRad(mClampF(mSunAzimuth,0,359));
   F32 pitch = mDegToRad(mClampF(mSunElevation,-360,+360));
   VectorF lightDirection;
   MathUtils::getVectorFromAngles(lightDirection, yaw, pitch);
   lightDirection.normalize();
   mLight->setDirection( -lightDirection );
   mLight->setBrightness( mBrightness );

   // Now make sure the colors are within range.
   mLightColor.clamp();
   mLight->setColor( mLightColor );
   mLightAmbient.clamp();
   mLight->setAmbient( mLightAmbient );

   // Optimization... disable shadows if the ambient and 
   // directional color are the same.
   bool castShadows = mLightColor != mLightAmbient && mCastShadows; 
   mLight->setCastShadows( castShadows );
}
Пример #18
0
bool TurretShape::_outsideLimits(Point3F& rot)
{
   if (rot.x < mPitchUp || rot.x > mPitchDown)
      return true;

   if (mHeadingMax < mDegToRad(180.0f))
   {
      if (rot.z < -mHeadingMax || rot.z > mHeadingMax)
         return true;
   }

   return false;
}
Пример #19
0
EditTSCtrl::EditTSCtrl()
{
   mGizmoProfile = NULL;
   mGizmo = NULL;

   mRenderMissionArea = true;
   mMissionAreaFillColor.set(255,0,0,20);
   mMissionAreaFrameColor.set(255,0,0,128);
   mMissionAreaHeightAdjust = 5.0f;

   mConsoleFrameColor.set(255,0,0,255);
   mConsoleFillColor.set(255,0,0,120);
   mConsoleSphereLevel = 1;
   mConsoleCircleSegments = 32;
   mConsoleLineWidth = 1;
   mRightMousePassThru = true;
   mMiddleMousePassThru = true;

   mConsoleRendering = false;

   mDisplayType = DisplayTypePerspective;
   mOrthoFOV = 50.0f;
   mOrthoCamTrans.set(0.0f, 0.0f, 0.0f);

   mIsoCamAngle = mDegToRad(45.0f);
   mIsoCamRot = EulerF(0, 0, 0);

   mRenderGridPlane = true;
   mGridPlaneOriginColor = ColorI(255, 255, 255, 100);
   mGridPlaneColor = ColorI(102, 102, 102, 100);
   mGridPlaneMinorTickColor = ColorI(51, 51, 51, 100);
   mGridPlaneMinorTicks = 9;
   mGridPlaneSize = 1.0f;
   mGridPlaneSizePixelBias = 10.0f;

   mLastMousePos.set(0, 0);

   mAllowBorderMove = false;
   mMouseMoveBorder = 20;
   mMouseMoveSpeed = 0.1f;
   mLastBorderMoveTime = 0;
   mLeftMouseDown = false;
   mRightMouseDown = false;
   mMiddleMouseDown = false;
   mMiddleMouseTriggered = false;
   mMouseLeft = false;

   mBlendSB = NULL;

}
void AdvancedLightBinManager::setupSGData( SceneData &data, const SceneRenderState* state, LightInfo *light )
{
   PROFILE_SCOPE( AdvancedLightBinManager_setupSGData );

   data.lights[0] = light;
   data.ambientLightColor = state->getAmbientLightColor();
   data.objTrans = &MatrixF::Identity;

   if ( light )
   {
      if ( light->getType() == LightInfo::Point )
      {
         // The point light volume gets some flat spots along
         // the perimiter mostly visible in the constant and 
         // quadradic falloff modes.
         //
         // To account for them slightly increase the scale 
         // instead of greatly increasing the polycount.

         mLightMat = light->getTransform();
         mLightMat.scale( light->getRange() * 1.01f );
         data.objTrans = &mLightMat;
      }
      else if ( light->getType() == LightInfo::Spot )
      {
         mLightMat = light->getTransform();

         // Rotate it to face down the -y axis.
         MatrixF scaleRotateTranslate( EulerF( M_PI_F / -2.0f, 0.0f, 0.0f ) );

         // Calculate the radius based on the range and angle.
         F32 range = light->getRange().x;
         F32 radius = range * mSin( mDegToRad( light->getOuterConeAngle() ) * 0.5f );

         // NOTE: This fudge makes the cone a little bigger
         // to remove the facet egde of the cone geometry.
         radius *= 1.1f;

         // Use the scale to distort the cone to
         // match our radius and range.
         scaleRotateTranslate.scale( Point3F( radius, radius, range ) );

         // Apply the transform and set the position.
         mLightMat *= scaleRotateTranslate;
         mLightMat.setPosition( light->getPosition() );

         data.objTrans = &mLightMat;
      }
   }
}
Пример #21
0
void TurretShape::updateAnimation(F32 dt)
{
   if (mRecoilThread)
      mShapeInstance->advanceTime(dt,mRecoilThread);
   if (mImageStateThread)
      mShapeInstance->advanceTime(dt,mImageStateThread);

   // Update any pitch and heading threads
   if (mPitchThread)
   {
      F32 d = mPitchDown - mPitchUp;
      if (!mIsZero(d))
      {
         F32 pos = (mRot.x - mPitchUp) / d;
         mShapeInstance->setPos(mPitchThread, mClampF(pos, 0.0f, 1.0f));
      }
   }
   if (mHeadingThread)
   {
      F32 pos = 0.0f;
      if (mHeadingMax < mDegToRad(180.0f))
      {
         F32 d = mHeadingMax * 2.0f;
         if (!mIsZero(d))
         {
            pos = (mRot.z + mHeadingMax) / d;
         }
      }
      else
      {
         pos = mRot.z / M_2PI;
         if (pos < 0.0f)
         {
            // We don't want negative rotations to simply mirror the
            // positive rotations but to animate into them as if -0.0
            // is equivalent to 1.0.
            pos = mFmod(pos, 1.0f) + 1.0f;
         }
         if (pos > 1.0f)
         {
            pos = mFmod(pos, 1.0f);
         }
      }
      mShapeInstance->setPos(mHeadingThread, mClampF(pos, 0.0f, 1.0f));
   }
}
Пример #22
0
bool OculusVRDevice::process()
{
   if(!mEnabled)
      return false;

   if(!getActive())
      return false;

   //Build the maximum axis angle to be passed into the sensor process()
   F32 maxAxisRadius = mSin(mDegToRad(smMaximumAxisAngle));

   // Process each sensor
   for(U32 i=0; i<mSensorDevices.size(); ++i)
   {
      mSensorDevices[i]->process(mDeviceType, smGenerateAngleAxisRotationEvents, smGenerateEulerRotationEvents, smGenerateRotationAsAxisEvents, maxAxisRadius);
   }

   return true;
}
void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const LightInfo *lightInfo, const SceneRenderState* renderState, const MatrixF &worldViewOnly )
{
   MaterialParameters *matParams = matInstance->getMaterialParameters();

   // Set color in the right format, set alpha to the luminance value for the color.
   ColorF col = lightInfo->getColor();

   // TODO: The specularity control of the light
   // is being scaled by the overall lumiance.
   //
   // Not sure if this may be the source of our
   // bad specularity results maybe?
   //

   const Point3F colorToLumiance( 0.3576f, 0.7152f, 0.1192f );
   F32 lumiance = mDot(*((const Point3F *)&lightInfo->getColor()), colorToLumiance );
   col.alpha *= lumiance;

   matParams->setSafe( lightColor, col );
   matParams->setSafe( lightBrightness, lightInfo->getBrightness() );

   switch( lightInfo->getType() )
   {
   case LightInfo::Vector:
      {
         VectorF lightDir = lightInfo->getDirection();
         worldViewOnly.mulV(lightDir);
         lightDir.normalize();
         matParams->setSafe( lightDirection, lightDir );

         // Set small number for alpha since it represents existing specular in
         // the vector light. This prevents a divide by zero.
         ColorF ambientColor = renderState->getAmbientLightColor();
         ambientColor.alpha = 0.00001f;
         matParams->setSafe( lightAmbient, ambientColor );

         // If no alt color is specified, set it to the average of
         // the ambient and main color to avoid artifacts.
         //
         // TODO: Trilight disabled until we properly implement it
         // in the light info!
         //
         //ColorF lightAlt = lightInfo->getAltColor();
         ColorF lightAlt( ColorF::BLACK ); // = lightInfo->getAltColor();
         if ( lightAlt.red == 0.0f && lightAlt.green == 0.0f && lightAlt.blue == 0.0f )
            lightAlt = (lightInfo->getColor() + renderState->getAmbientLightColor()) / 2.0f;

         ColorF trilightColor = lightAlt;
         matParams->setSafe(lightTrilight, trilightColor);
      }
      break;

   case LightInfo::Spot:
      {
         const F32 outerCone = lightInfo->getOuterConeAngle();
         const F32 innerCone = getMin( lightInfo->getInnerConeAngle(), outerCone );
         const F32 outerCos = mCos( mDegToRad( outerCone / 2.0f ) );
         const F32 innerCos = mCos( mDegToRad( innerCone / 2.0f ) );
         Point4F spotParams(  outerCos, 
                              innerCos - outerCos, 
                              mCos( mDegToRad( outerCone ) ), 
                              0.0f );

         matParams->setSafe( lightSpotParams, spotParams );

         VectorF lightDir = lightInfo->getDirection();
         worldViewOnly.mulV(lightDir);
         lightDir.normalize();
         matParams->setSafe( lightDirection, lightDir );
      }
      // Fall through

   case LightInfo::Point:
   {
      const F32 radius = lightInfo->getRange().x;
      matParams->setSafe( lightRange, radius );

      Point3F lightPos;
      worldViewOnly.mulP(lightInfo->getPosition(), &lightPos);
      matParams->setSafe( lightPosition, lightPos );

      // Get the attenuation falloff ratio and normalize it.
      Point3F attenRatio = lightInfo->getExtended<ShadowMapParams>()->attenuationRatio;
      F32 total = attenRatio.x + attenRatio.y + attenRatio.z;
      if ( total > 0.0f )
         attenRatio /= total;

      Point2F attenParams( ( 1.0f / radius ) * attenRatio.y,
                           ( 1.0f / ( radius * radius ) ) * attenRatio.z );

      matParams->setSafe( lightAttenuation, attenParams );
      break;
   }

   default:
      AssertFatal( false, "Bad light type!" );
      break;
   }
}
bool LeapMotionDevice::process()
{
   if(!mEnabled)
      return false;

   if(!getActive())
      return false;

   //Con::printf("LeapMotionDevice::process()");

   //Build the maximum hand axis angle to be passed into the LeapMotionDeviceData::setData()
   F32 maxHandAxisRadius = mSin(mDegToRad(smMaximumHandAxisAngle));

   // Get a frame of data
   const Leap::Frame frame = mController->frame();

   //const Leap::HandList hands = frame.hands();
   //Con::printf("Frame: %lld  Hands: %d  Fingers: %d  Tools: %d", (long long)frame.id(), hands.count(), frame.fingers().count(), frame.tools().count());

   // Store the current data
   LeapMotionDeviceData* currentBuffer = (mPrevData == mDataBuffer[0]) ? mDataBuffer[1] : mDataBuffer[0];
   currentBuffer->setData(frame, mPrevData, smKeepHandIndexPersistent, smKeepPointableIndexPersistent, maxHandAxisRadius);
   U32 diff = mPrevData->compare(currentBuffer);
   U32 metaDiff = mPrevData->compareMeta(currentBuffer);

   // Update the previous data pointers.  We do this here in case someone calls our
   // console functions during one of the input events below.
   mPrevData = currentBuffer;

   // Send out any meta data
   if(metaDiff & LeapMotionDeviceData::METADIFF_FRAME_VALID_DATA)
   {
      // Frame valid change event
      INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_BUTTON, LM_FRAMEVALIDDATA, currentBuffer->mHasTrackingData ? SI_MAKE : SI_BREAK, currentBuffer->mHasTrackingData ? 1.0f : 0.0f);
   }

   // Send out any valid data
   if(currentBuffer->mDataSet && currentBuffer->mIsValid)
   {
      // Hands and their pointables
      if(smGenerateIndividualEvents)
      {
         for(U32 i=0; i<LeapMotionConstants::MaxHands; ++i)
         {
            if(currentBuffer->mHandValid[i])
            {
               // Send out position
               INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_POS, LM_HAND[i], SI_MOVE, currentBuffer->mHandPosPoint[i]);

               // Send out rotation
               INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_ROT, LM_HANDROT[i], SI_MOVE, currentBuffer->mHandRotQuat[i]);

               // Pointables for hand
               for(U32 j=0; j<LeapMotionConstants::MaxPointablesPerHand; ++j)
               {
                  if(currentBuffer->mPointableValid[i][j])
                  {
                     // Send out position
                     INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_POS, LM_HANDPOINTABLE[i][j], SI_MOVE, currentBuffer->mPointablePosPoint[i][j]);

                     // Send out rotation
                     INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_ROT, LM_HANDPOINTABLEROT[i][j], SI_MOVE, currentBuffer->mPointableRotQuat[i][j]);
                  }
               }
            }
         }
      }

      // Single Hand as axis rotation
      if(smGenerateSingleHandRotationAsAxisEvents && diff & LeapMotionDeviceData::DIFF_HANDROTAXIS)
      {
         if(diff & LeapMotionDeviceData::DIFF_HANDROTAXISX)
            INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_AXIS, LM_HANDAXISX, SI_MOVE, currentBuffer->mHandRotAxis[0]);
         if(diff & LeapMotionDeviceData::DIFF_HANDROTAXISY)
            INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_AXIS, LM_HANDAXISY, SI_MOVE, currentBuffer->mHandRotAxis[1]);
      }
   }

   // Send out whole frame event, but only if the special frame group is defined
   if(smGenerateWholeFrameEvents && LeapMotionFrameStore::isFrameGroupDefined())
   {
      S32 id = LEAPMOTIONFS->generateNewFrame(frame, maxHandAxisRadius);
      if(id != 0)
      {
         INPUTMGR->buildInputEvent(mDeviceType, DEFAULT_MOTION_UNIT, SI_INT, LM_FRAME, SI_VALUE, id);
      }
   }

   return true;
}
void fxShapeReplicator::CreateShapes(void)
{
   F32				HypX, HypY;
   F32				Angle;
   U32				RelocationRetry;
   Point3F			ShapePosition;
   Point3F			ShapeStart;
   Point3F			ShapeEnd;
   Point3F			ShapeScale;
   EulerF			ShapeRotation;
   QuatF			QRotation;
   bool			CollisionResult;
   RayInfo			RayEvent;
   TSShape*		pShape;


   // Don't create shapes if we are hiding replications.
   if (mFieldData.mHideReplications) return;

   // Cannot continue without shapes!
   if (dStrcmp(mFieldData.mShapeFile, "") == 0) return;

   // Check that we can position somewhere!
   if (!(	mFieldData.mAllowOnTerrain ||
      mFieldData.mAllowStatics ||
      mFieldData.mAllowOnWater))
   {
      // Problem ...
      Con::warnf(ConsoleLogEntry::General, "[%s] - Could not place object, All alloweds are off!", getName());

      // Return here.
      return;
   }

   // Check Shapes.
   AssertFatal(mCurrentShapeCount==0,"Shapes already present, this should not be possible!")

      // Check that we have a shape...
      if (!mFieldData.mShapeFile) return;

   // Set Seed.
   RandomGen.setSeed(mFieldData.mSeed);

   // Set shape vector.
   mReplicatedShapes.clear();

   // Add shapes.
   for (U32 idx = 0; idx < mFieldData.mShapeCount; idx++)
   {
      fxShapeReplicatedStatic*	fxStatic;

      // Create our static shape.
      fxStatic = new fxShapeReplicatedStatic();

      // Set the 'shapeName' field.
      fxStatic->setField("shapeName", mFieldData.mShapeFile);

      // Is this Replicator on the Server?
      if (isServerObject())
         // Yes, so stop it from Ghosting. (Hack, Hack, Hack!)
         fxStatic->touchNetFlags(Ghostable, false);
      else
         // No, so flag as ghost object. (Another damn Hack!)
         fxStatic->touchNetFlags(IsGhost, true);

      // Register the Object.
      if (!fxStatic->registerObject())
      {
         // Problem ...
         Con::warnf(ConsoleLogEntry::General, "[%s] - Could not load shape file '%s'!", getName(), mFieldData.mShapeFile);

         // Destroy Shape.
         delete fxStatic;

         // Destroy existing hapes.
         DestroyShapes();

         // Quit.
         return;
      }

      // Get Allocated Shape.
      pShape = fxStatic->getShape();

      // Reset Relocation Retry.
      RelocationRetry = mFieldData.mShapeRetries;

      // Find it a home ...
      do
      {
         // Get the Replicator Position.
         ShapePosition = getPosition();

         // Calculate a random offset
         HypX	= RandomGen.randF(mFieldData.mInnerRadiusX, mFieldData.mOuterRadiusX);
         HypY	= RandomGen.randF(mFieldData.mInnerRadiusY, mFieldData.mOuterRadiusY);
         Angle	= RandomGen.randF(0, (F32)M_2PI);

         // Calcualte the new position.
         ShapePosition.x += HypX * mCos(Angle);
         ShapePosition.y += HypY * mSin(Angle);


         // Initialise RayCast Search Start/End Positions.
         ShapeStart = ShapeEnd = ShapePosition;
         ShapeStart.z = 2000.f;
         ShapeEnd.z= -2000.f;

         // Is this the Server?
         if (isServerObject())
            // Perform Ray Cast Collision on Server Terrain.
            CollisionResult = gServerContainer.castRay(ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);
         else
            // Perform Ray Cast Collision on Client Terrain.
            CollisionResult = gClientContainer.castRay(	ShapeStart, ShapeEnd, FXREPLICATOR_COLLISION_MASK, &RayEvent);

         // Did we hit anything?
         if (CollisionResult)
         {
            // For now, let's pretend we didn't get a collision.
            CollisionResult = false;

            // Yes, so get it's type.
            U32 CollisionType = RayEvent.object->getTypeMask();

            // Check Illegal Placements.
            if (((CollisionType & TerrainObjectType) && !mFieldData.mAllowOnTerrain)	||
               ((CollisionType & StaticShapeObjectType) && !mFieldData.mAllowStatics)	||
               ((CollisionType & WaterObjectType) && !mFieldData.mAllowOnWater) ) continue;

            // If we collided with water and are not allowing on the water surface then let's find the
            // terrain underneath and pass this on as the original collision else fail.
            //
            // NOTE:- We need to do this on the server/client as appropriate.
            if ((CollisionType & WaterObjectType) && !mFieldData.mAllowWaterSurface)
            {
               // Is this the Server?
               if (isServerObject())
               {
                  // Yes, so do it on the server container.
                  if (!gServerContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
               }
               else
               {
                  // No, so do it on the client container.
                  if (!gClientContainer.castRay( ShapeStart, ShapeEnd, FXREPLICATOR_NOWATER_COLLISION_MASK, &RayEvent)) continue;
               }
            }

            // We passed with flying colours so carry on.
            CollisionResult = true;
         }

         // Invalidate if we are below Allowed Terrain Angle.
         if (RayEvent.normal.z < mSin(mDegToRad(90.0f-mFieldData.mAllowedTerrainSlope))) CollisionResult = false;

         // Wait until we get a collision.
      } while(!CollisionResult && --RelocationRetry);

      // Check for Relocation Problem.
      if (RelocationRetry > 0)
      {
         // Adjust Impact point.
         RayEvent.point.z += mFieldData.mOffsetZ;

         // Set New Position.
         ShapePosition = RayEvent.point;
      }
      else
      {
         // Warning.
         Con::warnf(ConsoleLogEntry::General, "[%s] - Could not find satisfactory position for shape '%s' on %s!", getName(), mFieldData.mShapeFile,isServerObject()?"Server":"Client");

         // Unregister Object.
         fxStatic->unregisterObject();

         // Destroy Shape.
         delete fxStatic;

         // Skip to next.
         continue;
      }

      // Get Shape Transform.
      MatrixF XForm = fxStatic->getTransform();

      // Are we aligning to Terrain?
      if (mFieldData.mAlignToTerrain)
      {
         // Yes, so set rotation to Terrain Impact Normal.
         ShapeRotation = RayEvent.normal * mFieldData.mTerrainAlignment;
      }
      else
      {
         // No, so choose a new Rotation (in Radians).
         ShapeRotation.set(	mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.x, mFieldData.mShapeRotateMax.x)),
            mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.y, mFieldData.mShapeRotateMax.y)),
            mDegToRad(RandomGen.randF(mFieldData.mShapeRotateMin.z, mFieldData.mShapeRotateMax.z)));
      }

      // Set Quaternion Roation.
      QRotation.set(ShapeRotation);

      // Set Transform Rotation.
      QRotation.setMatrix(&XForm);

      // Set Position.
      XForm.setColumn(3, ShapePosition);

      // Set Shape Position / Rotation.
      fxStatic->setTransform(XForm);

      // Choose a new Scale.
      ShapeScale.set(	RandomGen.randF(mFieldData.mShapeScaleMin.x, mFieldData.mShapeScaleMax.x),
         RandomGen.randF(mFieldData.mShapeScaleMin.y, mFieldData.mShapeScaleMax.y),
         RandomGen.randF(mFieldData.mShapeScaleMin.z, mFieldData.mShapeScaleMax.z));

      // Set Shape Scale.
      fxStatic->setScale(ShapeScale);

      // Lock it.
      fxStatic->setLocked(true);

      // Store Shape in Replicated Shapes Vector.
      //mReplicatedShapes[mCurrentShapeCount++] = fxStatic;
      mReplicatedShapes.push_back(fxStatic);

   }

   mCurrentShapeCount = mReplicatedShapes.size();

   // Take first Timestamp.
   mLastRenderTime = Platform::getVirtualMilliseconds();
}
void FontRenderBatcher::render( F32 rot, const Point2F &offset )
{
   if( mLength == 0 )
      return;

   GFX->setStateBlock(mFontSB);
   for(U32 i = 0; i < GFX->getNumSamplers(); i++)
      GFX->setTexture(i, NULL);

   MatrixF rotMatrix;

   bool doRotation = rot != 0.f;
   if(doRotation)
      rotMatrix.set( EulerF( 0.0, 0.0, mDegToRad( rot ) ) );

   // Write verts out.
   U32 currentPt = 0;
   GFXVertexBufferHandle<GFXVertexPCT> verts(GFX, mLength * 6, GFXBufferTypeVolatile);
   verts.lock();

   for( S32 i = 0; i < mSheets.size(); i++ )
   {
      // Do some early outs...
      if(!mSheets[i])
         continue;

      if(!mSheets[i]->numChars)
         continue;

      mSheets[i]->startVertex = currentPt;
      const GFXTextureObject *tex = mFont->getTextureHandle(i);

      for( S32 j = 0; j < mSheets[i]->numChars; j++ )
      {
         // Get some general info to proceed with...
         const CharMarker &m = mSheets[i]->charIndex[j];
         const PlatformFont::CharInfo &ci = mFont->getCharInfo( m.c );

         // Where are we drawing it?
         F32 drawY = offset.y + mFont->getBaseline() - ci.yOrigin * TEXT_MAG;
         F32 drawX = offset.x + m.x + ci.xOrigin;

         // Figure some values.
         const F32 texWidth = (F32)tex->getWidth();
         const F32 texHeight = (F32)tex->getHeight();
         const F32 texLeft   = (F32)(ci.xOffset)             / texWidth;
         const F32 texRight  = (F32)(ci.xOffset + ci.width)  / texWidth;
         const F32 texTop    = (F32)(ci.yOffset)             / texHeight;
         const F32 texBottom = (F32)(ci.yOffset + ci.height) / texHeight;

         const F32 fillConventionOffset = GFX->getFillConventionOffset();
         const F32 screenLeft   = drawX - fillConventionOffset;
         const F32 screenRight  = drawX - fillConventionOffset + ci.width * TEXT_MAG;
         const F32 screenTop    = drawY - fillConventionOffset;
         const F32 screenBottom = drawY - fillConventionOffset + ci.height * TEXT_MAG;

         // Build our vertices. We NEVER read back from the buffer, that's
         // incredibly slow, so for rotation do it into tmp. This code is
         // ugly as sin.
         Point3F tmp;

         tmp.set( screenLeft, screenTop, 0.f );
         if(doRotation)
            rotMatrix.mulP( tmp, &verts[currentPt].point);
         else
            verts[currentPt].point = tmp;
         verts[currentPt].color = m.color;
         verts[currentPt].texCoord.set( texLeft, texTop );
         currentPt++;

         tmp.set( screenLeft, screenBottom, 0.f );
         if(doRotation)
            rotMatrix.mulP( tmp, &verts[currentPt].point);
         else
            verts[currentPt].point = tmp;
         verts[currentPt].color = m.color;
         verts[currentPt].texCoord.set( texLeft, texBottom );
         currentPt++;

         tmp.set( screenRight, screenBottom, 0.f );
         if(doRotation)
            rotMatrix.mulP( tmp, &verts[currentPt].point);
         else
            verts[currentPt].point = tmp;
         verts[currentPt].color = m.color;
         verts[currentPt].texCoord.set( texRight, texBottom );
         currentPt++;

         tmp.set( screenRight, screenBottom, 0.f );
         if(doRotation)
            rotMatrix.mulP( tmp, &verts[currentPt].point);
         else
            verts[currentPt].point = tmp;
         verts[currentPt].color = m.color;
         verts[currentPt].texCoord.set( texRight, texBottom );
         currentPt++;

         tmp.set( screenRight, screenTop, 0.f );
         if(doRotation)
            rotMatrix.mulP( tmp, &verts[currentPt].point);
         else
            verts[currentPt].point = tmp;
         verts[currentPt].color = m.color;
         verts[currentPt].texCoord.set( texRight, texTop );
         currentPt++;

         tmp.set( screenLeft, screenTop, 0.f );
         if(doRotation)
            rotMatrix.mulP( tmp, &verts[currentPt].point);
         else
            verts[currentPt].point = tmp;
         verts[currentPt].color = m.color;
         verts[currentPt].texCoord.set( texLeft, texTop );
         currentPt++;
      }
   }

   verts->unlock();

   AssertFatal(currentPt <= mLength * 6, "FontRenderBatcher::render - too many verts for length of string!");

   GFX->setVertexBuffer(verts);
   GFX->setupGenericShaders( GFXDevice::GSAddColorTexture );

   // Now do an optimal render!
   for( S32 i = 0; i < mSheets.size(); i++ )
   {
      if(!mSheets[i])
         continue;

      if(!mSheets[i]->numChars )
         continue;
      
      GFX->setTexture( 0, mFont->getTextureHandle(i) );
      GFX->drawPrimitive(GFXTriangleList, mSheets[i]->startVertex, mSheets[i]->numChars * 2);
   }
}
Пример #27
0
bool EditTSCtrl::processCameraQuery(CameraQuery * query)
{
   if(mDisplayType == DisplayTypePerspective)
   {
      query->ortho = false;
   }
   else
   {
      query->ortho = true;
   }

   if (getCameraTransform(&query->cameraMatrix))
   {
      query->farPlane = gClientSceneGraph->getVisibleDistance() * smVisibleDistanceScale;
      query->nearPlane = gClientSceneGraph->getNearClip();
      query->fov = mDegToRad(smCamFOV);

      if(query->ortho)
      {
         MatrixF camRot(true);
         const F32 camBuffer = 1.0f;
         Point3F camPos = query->cameraMatrix.getPosition();

         F32 isocamplanedist = 0.0f;
         if(mDisplayType == DisplayTypeIsometric)
         {
            const RectI& vp = GFX->getViewport();
            isocamplanedist = 0.25 * vp.extent.y * mSin(mIsoCamAngle);
         }

         // Calculate the scene bounds
         Box3F sceneBounds;
         computeSceneBounds(sceneBounds);

         if(!sceneBounds.isValidBox())
         {
            sceneBounds.maxExtents = camPos + smMinSceneBounds;
            sceneBounds.minExtents = camPos - smMinSceneBounds;
         }
         else
         {
            query->farPlane = getMax(smMinSceneBounds.x * 2.0f, (sceneBounds.maxExtents - sceneBounds.minExtents).len() + camBuffer * 2.0f + isocamplanedist);
         }

         mRawCamPos = camPos;
         camPos += mOrthoCamTrans;

         switch(mDisplayType)
         {
            case DisplayTypeTop:
               camRot.setColumn(0, Point3F(1.0, 0.0,  0.0));
               camRot.setColumn(1, Point3F(0.0, 0.0, -1.0));
               camRot.setColumn(2, Point3F(0.0, 1.0,  0.0));
               camPos.z = getMax(camPos.z + smMinSceneBounds.z, sceneBounds.maxExtents.z + camBuffer);
               break;

            case DisplayTypeBottom:
               camRot.setColumn(0, Point3F(1.0,  0.0,  0.0));
               camRot.setColumn(1, Point3F(0.0,  0.0,  1.0));
               camRot.setColumn(2, Point3F(0.0, -1.0,  0.0));
               camPos.z = getMin(camPos.z - smMinSceneBounds.z, sceneBounds.minExtents.z - camBuffer);
               break;

            case DisplayTypeFront:
               camRot.setColumn(0, Point3F(-1.0,  0.0,  0.0));
               camRot.setColumn(1, Point3F( 0.0, -1.0,  0.0));
               camRot.setColumn(2, Point3F( 0.0,  0.0,  1.0));
               camPos.y = getMax(camPos.y + smMinSceneBounds.y, sceneBounds.maxExtents.y + camBuffer);
               break;

            case DisplayTypeBack:
               camRot.setColumn(0, Point3F(1.0,  0.0,  0.0));
               camRot.setColumn(1, Point3F(0.0,  1.0,  0.0));
               camRot.setColumn(2, Point3F(0.0,  0.0,  1.0));
               camPos.y = getMin(camPos.y - smMinSceneBounds.y, sceneBounds.minExtents.y - camBuffer);
               break;

            case DisplayTypeLeft:
               camRot.setColumn(0, Point3F( 0.0, -1.0,  0.0));
               camRot.setColumn(1, Point3F( 1.0,  0.0,  0.0));
               camRot.setColumn(2, Point3F( 0.0,  0.0,  1.0));
               camPos.x = getMin(camPos.x - smMinSceneBounds.x, sceneBounds.minExtents.x - camBuffer);
               break;

            case DisplayTypeRight:
               camRot.setColumn(0, Point3F( 0.0,  1.0,  0.0));
               camRot.setColumn(1, Point3F(-1.0,  0.0,  0.0));
               camRot.setColumn(2, Point3F( 0.0,  0.0,  1.0));
               camPos.x = getMax(camPos.x + smMinSceneBounds.x, sceneBounds.maxExtents.x + camBuffer);
               break;

            case DisplayTypeIsometric:
               camPos.z = sceneBounds.maxExtents.z + camBuffer + isocamplanedist;
               MatrixF angle(EulerF(mIsoCamAngle, 0, 0));
               MatrixF rot(mIsoCamRot);
               camRot.mul(rot, angle);
               break;
         }

         query->cameraMatrix = camRot;
         query->cameraMatrix.setPosition(camPos);
         query->fov = mOrthoFOV;
      }

      smCamMatrix = query->cameraMatrix;
      smCamMatrix.getColumn(3,&smCamPos);
      smCamOrtho = query->ortho;
      smCamNearPlane = query->nearPlane;

      return true;
   }
   return false;
}
void LightManager::_update4LightConsts(   const SceneData &sgData,
                                          GFXShaderConstHandle *lightPositionSC,
                                          GFXShaderConstHandle *lightDiffuseSC,
                                          GFXShaderConstHandle *lightAmbientSC,
                                          GFXShaderConstHandle *lightInvRadiusSqSC,
                                          GFXShaderConstHandle *lightSpotDirSC,
                                          GFXShaderConstHandle *lightSpotAngleSC,
										  GFXShaderConstHandle *lightSpotFalloffSC,
                                          GFXShaderConstBuffer *shaderConsts )
{
   PROFILE_SCOPE( LightManager_Update4LightConsts );

   // Skip over gathering lights if we don't have to!
   if (  lightPositionSC->isValid() || 
         lightDiffuseSC->isValid() ||
         lightInvRadiusSqSC->isValid() ||
         lightSpotDirSC->isValid() ||
         lightSpotAngleSC->isValid() ||
		 lightSpotFalloffSC->isValid() )
   {
      PROFILE_SCOPE( LightManager_Update4LightConsts_setLights );

      static AlignedArray<Point4F> lightPositions( 3, sizeof( Point4F ) );
      static AlignedArray<Point4F> lightSpotDirs( 3, sizeof( Point4F ) );
      static AlignedArray<Point4F> lightColors( 4, sizeof( Point4F ) );
      static Point4F lightInvRadiusSq;
      static Point4F lightSpotAngle;
	  static Point4F lightSpotFalloff;
      F32 range;
      
      // Need to clear the buffers so that we don't leak
      // lights from previous passes or have NaNs.
      dMemset( lightPositions.getBuffer(), 0, lightPositions.getBufferSize() );
      dMemset( lightSpotDirs.getBuffer(), 0, lightSpotDirs.getBufferSize() );
      dMemset( lightColors.getBuffer(), 0, lightColors.getBufferSize() );
      lightInvRadiusSq = Point4F::Zero;
      lightSpotAngle.set( -1.0f, -1.0f, -1.0f, -1.0f );
      lightSpotFalloff.set( F32_MAX, F32_MAX, F32_MAX, F32_MAX );

      // Gather the data for the first 4 lights.
      const LightInfo *light;
      for ( U32 i=0; i < 4; i++ )
      {
         light = sgData.lights[i];
         if ( !light )            
            break;
      
            // The light positions and spot directions are 
            // in SoA order to make optimal use of the GPU.
            const Point3F &lightPos = light->getPosition();
            lightPositions[0][i] = lightPos.x;
            lightPositions[1][i] = lightPos.y;
            lightPositions[2][i] = lightPos.z;

            const VectorF &lightDir = light->getDirection();
            lightSpotDirs[0][i] = lightDir.x;
            lightSpotDirs[1][i] = lightDir.y;
            lightSpotDirs[2][i] = lightDir.z;
            
            if ( light->getType() == LightInfo::Spot )
			{
               lightSpotAngle[i] = mCos( mDegToRad( light->getOuterConeAngle() / 2.0f ) ); 
			   lightSpotFalloff[i] = 1.0f / getMax( F32_MIN, mCos( mDegToRad( light->getInnerConeAngle() / 2.0f ) ) - lightSpotAngle[i] );
			}

         // Prescale the light color by the brightness to 
         // avoid doing this in the shader.
         lightColors[i] = Point4F(light->getColor()) * light->getBrightness();

         // We need 1 over range^2 here.
         range = light->getRange().x;
         lightInvRadiusSq[i] = 1.0f / ( range * range );
      }

      shaderConsts->setSafe( lightPositionSC, lightPositions );   
      shaderConsts->setSafe( lightDiffuseSC, lightColors );
      shaderConsts->setSafe( lightInvRadiusSqSC, lightInvRadiusSq );
      
      shaderConsts->setSafe( lightSpotDirSC, lightSpotDirs ); 
      shaderConsts->setSafe( lightSpotAngleSC, lightSpotAngle );
		shaderConsts->setSafe( lightSpotFalloffSC, lightSpotFalloff );

      
   }

   // Setup the ambient lighting from the first 
   // light which is the directional light if 
   // one exists at all in the scene.
   if ( lightAmbientSC->isValid() )
      shaderConsts->set( lightAmbientSC, sgData.ambientLightColor );
}
void TSLastDetail::_update()
{
   // We're gonna render... make sure we can.
   bool sceneBegun = GFX->canCurrentlyRender();
   if ( !sceneBegun )
      GFX->beginScene();

   _validateDim();

   Vector<GBitmap*> bitmaps;
   Vector<GBitmap*> normalmaps;

   // We need to create our own instance to render with.
   TSShapeInstance *shape = new TSShapeInstance( mShape, true );

   // Animate the shape once.
   shape->animate( mDl );

   // So we don't have to change it everywhere.
   const GFXFormat format = GFXFormatR8G8B8A8;  

   S32 imposterCount = ( ((2*mNumPolarSteps) + 1 ) * mNumEquatorSteps ) + ( mIncludePoles ? 2 : 0 );

   // Figure out the optimal texture size.
   Point2I texSize( smMaxTexSize, smMaxTexSize );
   while ( true )
   {
      Point2I halfSize( texSize.x / 2, texSize.y / 2 );
      U32 count = ( halfSize.x / mDim ) * ( halfSize.y / mDim );
      if ( count < imposterCount )
      {
         // Try half of the height.
         count = ( texSize.x / mDim ) * ( halfSize.y / mDim );
         if ( count >= imposterCount )
            texSize.y = halfSize.y;
         break;
      }

      texSize = halfSize;
   }

   GBitmap *imposter = NULL;
   GBitmap *normalmap = NULL;
   GBitmap destBmp( texSize.x, texSize.y, true, format );
   GBitmap destNormal( texSize.x, texSize.y, true, format );

   U32 mipLevels = destBmp.getNumMipLevels();

   ImposterCapture *imposterCap = new ImposterCapture();

   F32 equatorStepSize = M_2PI_F / (F32)mNumEquatorSteps;

   static const MatrixF topXfm( EulerF( -M_PI_F / 2.0f, 0, 0 ) );
   static const MatrixF bottomXfm( EulerF( M_PI_F / 2.0f, 0, 0 ) );

   MatrixF angMat;

   F32 polarStepSize = 0.0f;
   if ( mNumPolarSteps > 0 )
      polarStepSize = -( 0.5f * M_PI_F - mDegToRad( mPolarAngle ) ) / (F32)mNumPolarSteps;

   PROFILE_START(TSLastDetail_snapshots);

   S32 currDim = mDim;
   for ( S32 mip = 0; mip < mipLevels; mip++ )
   {
      if ( currDim < 1 )
         currDim = 1;
      
      dMemset( destBmp.getWritableBits(mip), 0, destBmp.getWidth(mip) * destBmp.getHeight(mip) * GFXFormat_getByteSize( format ) );
      dMemset( destNormal.getWritableBits(mip), 0, destNormal.getWidth(mip) * destNormal.getHeight(mip) * GFXFormat_getByteSize( format ) );

      bitmaps.clear();
      normalmaps.clear();

      F32 rotX = 0.0f;
      if ( mNumPolarSteps > 0 )
         rotX = -( mDegToRad( mPolarAngle ) - 0.5f * M_PI_F );

      // We capture the images in a particular order which must
      // match the order expected by the imposter renderer.

      imposterCap->begin( shape, mDl, currDim, mRadius, mCenter );

      for ( U32 j=0; j < (2 * mNumPolarSteps + 1); j++ )
      {
         F32 rotZ = -M_PI_F / 2.0f;

         for ( U32 k=0; k < mNumEquatorSteps; k++ )
         {            
            angMat.mul( MatrixF( EulerF( rotX, 0, 0 ) ),
                        MatrixF( EulerF( 0, 0, rotZ ) ) );

            imposterCap->capture( angMat, &imposter, &normalmap );

            bitmaps.push_back( imposter );
            normalmaps.push_back( normalmap );

            rotZ += equatorStepSize;
         }

         rotX += polarStepSize;

         if ( mIncludePoles )
         {
            imposterCap->capture( topXfm, &imposter, &normalmap );

            bitmaps.push_back(imposter);
            normalmaps.push_back( normalmap );

            imposterCap->capture( bottomXfm, &imposter, &normalmap );

            bitmaps.push_back( imposter );
            normalmaps.push_back( normalmap );
         }         
      }

      imposterCap->end();

      Point2I texSize( destBmp.getWidth(mip), destBmp.getHeight(mip) );

      // Ok... pack in bitmaps till we run out.
      for ( S32 y=0; y+currDim <= texSize.y; )
      {
         for ( S32 x=0; x+currDim <= texSize.x; )
         {
            // Copy the next bitmap to the dest texture.
            GBitmap* bmp = bitmaps.first();
            bitmaps.pop_front();
            destBmp.copyRect( bmp, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip );
            delete bmp;

            // Copy the next normal to the dest texture.
            GBitmap* normalmap = normalmaps.first();
            normalmaps.pop_front();
            destNormal.copyRect( normalmap, RectI( 0, 0, currDim, currDim ), Point2I( x, y ), 0, mip );
            delete normalmap;

            // Did we finish?
            if ( bitmaps.empty() )
               break;

            x += currDim;
         }

         // Did we finish?
         if ( bitmaps.empty() )
            break;

         y += currDim;
      }

      // Next mip...
      currDim /= 2;
   }

   PROFILE_END(); // TSLastDetail_snapshots

   delete imposterCap;
   delete shape;   
   
   
   // Should we dump the images?
   if ( Con::getBoolVariable( "$TSLastDetail::dumpImposters", false ) )
   {
      String imposterPath = mCachePath + ".imposter.png";
      String normalsPath = mCachePath + ".imposter_normals.png";

      FileStream stream;
      if ( stream.open( imposterPath, Torque::FS::File::Write  ) )
         destBmp.writeBitmap( "png", stream );
      stream.close();

      if ( stream.open( normalsPath, Torque::FS::File::Write ) )
         destNormal.writeBitmap( "png", stream );
      stream.close();
   }

   // DEBUG: Some code to force usage of a test image.
   //GBitmap* tempMap = GBitmap::load( "./forest/data/test1234.png" );
   //tempMap->extrudeMipLevels();
   //mTexture.set( tempMap, &GFXDefaultStaticDiffuseProfile, false );
   //delete tempMap;

   DDSFile *ddsDest = DDSFile::createDDSFileFromGBitmap( &destBmp );
   DDSUtil::squishDDS( ddsDest, GFXFormatDXT3 );

   DDSFile *ddsNormals = DDSFile::createDDSFileFromGBitmap( &destNormal );
   DDSUtil::squishDDS( ddsNormals, GFXFormatDXT5 );

   // Finally save the imposters to disk.
   FileStream fs;
   if ( fs.open( _getDiffuseMapPath(), Torque::FS::File::Write ) )
   {
      ddsDest->write( fs );
      fs.close();
   }
   if ( fs.open( _getNormalMapPath(), Torque::FS::File::Write ) )
   {
      ddsNormals->write( fs );
      fs.close();
   }

   delete ddsDest;
   delete ddsNormals;

   // If we did a begin then end it now.
   if ( !sceneBegun )
      GFX->endScene();
}
void ForestWind::processTick()
{
   PROFILE_SCOPE( ForestWind_ProcessTick );

   const F32 deltaTime = 0.032f;
   const U32 simTime = Sim::getCurrentTime();
   
   Point2F finalVec( 0, 0 );
   Point2F windDir( mParent->mWindDirection.x, mParent->mWindDirection.y );

   if ( mLastGustTime < simTime )
   {
      Point2F turbVec( 0, 0 );
      if ( mLastGustTime < simTime + (mParent->mWindTurbulenceFrequency * 1000.0f) )
         turbVec = (mRandom.randF() * mParent->mWindTurbulenceStrength) * windDir;

      mLastGustTime = simTime + (mParent->mWindGustFrequency * 1000.0f);
      Point2F gustVec = (mRandom.randF() * mParent->mWindGustStrength + mRandom.randF() * mParent->mWindGustWobbleStrength) * windDir;

      finalVec += gustVec + turbVec;
      //finalVec.normalizeSafe();
   }
   
   //bool rotationChange = false;

   if ( mLastYawTime < simTime )
   {
      mLastYawTime = simTime + (mParent->mWindGustYawFrequency * 1000.0f);
      F32 rotateAmt = mRandom.randF() * mParent->mWindGustYawAngle + mRandom.randF() * mParent->mWindGustWobbleStrength;
      
      if ( mRandom.randF() <= 0.5f )
         rotateAmt = -rotateAmt;

      rotateAmt = mDegToRad( rotateAmt );

      if ( rotateAmt > M_2PI_F )
         rotateAmt -= M_2PI_F;
      else if ( rotateAmt < -M_2PI_F )
         rotateAmt += M_2PI_F;

      mTargetYawAngle = rotateAmt;

      //finalVec.rotate( rotateAmt );
      mCurrentTarget.rotate( rotateAmt );
   }
   
   //mCurrentTarget.normalizeSafe();

   if ( mCurrentTarget.isZero() || mCurrentInterp >= 1.0f )
   {
      mCurrentInterp = 0;
      mCurrentTarget.set( 0, 0 );
   
      Point2F windDir( mDirection.x, mDirection.y );
      windDir.normalizeSafe();

      mCurrentTarget = finalVec + windDir;
   }
   else
   {
      mCurrentInterp += deltaTime;
      mCurrentInterp = mClampF( mCurrentInterp, 0.0f, 1.0f );
      mDirection.interpolate( mDirection, Point3F( mCurrentTarget.x, mCurrentTarget.y, 0 ), mCurrentInterp );
      //F32 rotateAmt = mLerp( 0, mTargetYawAngle, mCurrentInterp );

      //mTargetYawAngle -= rotateAmt;

      //Point2F dir( mDirection.x, mDirection.y );
      //if ( mTargetYawAngle > 0.0f )
        // dir.rotate( rotateAmt );

      //mDirection.set( dir.x, dir.y, 0 );
   }
}