void LightManager::registerGlobalLights( const Frustum *frustum, bool staticLighting )
{
   PROFILE_SCOPE( LightManager_RegisterGlobalLights );

   // TODO: We need to work this out...
   //
   // 1. Why do we register and unregister lights on every 
   //    render when they don't often change... shouldn't we
   //    just register once and keep them?
   // 
   // 2. If we do culling of lights should this happen as part
   //    of registration or somewhere else?
   //

   // Grab the lights to process.
   Vector<SceneObject*> activeLights;
   const U32 lightMask = LightObjectType;
   
   if ( staticLighting || !frustum )
   {
      // We're processing static lighting or want all the lights
      // in the container registerd...  so no culling.
      getSceneManager()->getContainer()->findObjectList( lightMask, &activeLights );
   }
   else
   {
      // Cull the lights using the frustum.
      getSceneManager()->getContainer()->findObjectList( *frustum, lightMask, &activeLights );

      // Store the culling position for sun placement
      // later... see setSpecialLight.
      mCullPos = frustum->getPosition();

      // HACK: Make sure the control object always gets 
      // processed as lights mounted to it don't change
      // the shape bounds and can often get culled.

      GameConnection *conn = GameConnection::getConnectionToServer();
      if ( conn->getControlObject() )
      {
         GameBase *conObject = conn->getControlObject();
         activeLights.push_back_unique( conObject );
      }
   }

   // Let the lights register themselves.
   for ( U32 i = 0; i < activeLights.size(); i++ )
   {
      ISceneLight *lightInterface = dynamic_cast<ISceneLight*>( activeLights[i] );
      if ( lightInterface )
         lightInterface->submitLights( this, staticLighting );
   }
}
Пример #2
0
void StdServerProcessList::onPreTickObject( ProcessObject *pobj )
{
   if ( pobj->mIsGameObject )
   {
      SimObjectPtr<GameObject> obj = getGameObject( pobj );

      // Each object is either advanced a single tick, or if it's
      // being controlled by a client, ticked once for each pending move.
      GameConnection *con = obj->getControllingClient();

      if ( con && con->getControlObject() == obj )
      {
         Move* movePtr;
         U32 numMoves;
         con->mMoveList->getMoves( &movePtr, &numMoves );

         if ( numMoves == 0 )
         {
   #ifdef TORQUE_DEBUG_NET_MOVES
            Con::printf("no moves on object %i, skip tick",obj->getId());
   #endif         
            return;
         }
      }
   }

   Parent::onPreTickObject (pobj );
}
Пример #3
0
void HifiClientProcessList::advanceObjects()
{
#ifdef TORQUE_DEBUG_NET_MOVES
   Con::printf("Advance client time...");
#endif

   // client re-computes this each time objects are advanced
   gMaxHiFiVelSq = 0;
   Parent::advanceObjects();

   // We need to consume a move on the connections whether 
   // there is a control object to consume the move or not,
   // otherwise client and server can get out of sync move-wise
   // during startup.  If there is a control object, we cleared
   // a move above.  Handle case where no control object here.
   // Note that we might consume an extra move here and there when
   // we had a control object in above loop but lost it during tick.
   // That is no big deal so we don't bother trying to carefully
   // track it.
   GameConnection * client = GameConnection::getConnectionToServer();
   if (client && client->getControlObject() == NULL)
      client->mMoveList->clearMoves(1);

#ifdef TORQUE_DEBUG_NET_MOVES
   Con::printf("---------");
#endif
}
Пример #4
0
static GameBase * getControlObj()
{
   GameConnection * connection = GameConnection::getLocalClientConnection();
   ShapeBase* control = 0;
   if(connection)
      control = dynamic_cast<ShapeBase*>(connection->getControlObject());
   return(control);
}
Пример #5
0
void WaterObject::updateUnderwaterEffect( SceneRenderState *state )
{
   AssertFatal( isClientObject(), "uWaterObject::updateUnderwaterEffect() called on the server" );

   PostEffect *effect = getUnderwaterEffect();
   if ( !effect )
      return;

   // Never use underwater postFx with Basic Lighting, we don't have depth.
   if ( mBasicLighting )
   {
      effect->disable();
      return;
   }

   GameConnection *conn = GameConnection::getConnectionToServer();
   if ( !conn )
      return;

   GameBase *control = conn->getControlObject();
   if ( !control )
      return;

   WaterObject *water = control->getCurrentWaterObject();
   if ( water == NULL )
      effect->disable();

   else if ( water == this )
   {
      MatrixF mat;      
      conn->getControlCameraTransform( 0, &mat );
      
      if ( mUnderwater )
      {
         effect->enable();
         effect->setOnThisFrame( true );

         mWaterFogData.depthGradMax = mDepthGradientMax;
         state->getSceneManager()->setWaterFogData( mWaterFogData );

         // Register our depthGradient texture with a name so it can
         // be fetched by the effect when it renders.
         if ( !mNamedDepthGradTex.isRegistered() )
            mNamedDepthGradTex.registerWithName( "waterDepthGradMap" );
         mNamedDepthGradTex.setTexture( mDepthGradientTex );         
      }
      else
         effect->disable();
   }
}
void ExtendedClientProcessList::onTickObject( ProcessObject *obj )
{
   PROFILE_SCOPE( ExtendedClientProcessList_OnTickObject );

   // In case the object deletes itself during its processTick.
   SimObjectPtr<SceneObject> safePtr = static_cast<SceneObject*>( obj );   

   // Each object is either advanced a single tick, or if it's
   // being controlled by a client, ticked once for each pending move.
   ExtendedMove* extMovePtr;
   U32 numMoves;
   GameConnection* con = obj->getControllingClient();
   if  ( con && con->getControlObject() == obj )
   {
      ExtendedMoveList* extMoveList = static_cast<ExtendedMoveList*>(con->mMoveList);
      extMoveList->getExtMoves( &extMovePtr, &numMoves );
      if ( numMoves )
      {
         // Note: should only have a single move at this point
         AssertFatal(numMoves==1,"ClientProccessList::onTickObject: more than one move in queue");

         #ifdef TORQUE_DEBUG_NET_MOVES
         U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
         #endif

         if ( obj->isTicking() )
            obj->processTick( extMovePtr );

         if ( bool(safePtr) && obj->getControllingClient() )
         {
            U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );

            // set checksum if not set or check against stored value if set
            extMovePtr->checksum = newsum;

            #ifdef TORQUE_DEBUG_NET_MOVES
            Con::printf("move checksum: %i, (start %i), (move %f %f %f)",
               movePtr->checksum,sum,movePtr->yaw,movePtr->y,movePtr->z);
            #endif
         }
         con->mMoveList->clearMoves( 1 );
      }
   }
   else if ( obj->isTicking() )
      obj->processTick( 0 );

  

}
Пример #7
0
void HifiServerProcessList::onTickObject(ProcessObject * pobj)
{
   // Each object is advanced a single tick
   // If it's controlled by a client, tick using a move.
               
   Move *movePtr;
   U32 numMoves;
   GameConnection *con = pobj->getControllingClient();
   SimObjectPtr<GameBase> obj = getGameBase( pobj );

   if ( obj && con && con->getControlObject() == obj && con->mMoveList->getMoves( &movePtr, &numMoves ) )
   {
#ifdef TORQUE_DEBUG_NET_MOVES
      U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );
#endif

      obj->processTick(movePtr);

      if ( bool(obj) && obj->getControllingClient() )
      {
         U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );

         // check move checksum
         if ( movePtr->checksum != newsum )
         {
#ifdef TORQUE_DEBUG_NET_MOVES
            if ( !obj->mIsAiControlled )
               Con::printf( "move %i checksum disagree: %i != %i, (start %i), (move %f %f %f)",
               movePtr->id, movePtr->checksum, newsum, sum, movePtr->yaw, movePtr->y, movePtr->z );
#endif
            movePtr->checksum = Move::ChecksumMismatch;
         }
         else
         {
#ifdef TORQUE_DEBUG_NET_MOVES
            Con::printf( "move %i checksum agree: %i == %i, (start %i), (move %f %f %f)",
               movePtr->id, movePtr->checksum, newsum, sum, movePtr->yaw, movePtr->y, movePtr->z );
#endif
         }

         // Adding this seems to fix constant corrections, but is it
         // really a sound fix?
         con->mMoveList->clearMoves( 1 );
      }
   }
   else if ( pobj->isTicking() )
      pobj->processTick( 0 );
}
Пример #8
0
void HifiClientProcessList::onTickObject(ProcessObject * pobj)
{
   // Each object is advanced a single tick
   // If it's controlled by a client, tick using a move.   

   Move *movePtr;
   U32 numMoves;
   GameConnection *con = pobj->getControllingClient();
   SimObjectPtr<GameBase> obj = getGameBase( pobj );

   if ( obj && con && con->getControlObject() == obj && con->mMoveList->getMoves( &movePtr, &numMoves) )
   {
#ifdef TORQUE_DEBUG_NET_MOVES
      U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );
#endif

      obj->processTick( movePtr );

      if ( bool(obj) && obj->getControllingClient() )
      {
         U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );

         // set checksum if not set or check against stored value if set
         movePtr->checksum = newsum;

#ifdef TORQUE_DEBUG_NET_MOVES
         Con::printf( "move checksum: %i, (start %i), (move %f %f %f)",
            movePtr->checksum,sum,movePtr->yaw,movePtr->y,movePtr->z );
#endif
      }
      con->mMoveList->clearMoves( 1 );
   }
   else if ( pobj->isTicking() )
      pobj->processTick( 0 );
   
   if ( obj && ( obj->getTypeMask() & GameBaseHiFiObjectType ) )
   {
      GameConnection * serverConnection = GameConnection::getConnectionToServer();
      TickCacheEntry * tce = obj->getTickCache().addCacheEntry();
      BitStream bs( tce->packetData, TickCacheEntry::MaxPacketSize );
      obj->writePacketData( serverConnection, &bs );

      Point3F vel = obj->getVelocity();
      F32 velSq = mDot( vel, vel );
      gMaxHiFiVelSq = getMax( gMaxHiFiVelSq, velSq );
   }
}
Пример #9
0
// Checks collisions with a SpeedZone
bool SpeedZone::collide(BfObject *hitObject)
{
    if(ignoreThisCollision)
        return false;

    // This is run on both server and client side to reduce lag
    if(isShipType(hitObject->getObjectTypeNumber()))     // Only ships & robots collide
    {
#ifndef ZAP_DEDICATED
        if(isGhost()) // On client, don't process speedZone on all moveObjects except the controlling one
        {
            ClientGame *client = static_cast<ClientGame *>(getGame());
            GameConnection *gc = client->getConnectionToServer();
            if(gc && gc->getControlObject() != hitObject)
                return false;
        }
#endif
        return true;
    }
    return false;
}
Пример #10
0
void Etherform::interpolateTick(F32 dt)
{
	Parent::interpolateTick(dt);

	if(dt != 0.0f)
	{
		Point3F pos = delta.pos + delta.posVec * dt;
		Point3F rot = delta.rot + delta.rotVec * dt;

		this->setRenderPosition(pos, rot, dt);

		// update laser trails...
		for( S32 i=0; i < NUM_ETHERFORM_LASERTRAILS; i++ )
		{
			if(mLaserTrailList[i])
				mLaserTrailList[i]->setLastNodePos(pos);
		}

		// apply camera effects - is this the best place? - bramage
		GameConnection* connection = GameConnection::getConnectionToServer();
		if(connection->isFirstPerson())
		{
			GameBase* obj = connection->getControlObject();
			if( obj == this )
			{
				MatrixF curTrans = this->getRenderTransform();
				curTrans.mul( gCamFXMgr.getTrans() );
				Parent::setRenderTransform( curTrans );
			}
		}
	}
	else
	{
		this->setRenderPosition(delta.pos, delta.rot, 0);
	}

	// Save last interpolation delta value.
	delta.dt = dt;
}
Пример #11
0
//----------------------------------------------------------------------------
/// Core rendering method for this control.
///
/// This method scans through all the current client ShapeBase objects.
/// If one is named, it displays the name and damage information for it.
///
/// Information is offset from the center of the object's bounding box,
/// unless the object is a PlayerObjectType, in which case the eye point
/// is used.
///
/// @param   updateRect   Extents of control.
void afxGuiTextHud::onRender( Point2I, const RectI &updateRect)
{
   // Background fill first
   if (mShowFill)
      GFX->getDrawUtil()->drawRectFill(updateRect, mFillColor.toColorI());

   // Must be in a TS Control
   GuiTSCtrl *parent = dynamic_cast<GuiTSCtrl*>(getParent());
   if (!parent) return;

   // Must have a connection and control object
   GameConnection* conn = GameConnection::getConnectionToServer();
   if (!conn)
      return;

   GameBase * control = dynamic_cast<GameBase*>(conn->getControlObject());
   if (!control)
      return;

   // Get control camera info
   MatrixF cam;
   Point3F camPos;
   VectorF camDir;
   conn->getControlCameraTransform(0,&cam);
   cam.getColumn(3, &camPos);
   cam.getColumn(1, &camDir);

   F32 camFovCos;
   conn->getControlCameraFov(&camFovCos);
   camFovCos = mCos(mDegToRad(camFovCos) / 2);

   // Visible distance info & name fading
   F32 visDistance = gClientSceneGraph->getVisibleDistance();
   F32 visDistanceSqr = visDistance * visDistance;
   F32 fadeDistance = visDistance * mDistanceFade;

   // Collision info. We're going to be running LOS tests and we
   // don't want to collide with the control object.
   static U32 losMask = TerrainObjectType | TerrainLikeObjectType | ShapeBaseObjectType;

   if (!mEnableControlObjectOcclusion)
      control->disableCollision();

   if (mLabelAllShapes)
   {
     // This section works just like GuiShapeNameHud and renders labels for
     // all the shapes.

     // All ghosted objects are added to the server connection group,
     // so we can find all the shape base objects by iterating through
     // our current connection.
     for (SimSetIterator itr(conn); *itr; ++itr) 
     {
       ///if ((*itr)->getTypeMask() & ShapeBaseObjectType) 
       ///{
       ShapeBase* shape = dynamic_cast<ShapeBase*>(*itr);
       if ( shape ) {
         if (shape != control && shape->getShapeName()) 
         {

           // Target pos to test, if it's a player run the LOS to his eye
           // point, otherwise we'll grab the generic box center.
           Point3F shapePos;
           if (shape->getTypeMask() & PlayerObjectType) 
           {
             MatrixF eye;

             // Use the render eye transform, otherwise we'll see jittering
             shape->getRenderEyeTransform(&eye);
             eye.getColumn(3, &shapePos);
           }
           else 
           {
             // Use the render transform instead of the box center
             // otherwise it'll jitter.
             MatrixF srtMat = shape->getRenderTransform();
             srtMat.getColumn(3, &shapePos);
           }

           VectorF shapeDir = shapePos - camPos;

           // Test to see if it's in range
           F32 shapeDist = shapeDir.lenSquared();
           if (shapeDist == 0 || shapeDist > visDistanceSqr)
             continue;
           shapeDist = mSqrt(shapeDist);

           // Test to see if it's within our viewcone, this test doesn't
           // actually match the viewport very well, should consider
           // projection and box test.
           shapeDir.normalize();
           F32 dot = mDot(shapeDir, camDir);
           if (dot < camFovCos)
             continue;

           // Test to see if it's behind something, and we want to
           // ignore anything it's mounted on when we run the LOS.
           RayInfo info;
           shape->disableCollision();
           SceneObject *mount = shape->getObjectMount();
           if (mount)
             mount->disableCollision();
           bool los = !gClientContainer.castRay(camPos, shapePos,losMask, &info);
           shape->enableCollision();
           if (mount)
             mount->enableCollision();

           if (!los)
             continue;

           // Project the shape pos into screen space and calculate
           // the distance opacity used to fade the labels into the
           // distance.
           Point3F projPnt;
           shapePos.z += mVerticalOffset;
           if (!parent->project(shapePos, &projPnt))
             continue;
           F32 opacity = (shapeDist < fadeDistance)? 1.0:
             1.0 - (shapeDist - fadeDistance) / (visDistance - fadeDistance);

           // Render the shape's name
           drawName(Point2I((S32)projPnt.x, (S32)projPnt.y),shape->getShapeName(),opacity);
         }
       }
     }
   }

   // This section renders all text added by afxGuiText effects.
   for (S32 i = 0; i < text_items.size(); i++)
   {
     HudTextSpec* spec = &text_items[i];
     if (spec->text && spec->text[0] != '\0') 
     {
       VectorF shapeDir = spec->pos - camPos;

       // do range test
       F32 shapeDist = shapeDir.lenSquared();
       if (shapeDist == 0 || shapeDist > visDistanceSqr)
         continue;
       shapeDist = mSqrt(shapeDist);

       // Test to see if it's within our viewcone, this test doesn't
       // actually match the viewport very well, should consider
       // projection and box test.
       shapeDir.normalize();
       F32 dot = mDot(shapeDir, camDir);
       if (dot < camFovCos)
         continue;

       // Test to see if it's behind something, and we want to
       // ignore anything it's mounted on when we run the LOS.
       RayInfo info;
       if (spec->obj)
         spec->obj->disableCollision();
       bool los = !gClientContainer.castRay(camPos, spec->pos, losMask, &info);
       if (spec->obj)
         spec->obj->enableCollision();
       if (!los)
         continue;

       // Project the shape pos into screen space.
       Point3F projPnt;
       if (!parent->project(spec->pos, &projPnt))
         continue;

       // Calculate the distance opacity used to fade text into the distance.
       F32 opacity = (shapeDist < fadeDistance)? 1.0 : 1.0 - (shapeDist - fadeDistance) / (25.0f);
       if (opacity > 0.01f)
        drawName(Point2I((S32)projPnt.x, (S32)projPnt.y), spec->text, opacity, &spec->text_clr);
     }
   }

   // Restore control object collision
   if (!mEnableControlObjectOcclusion)
      control->enableCollision();

   // Border last
   if (mShowFrame)
      GFX->getDrawUtil()->drawRect(updateRect, mFrameColor.toColorI());

   reset();
}
Пример #12
0
bool LightFlareData::_testVisibility(const SceneRenderState *state, LightFlareState *flareState, U32 *outVisDelta, F32 *outOcclusionFade, Point3F *outLightPosSS)
{
   // Reflections use the results from the last forward
   // render so we don't need multiple queries.
   if ( state->isReflectPass() )
   {
      *outOcclusionFade = flareState->occlusion;
      *outVisDelta = Sim::getCurrentTime() - flareState->visChangedTime;
      return flareState->visible;
   }

   // Initialize it to something first.
   *outOcclusionFade = 0;

   // First check to see if the flare point 
   // is on scren at all... if not then return
   // the last result.
   const Point3F &lightPos = flareState->lightMat.getPosition();  
   const RectI &viewport = GFX->getViewport();
   MatrixF projMatrix;
   state->getCameraFrustum().getProjectionMatrix(&projMatrix);
   if( state->isReflectPass() )
      projMatrix = state->getSceneManager()->getNonClipProjection();
   bool onScreen = MathUtils::mProjectWorldToScreen( lightPos, outLightPosSS, viewport, GFX->getWorldMatrix(), projMatrix );

   // It is onscreen, so raycast as a simple occlusion test.
   const LightInfo *lightInfo = flareState->lightInfo;
   const bool isVectorLight = lightInfo->getType() == LightInfo::Vector;

   const bool useOcclusionQuery = isVectorLight ? flareState->worldRadius > 0.0f : mOcclusionRadius > 0.0f;
   bool needsRaycast = true;

   // NOTE: if hardware does not support HOQ it will return NULL
   // and we will retry every time but there is not currently a good place
   // for one-shot initialization of LightFlareState
   if ( useOcclusionQuery )
   {
      // Always treat light as onscreen if using HOQ
      // it will be faded out if offscreen anyway.
      onScreen = true;
	  needsRaycast = false;

      // Test the hardware queries for rendered pixels.
      U32 pixels = 0, fullPixels = 0;
      GFXOcclusionQuery::OcclusionQueryStatus status;
      flareState->occlusionQuery.getLastStatus( false, &status, &pixels );      
      flareState->fullPixelQuery.getLastStatus( false, NULL, &fullPixels );
      
      if ( status == GFXOcclusionQuery::NotOccluded && fullPixels != 0 )
         *outOcclusionFade = mClampF( (F32)pixels / (F32)fullPixels, 0.0f, 1.0f );

        if( !flareState->occlusionQuery.isWaiting() )
        {
            // Setup the new queries.
            RenderPassManager *rpm = state->getRenderPass();
            OccluderRenderInst *ri = rpm->allocInst<OccluderRenderInst>();   
            ri->type = RenderPassManager::RIT_Occluder;
            ri->query = flareState->occlusionQuery.getQuery();
            ri->query2 = flareState->fullPixelQuery.getQuery();
            ri->isSphere = true;
            ri->position = lightPos;
            if ( isVectorLight && flareState->worldRadius > 0.0f )         
                ri->scale.set( flareState->worldRadius );
            else
                ri->scale.set( mOcclusionRadius );
            ri->orientation = rpm->allocUniqueXform( lightInfo->getTransform() );         
      
            // Submit the queries.
            state->getRenderPass()->addInst( ri );
        }
   }

   const Point3F &camPos = state->getCameraPosition();

   if ( needsRaycast )
   {
      // Use a raycast to determine occlusion.
      GameConnection *conn = GameConnection::getConnectionToServer();
      if ( !conn )
         return false;

      const bool fps = conn->isFirstPerson();
      GameBase *control = conn->getControlObject();
      if ( control && fps )
         control->disableCollision();

      RayInfo rayInfo;

      if ( !gClientContainer.castRay( camPos, lightPos, LosMask, &rayInfo ) )
         *outOcclusionFade = 1.0f;

      if ( control && fps )
         control->enableCollision();
   }

   // The raycast and hardware occlusion query only calculate if
   // the flare is on screen... if does not account for being 
   // partially offscreen.
   //
   // The code here clips a box against the viewport to 
   // get an approximate percentage of onscreen area.
   //
   F32 worldRadius = flareState->worldRadius > 0 ? flareState->worldRadius : mOcclusionRadius;
   if ( worldRadius > 0.0f )
   {
      F32 dist = ( camPos - lightPos ).len();
      F32 pixelRadius = state->projectRadius(dist, worldRadius);

      RectI visRect( outLightPosSS->x - pixelRadius, outLightPosSS->y - pixelRadius, 
                     pixelRadius * 2.0f, pixelRadius * 2.0f ); 
      F32 fullArea = visRect.area();

      if ( visRect.intersect( viewport ) )
      {
         F32 visArea = visRect.area();
         *outOcclusionFade *= visArea / fullArea;
         onScreen = true;
      }
      else
         *outOcclusionFade = 0.0f;
   }
   
   const bool lightVisible = onScreen && *outOcclusionFade > 0.0f;

   // To perform a fade in/out when we gain or lose visibility
   // we must update/store the visibility state and time.
   const U32 currentTime = Sim::getCurrentTime();
   if ( lightVisible != flareState->visible )
   {
      flareState->visible = lightVisible;
      flareState->visChangedTime = currentTime;
   }

   // Return the visibility delta for time fading.
   *outVisDelta = currentTime - flareState->visChangedTime;

   // Store the final occlusion fade so that it can
   // be used in reflection rendering later.
   flareState->occlusion = *outOcclusionFade;

   return lightVisible;
}
Пример #13
0
void SceneManager::_renderScene( SceneRenderState* state, U32 objectMask, SceneZoneSpace* baseObject, U32 baseZone )
{
   AssertFatal( this == gClientSceneGraph, "SceneManager::_buildSceneGraph - Only the client scenegraph can support this call!" );

   PROFILE_SCOPE( SceneGraph_batchRenderImages );

   // In the editor, override the type mask for diffuse passes.

   if( gEditingMission && state->isDiffusePass() )
      objectMask = EDITOR_RENDER_TYPEMASK;

   // Update the zoning state and traverse zones.

   if( getZoneManager() )
   {
      // Update.

      getZoneManager()->updateZoningState();

      // If zone culling isn't disabled, traverse the
      // zones now.

      if( !state->getCullingState().disableZoneCulling() )
      {
         // Find the start zone if we haven't already.

         if( !baseObject )
         {
            getZoneManager()->findZone( state->getCameraPosition(), baseObject, baseZone );
            AssertFatal( baseObject != NULL, "SceneManager::_renderScene - findZone() did not return an object" );
         }

         // Traverse zones starting in base object.

         SceneTraversalState traversalState( &state->getCullingState() );
         PROFILE_START( Scene_traverseZones );
         baseObject->traverseZones( &traversalState, baseZone );
         PROFILE_END();

         // Set the scene render box to the area we have traversed.

         state->setRenderArea( traversalState.getTraversedArea() );
      }
   }

   // Set the query box for the container query.  Never
   // make it larger than the frustum's AABB.  In the editor,
   // always query the full frustum as that gives objects
   // the opportunity to render editor visualizations even if
   // they are otherwise not in view.

   if( !state->getFrustum().getBounds().isOverlapped( state->getRenderArea() ) )
   {
      // This handles fringe cases like flying backwards into a zone where you
      // end up pretty much standing on a zone border and looking directly into
      // its "walls".  In that case the traversal area will be behind the frustum
      // (remember that the camera isn't where visibility starts, it's the near
      // distance).

      return;
   }

   Box3F queryBox = state->getFrustum().getBounds();
   if( !gEditingMission )
   {
      queryBox.minExtents.setMax( state->getRenderArea().minExtents );
      queryBox.maxExtents.setMin( state->getRenderArea().maxExtents );
   }

   PROFILE_START( Scene_cullObjects );

   //TODO: We should split the codepaths here based on whether the outdoor zone has visible space.
   //    If it has, we should use the container query-based path.
   //    If it hasn't, we should fill the object list directly from the zone lists which will usually
   //       include way fewer objects.
   
   // Gather all objects that intersect the scene render box.

   mBatchQueryList.clear();
   getContainer()->findObjectList( queryBox, objectMask, &mBatchQueryList );

   // Cull the list.

   U32 numRenderObjects = state->getCullingState().cullObjects(
      mBatchQueryList.address(),
      mBatchQueryList.size(),
      !state->isDiffusePass() ? SceneCullingState::CullEditorOverrides : 0 // Keep forced editor stuff out of non-diffuse passes.
   );

   //HACK: If the control object is a Player and it is not in the render list, force
   // it into it.  This really should be solved by collision bounds being separate from
   // object bounds; only because the Player class is using bounds not encompassing
   // the actual player object is it that we have this problem in the first place.
   // Note that we are forcing the player object into ALL passes here but such
   // is the power of proliferation of things done wrong.

   GameConnection* connection = GameConnection::getConnectionToServer();
   if( connection )
   {
      Player* player = dynamic_cast< Player* >( connection->getControlObject() );
      if( player )
      {
         mBatchQueryList.setSize( numRenderObjects );
         if( !mBatchQueryList.contains( player ) )
         {
            mBatchQueryList.push_back( player );
            numRenderObjects ++;
         }
      }
   }

   PROFILE_END();

   // Render the remaining objects.

   PROFILE_START( Scene_renderObjects );
   state->renderObjects( mBatchQueryList.address(), numRenderObjects );
   PROFILE_END();

   // Render bounding boxes, if enabled.

   if( smRenderBoundingBoxes && state->isDiffusePass() )
   {
      GFXDEBUGEVENT_SCOPE( Scene_renderBoundingBoxes, ColorI::WHITE );

      GameBase* cameraObject = 0;
      if( connection )
         cameraObject = connection->getCameraObject();

      GFXStateBlockDesc desc;
      desc.setFillModeWireframe();
      desc.setZReadWrite( true, false );

      for( U32 i = 0; i < numRenderObjects; ++ i )
      {
         SceneObject* object = mBatchQueryList[ i ];

         // Skip global bounds object.
         if( object->isGlobalBounds() )
            continue;

         // Skip camera object as we're viewing the scene from it.
         if( object == cameraObject )
            continue;

         const Box3F& worldBox = object->getWorldBox();
         GFX->getDrawUtil()->drawObjectBox(
            desc,
            Point3F( worldBox.len_x(), worldBox.len_y(), worldBox.len_z() ),
            worldBox.getCenter(),
            MatrixF::Identity,
            ColorI::WHITE
         );
      }
   }
}
Пример #14
0
void StdServerProcessList::onTickObject( ProcessObject *pobj )
{
   PROFILE_SCOPE( StdServerProcessList_OnTickObject );
   
   // Each object is either advanced a single tick, or if it's
   // being controlled by a client, ticked once for each pending move.

   GameConnection *con = pobj->getControllingClient();

   if ( pobj->mIsGameObject && con && con->getControlObject() == pobj )
   {
      // In case the object is deleted during its own tick.
      SimObjectPtr<GameObject> obj = getGameObject( pobj );

      Move* movePtr;
      U32 m, numMoves;
      con->mMoveList->getMoves( &movePtr, &numMoves );

      // For debugging it can be useful to know when this happens.
      //if ( numMoves > 1 )
      //   Con::printf( "numMoves: %i", numMoves );

      // Do we really need to test the control object each iteration? Does it change?
      for ( m = 0; m < numMoves && con && con->getControlObject() == obj; m++, movePtr++ )
      {         
         #ifdef TORQUE_DEBUG_NET_MOVES
         U32 sum = Move::ChecksumMask & obj->getPacketDataChecksum(obj->getControllingClient());
         #endif
      
         if ( obj->isTicking() )
            obj->processMove( movePtr );

         if ( con && con->getControlObject() == obj )
         {
            U32 newsum = Move::ChecksumMask & obj->getPacketDataChecksum( obj->getControllingClient() );

            // check move checksum
            if ( movePtr->checksum != newsum )
            {
               #ifdef TORQUE_DEBUG_NET_MOVES
               if( !obj->isAIControlled() )
                  Con::printf("move %i checksum disagree: %i != %i, (start %i), (move %f %f %f)",
                     movePtr->id, movePtr->checksum,newsum,sum,movePtr->yaw,movePtr->y,movePtr->z);
               #endif

               movePtr->checksum = Move::ChecksumMismatch;
            }
            else
            {
               #ifdef TORQUE_DEBUG_NET_MOVES
               Con::printf("move %i checksum agree: %i == %i, (start %i), (move %f %f %f)",
                  movePtr->id, movePtr->checksum,newsum,sum,movePtr->yaw,movePtr->y,movePtr->z);
               #endif
            }
         }
      }

      con->mMoveList->clearMoves( m );
   }
   else if ( pobj->isTicking() )
      pobj->processMove( 0 );
}
Пример #15
0
void LightFlareData::prepRender( SceneState *state, LightFlareState *flareState )
{    
   PROFILE_SCOPE( LightFlareData_prepRender );

   // No elements then nothing to render.
   if ( mElementCount == 0 )
      return;

   // We need these all over the place later.
   const Point3F &camPos = state->getCameraPosition();
   const RectI &viewport = GFX->getViewport();
   const Point3F &lightPos = flareState->lightMat.getPosition();
   LightInfo *lightInfo = flareState->lightInfo;

   bool isVectorLight = lightInfo->getType() == LightInfo::Vector;

   // Perform visibility testing on the light...
   // Project the light position from world to screen space, we need this
   // position later, and it tells us if it is actually onscreen.   
   
   Point3F lightPosSS;
   bool onscreen = MathUtils::mProjectWorldToScreen( lightPos, &lightPosSS, viewport, GFX->getWorldMatrix(), gClientSceneGraph->getNonClipProjection() );  

   U32 visDelta = U32_MAX;
   U32 fadeOutTime = 20;
   U32 fadeInTime = 125;    

   // Fade factor based on amount of occlusion.
   F32 occlusionFade = 1.0f;

   bool lightVisible = true;
   
   if ( !state->isReflectPass() )
   {
      // It is onscreen, so raycast as a simple occlusion test.

      U32 losMask =	STATIC_COLLISION_MASK |
                     ShapeBaseObjectType |
                     StaticTSObjectType |
                     ItemObjectType |
                     PlayerObjectType;

      GameConnection *conn = GameConnection::getConnectionToServer();
      if ( !conn )
         return;

      bool needsRaycast = true;

      // NOTE: if hardware does not support HOQ it will return NULL
      // and we will retry every time but there is not currently a good place
      // for one-shot initialization of LightFlareState
      if ( flareState->occlusionQuery == NULL )
         flareState->occlusionQuery = GFX->createOcclusionQuery();
      if ( flareState->fullPixelQuery == NULL )
         flareState->fullPixelQuery = GFX->createOcclusionQuery();

      if ( flareState->occlusionQuery && 
           ( ( isVectorLight && flareState->worldRadius > 0.0f ) || 
             ( !isVectorLight && mOcclusionRadius > 0.0f ) ) )
      {
         // Always treat light as onscreen if using HOQ
         // it will be faded out if offscreen anyway.
         onscreen = true;

         U32 pixels = -1;
         GFXOcclusionQuery::OcclusionQueryStatus status = flareState->occlusionQuery->getStatus( true, &pixels );

         String str = flareState->occlusionQuery->statusToString( status );
         Con::setVariable( "$Flare::OcclusionStatus", str.c_str() );
         Con::setIntVariable( "$Flare::OcclusionVal", pixels );
         
         if ( status == GFXOcclusionQuery::Occluded )
            occlusionFade = 0.0f;

         if ( status != GFXOcclusionQuery::Unset )         
            needsRaycast = false;

         RenderPassManager *pass = state->getRenderPass();

         OccluderRenderInst *ri = pass->allocInst<OccluderRenderInst>();   

         Point3F scale( Point3F::One );

         if ( isVectorLight && flareState->worldRadius > 0.0f )         
            scale *= flareState->worldRadius;
         else
            scale *= mOcclusionRadius;
         
         ri->type = RenderPassManager::RIT_Occluder;
         ri->query = flareState->occlusionQuery;   
         ri->query2 = flareState->fullPixelQuery;
         ri->position = lightPos;
         ri->scale = scale;
         ri->orientation = pass->allocUniqueXform( lightInfo->getTransform() );         
         ri->isSphere = true;
         state->getRenderPass()->addInst( ri );

         if ( status == GFXOcclusionQuery::NotOccluded )
         {
            U32 fullPixels;
            flareState->fullPixelQuery->getStatus( true, &fullPixels );

            occlusionFade = (F32)pixels / (F32)fullPixels;

            // Approximation of the full pixel count rather than doing
            // two queries, but it is not very accurate.
            /*
            F32 dist = ( camPos - lightPos ).len();
            F32 radius = scale.x;
            radius = ( radius / dist ) * state->getWorldToScreenScale().y;

            occlusionFade = (F32)pixels / (4.0f * radius * radius);
            occlusionFade = mClampF( occlusionFade, 0.0f, 1.0f );            
            */
         }
      }

      Con::setFloatVariable( "$Flare::OcclusionFade", occlusionFade );

      if ( needsRaycast )
      {
         // Use a raycast to determine occlusion.

         bool fps = conn->isFirstPerson();

         GameBase *control = conn->getControlObject();
         if ( control && fps )
            control->disableCollision();

         RayInfo rayInfo;

         if ( gClientContainer.castRayRendered( camPos, lightPos, losMask, &rayInfo ) )
            occlusionFade = 0.0f;

         if ( control && fps )
            control->enableCollision();
      }

      lightVisible = onscreen && occlusionFade > 0.0f;

      // To perform a fade in/out when we gain or lose visibility
      // we must update/store the visibility state and time.

      U32 currentTime = Sim::getCurrentTime();

      if ( lightVisible != flareState->visible )
      {
         flareState->visible = lightVisible;
         flareState->visChangedTime = currentTime;
      }      

      // Save this in the state so that we have it during the reflect pass.
      flareState->occlusion = occlusionFade;

      visDelta = currentTime - flareState->visChangedTime;      
   }
   else // state->isReflectPass()
   {
      occlusionFade = flareState->occlusion;
      lightVisible = flareState->visible;
      visDelta = Sim::getCurrentTime() - flareState->visChangedTime;
   }

   // We can only skip rendering if the light is not visible, and it
   // has elapsed the fadeOutTime.
   if ( !lightVisible && visDelta > fadeOutTime )
      return;

   // In a reflection we only render the elements with zero distance.   
   U32 elementCount = mElementCount;
   if ( state->isReflectPass()  )
   {
      elementCount = 0;
      for ( ; elementCount < mElementCount; elementCount++ )
      {
         if ( mElementDist[elementCount] > 0.0f )
            break;
      }
   }

   if ( elementCount == 0 )
      return;

   // A bunch of preparatory math before generating verts...

   const Point2I &vpExtent = viewport.extent;
   Point3F viewportExtent( vpExtent.x, vpExtent.y, 1.0f );
   Point2I halfViewportExtentI( viewport.extent / 2 );
   Point3F halfViewportExtentF( (F32)halfViewportExtentI.x * 0.5f, (F32)halfViewportExtentI.y, 0.0f );
   Point3F screenCenter( 0,0,0 );
   Point3F oneOverViewportExtent( 1.0f / viewportExtent.x, 1.0f / viewportExtent.y, 1.0f );

   lightPosSS.y -= viewport.point.y;
   lightPosSS *= oneOverViewportExtent;
   lightPosSS = ( lightPosSS * 2.0f ) - Point3F::One;
   lightPosSS.y = -lightPosSS.y;
   lightPosSS.z = 0.0f;

   Point3F flareVec( screenCenter - lightPosSS );
   F32 flareLength = flareVec.len();   
   flareVec.normalizeSafe();

   Point3F basePoints[4];
   basePoints[0] = Point3F( -0.5, 0.5, 0.0 );  
   basePoints[1] = Point3F( -0.5, -0.5, 0.0 );   
   basePoints[2] = Point3F( 0.5, -0.5, 0.0 );   
   basePoints[3] = Point3F( 0.5, 0.5, 0.0 );

   Point3F rotatedBasePoints[4];
   rotatedBasePoints[0] = basePoints[0];
   rotatedBasePoints[1] = basePoints[1];
   rotatedBasePoints[2] = basePoints[2];
   rotatedBasePoints[3] = basePoints[3];

   Point3F fvec( -1, 0, 0 );   
   F32 rot = mAcos( mDot( fvec, flareVec ) );
   Point3F rvec( 0, -1, 0 );
   rot *= mDot( rvec, flareVec ) > 0.0f ? 1.0f : -1.0f;

   vectorRotateZAxis( rotatedBasePoints[0], rot );
   vectorRotateZAxis( rotatedBasePoints[1], rot );
   vectorRotateZAxis( rotatedBasePoints[2], rot );
   vectorRotateZAxis( rotatedBasePoints[3], rot );

   // Here we calculate a the light source's influence on the effect's size
   // and brightness...

   // Scale based on the current light brightness compared to its normal output.
   F32 lightSourceBrightnessScale = lightInfo->getBrightness() / flareState->fullBrightness;
   // Scale based on world space distance from camera to light source.
   F32 lightSourceWSDistanceScale = ( isVectorLight ) ? 1.0f : getMin( 10.0f / ( lightPos - camPos ).len(), 1.5f );   
   // Scale based on screen space distance from screen position of light source to the screen center.
   F32 lightSourceSSDistanceScale = ( 1.5f - ( lightPosSS - screenCenter ).len() ) / 1.5f;

   // Scale based on recent visibility changes, fading in or out.
   F32 fadeInOutScale = 1.0f;
   if ( lightVisible && visDelta < fadeInTime && flareState->occlusion )
      fadeInOutScale = (F32)visDelta / (F32)fadeInTime;
   else if ( !lightVisible && visDelta < fadeOutTime )
      fadeInOutScale = 1.0f - (F32)visDelta / (F32)fadeOutTime;

   // This combined scale influences the size of all elements this effect renders.
   // Note we also add in a scale that is user specified in the Light.
   F32 lightSourceIntensityScale = lightSourceBrightnessScale * 
                                   lightSourceWSDistanceScale * 
                                   lightSourceSSDistanceScale * 
                                   fadeInOutScale * 
                                   flareState->scale *
                                   occlusionFade;

   // The baseColor which modulates the color of all elements.
   ColorF baseColor;
   if ( flareState->fullBrightness == 0.0f )
      baseColor = ColorF::BLACK;
   else
      // These are the factors which affect the "alpha" of the flare effect.
      // Modulate more in as appropriate.
      baseColor = ColorF::WHITE * lightSourceBrightnessScale * occlusionFade;

   // Fill in the vertex buffer...
   const U32 vertCount = 4 * elementCount;
   if (  flareState->vertBuffer.isNull() || 
         flareState->vertBuffer->mNumVerts != vertCount )
         flareState->vertBuffer.set( GFX, vertCount, GFXBufferTypeDynamic );

   GFXVertexPCT *pVert = flareState->vertBuffer.lock();

   const Point2I &widthHeightI = mFlareTexture.getWidthHeight();
   Point2F oneOverTexSize( 1.0f / (F32)widthHeightI.x, 1.0f / (F32)widthHeightI.y );

   for ( U32 i = 0; i < elementCount; i++ )
   {      
      Point3F *basePos = mElementRotate[i] ? rotatedBasePoints : basePoints;

      ColorF elementColor( baseColor * mElementTint[i] );
      if ( mElementUseLightColor[i] )
         elementColor *= lightInfo->getColor();

      Point3F elementPos;
      elementPos = lightPosSS + flareVec * mElementDist[i] * flareLength;      
      elementPos.z = 0.0f;

      F32 maxDist = 1.5f;
      F32 elementDist = mSqrt( ( elementPos.x * elementPos.x ) + ( elementPos.y * elementPos.y ) );
      F32 distanceScale = ( maxDist - elementDist ) / maxDist;
      distanceScale = 1.0f;

      const RectF &elementRect = mElementRect[i];
      Point3F elementSize( elementRect.extent.x, elementRect.extent.y, 1.0f );
      elementSize *= mElementScale[i] * distanceScale * mScale * lightSourceIntensityScale;

      if ( elementSize.x < 100.0f )
      {
         F32 alphaScale = mPow( elementSize.x / 100.0f, 2 );
         elementColor *= alphaScale;
      }

      elementColor.clamp();

      Point2F texCoordMin, texCoordMax;
      texCoordMin = elementRect.point * oneOverTexSize;
      texCoordMax = ( elementRect.point + elementRect.extent ) * oneOverTexSize;          

      pVert->color = elementColor;
      pVert->point = ( basePos[0] * elementSize * oneOverViewportExtent ) + elementPos;      
      pVert->texCoord.set( texCoordMin.x, texCoordMax.y );
      pVert++;

      pVert->color = elementColor;
      pVert->point = ( basePos[1] * elementSize * oneOverViewportExtent ) + elementPos;
      pVert->texCoord.set( texCoordMax.x, texCoordMax.y );
      pVert++;

      pVert->color = elementColor;
      pVert->point = ( basePos[2] * elementSize * oneOverViewportExtent ) + elementPos;
      pVert->texCoord.set( texCoordMax.x, texCoordMin.y );
      pVert++;

      pVert->color = elementColor;
      pVert->point = ( basePos[3] * elementSize * oneOverViewportExtent ) + elementPos;
      pVert->texCoord.set( texCoordMin.x, texCoordMin.y );
      pVert++;
   }   

   flareState->vertBuffer.unlock();   

   // Create and submit the render instance...
   
   RenderPassManager *renderManager = state->getRenderPass();
   ParticleRenderInst *ri = renderManager->allocInst<ParticleRenderInst>();

   ri->vertBuff = &flareState->vertBuffer;
   ri->primBuff = &mFlarePrimBuffer;
   ri->translucentSort = true;
   ri->type = RenderPassManager::RIT_Particle;
   ri->sortDistSq = ( lightPos - camPos ).lenSquared();

   ri->modelViewProj = &MatrixF::Identity;
   ri->bbModelViewProj = ri->modelViewProj;

   ri->count = elementCount;

   // Only draw the light flare in high-res mode, never off-screen mode
   ri->systemState = ParticleRenderInst::AwaitingHighResDraw;

   ri->blendStyle = ParticleRenderInst::BlendGreyscale;

   ri->diffuseTex = &*(mFlareTexture);

   ri->softnessDistance = 1.0f; 

   // Sort by texture too.
   ri->defaultKey = ri->diffuseTex ? (U32)ri->diffuseTex : (U32)ri->vertBuff;

   renderManager->addInst( ri );
}
Пример #16
0
void Etherform::processTick(const Move* move)
{
   Parent::processTick(move);

   // Warp to catch up to server?
   if(delta.warpTicks > 0)
   {
		delta.warpTicks--;

		// Set new pos.
		getTransform().getColumn(3,&delta.pos);
		delta.pos += delta.warpOffset;
		delta.rot += delta.rotOffset;
		this->setPosition(delta.pos,delta.rot);
		this->setRenderPosition(delta.pos,delta.rot);

		// Backstepping
		delta.posVec.x = -delta.warpOffset.x;
		delta.posVec.y = -delta.warpOffset.y;
		delta.posVec.z = -delta.warpOffset.z;
		delta.rotVec.x = -delta.rotOffset.x;
		delta.rotVec.y = -delta.rotOffset.y;
		delta.rotVec.z = -delta.rotOffset.z;
	}
	else
	{
		// If there is no move, the we're either an
		// unattached etherform on the server, or another etherform's
		// client ghost.
		if(!move)
		{
			if(isGhost())
			{
				// If we haven't run out of prediction time,
				// predict using the last known move.
				if (mPredictionCount-- <= 0)
					return;

				move = &delta.move;
			}
			else
				move = &NullMove;
		}

		if(isServerObject() || (didRenderLastRender() || getControllingClient()))
		{
			delta.move = *move;

         if(isMounted())
         {
            // If we're mounted then do not perform any collision checks
            // and clear our previous working list.
            mConvex.clearWorkingList();
         }
         else
         {
            this->updateWorkingCollisionSet();
         }

			this->updateVelocity(move);
         VectorF contactNormal(0,0,0);
         this->findContact(&contactNormal );
			this->updatePos();
		}
	}

	// Add node to lasertrails.
	if(this->isClientObject())
	{
		GameConnection* conn = GameConnection::getConnectionToServer();
		if(conn && this == conn->getControlObject())
		{
			if(move->sendCount == 0)
				this->addLaserTrailNode(this->getPosition());
		}
		else
			this->addLaserTrailNode(this->getPosition());
	}
}
Пример #17
0
Move HoverPodController::getMove(ShapeBase* obj)
{
	Move retMove = NullMove;

	GameConnection* client = NULL;
	if(!Sim::findObject(mClientId, client)) 
		return retMove;

	ShapeBase* control = client->getControlObject();
	if(control)
	{
		Move cMove = client->lastReceivedMove();

		Point3F v1, v2;
		control->getTransform().getColumn(0, &v1);
		control->getTransform().getColumn(1, &v2);
		Point3F pv = v1*cMove.x + v2*cMove.y;

		//pv = mDirection * mDot(pv, mDirection);

		obj->getTransform().getColumn(0, &v1);
		obj->getTransform().getColumn(1, &v2);
		retMove.x = mDot(v1, pv);
		retMove.y = mDot(v2, pv);
	}
	return retMove;
	
#if 0
   if(this->isServerObject() && this->isMounted())
   {
		Move mMove = NullMove;
		ShapeBase* mount = this->getObjectMount();
		if(mount->getType() & VehicleObjectType)
		{
			Vehicle* vehicle = (Vehicle*)mount;
			if(move && move->x != 0)
			{
				mMove.yaw = move->x;
			}
			else
			{
				Point3F zv; vehicle->getTransform().getColumn(2, &zv);
				zv.normalize();
				Point3F m = vehicle->getRigid().angMomentum;
				//Point3F v = vehicle->getRigid().angVelocity;
				F32 dot = mDot(zv, m);
				//Con::printf("%f / %f %f %f / %f %f %f", dot,
				//	m.x, m.y, m.z, v.x, v.y, v.z);
				mMove.yaw = dot / 50;
			}

			if(move)
				mMove.y = move->y;

		}
		else if(move)
		{
			Point3F v1, v2;
			this->getTransform().getColumn(0, &v1);
			this->getTransform().getColumn(1, &v2);
			Point3F pv = v1*move->x + v2*move->y;

			mount->getTransform().getColumn(0, &v1);
			mount->getTransform().getColumn(1, &v2);

			mMove.x = mDot(v1, pv);
			mMove.y = mDot(v2, pv);
		}
		mount->processTick(&mMove);
   }
#endif