示例#1
0
void ClipMap::calculateModuloDeltaBounds(const RectI &oldData, const RectI &newData, 
                                              RectI *outRects, S32 *outRectCount)
{
   // Sanity checking.
   /*AssertFatal(oldData.point.x >= 0 && oldData.point.y >= 0 && oldData.isValidRect(),
      "ClipMap::calculateModuloDeltaBounds - negative oldData origin or bad rect!");

   AssertFatal(newData.point.x >= 0 && newData.point.y >= 0 && newData.isValidRect(),
      "ClipMap::calculateModuloDeltaBounds - negative newData origin or bad rect!");*/

   AssertFatal(newData.extent == oldData.extent, 
      "ClipMap::calculateModuloDeltaBounts - mismatching extents, can only work with matching extents!");

   // Easiest case - if they're the same then do nothing.
   if(oldData.point == newData.point)
   {
      *outRectCount = 0;
      return;
   }

   // Easy case - if there's no overlap then it's all new!
   if(!oldData.overlaps(newData))
   {
      // Clip out to return buffer, and we're done.
      clipAgainstGrid(mClipMapSize, newData, outRectCount, outRects);
      return;
   }

   // Calculate some useful values for both X and Y. Delta is used a lot
   // in determining bounds, and the boundary values are important for
   // determining where to start copying new data in.
   const S32 xDelta = newData.point.x - oldData.point.x;
   const S32 yDelta = newData.point.y - oldData.point.y;

   const S32 xBoundary = (oldData.point.x + oldData.extent.x) % mClipMapSize;
   const S32 yBoundary = (oldData.point.y + oldData.extent.y) % mClipMapSize;

   AssertFatal(xBoundary % mClipMapSize == oldData.point.x % mClipMapSize, 
      "ClipMap::calculateModuleDeltaBounds - we assume that left and "
      "right of the dataset are identical (ie, it's periodical on size of clipmap!) (x)");

   AssertFatal(yBoundary % mClipMapSize == oldData.point.y % mClipMapSize, 
      "ClipMap::calculateModuleDeltaBounds - we assume that left and "
      "right of the dataset are identical (ie, it's periodical on size of clipmap!) (y)");

   // Now, let's build up our rects. We have one rect if we are moving
   // on the X or Y axis, two if both. We dealt with the no-move case
   // previously.
   if(xDelta == 0)
   {
      // Moving on Y! So generate and store clipped results.
      RectI yRect;

      if(yDelta < 0)
      {
         // We need to generate the box from right of old to right of new.
         yRect.point = newData.point;
         yRect.extent.x = mClipMapSize;
         yRect.extent.y = -yDelta;
      }
      else
      {
         // We need to generate the box from left of old to left of new.
         yRect.point.x = newData.point.x; // Doesn't matter which rect we get this from.
         yRect.point.y = (oldData.point.y + oldData.extent.y);
         yRect.extent.x = mClipMapSize;
         yRect.extent.y = yDelta;
      }

      // Clip out to return buffer, and we're done.
      clipAgainstGrid(mClipMapSize, yRect, outRectCount, outRects);

      return;
   }
   else if(yDelta == 0)
   {
      // Moving on X! So generate and store clipped results.
      RectI xRect;

      if(xDelta < 0)
      {
         // We need to generate the box from right of old to right of new.
         xRect.point = newData.point;
         xRect.extent.x = -xDelta;
         xRect.extent.y = mClipMapSize;
      }
      else
      {
         // We need to generate the box from left of old to left of new.
         xRect.point.x = (oldData.point.x + oldData.extent.x);
         xRect.point.y = newData.point.y; // Doesn't matter which rect we get this from.
         xRect.extent.x = xDelta;
         xRect.extent.y = mClipMapSize;
      }

      // Clip out to return buffer, and we're done.
      clipAgainstGrid(mClipMapSize, xRect, outRectCount, outRects);

      return;
   }
   else
   {
      // Both! We have an L shape. So let's do the bulk of it in one rect,
      // and the remainder in the other. We'll choose X as the dominant axis.
      //
      // a-----b---------c   going from e to a.
      // |     |         |
      // |     |         |
      // d-----e---------f   So the dominant rect is abgh and the passive
      // |     |         |   rect is bcef. Obviously depending on delta we
      // |     |         |   have to switch things around a bit.
      // |     |         |          y+ ^
      // |     |         |             |  
      // g-----h---------i   x+->      |

      RectI xRect, yRect;

      if(xDelta < 0)
      {
         // Case in the diagram.
         xRect.point = newData.point;
         xRect.extent.x = -xDelta;
         xRect.extent.y = mClipMapSize;

         // Set up what of yRect we know, too.
         yRect.point.x = xRect.point.x + xRect.extent.x;
         yRect.extent.x = mClipMapSize - mAbs(xDelta); 
      }
      else
      {
         // Opposite of case in diagram!
         xRect.point.x = oldData.point.x + oldData.extent.x;
         xRect.point.y = newData.point.y;
         xRect.extent.x = xDelta;
         xRect.extent.y = mClipMapSize;

         // Set up what of yRect we know,  too.
         yRect.point.x = (xRect.point.x + xRect.extent.x )- mClipMapSize;
         yRect.extent.x = mClipMapSize - xRect.extent.x;
      }

      if(yDelta < 0)
      {
         // Case in the diagram.
         yRect.point.y = newData.point.y;
         yRect.extent.y = -yDelta;
      }
      else
      {
         // Opposite of case in diagram!
         yRect.point.y = oldData.point.y + oldData.extent.y;
         yRect.extent.y = yDelta;
      }

      // Make sure we don't overlap.
      AssertFatal(!yRect.overlaps(xRect), 
         "ClipMap::calculateModuloDeltaBounds - have overlap in result rects!");

      // Ok, now run them through the clipper.
      S32 firstCount;
      clipAgainstGrid(mClipMapSize, xRect, &firstCount, outRects);
      clipAgainstGrid(mClipMapSize, yRect, outRectCount, outRects + firstCount);
      *outRectCount += firstCount;

      // All done!
      return;
   }
}
示例#2
0
void TerrCell::updateGrid( const RectI &gridRect, bool opacityOnly )
{
   PROFILE_SCOPE( TerrCell_UpdateGrid );

   // If we have a VB... then update it.
   if ( mVertexBuffer.isValid() && !opacityOnly )            
      _updateVertexBuffer();

   // Update our PB, if any
   _updatePrimitiveBuffer();

   // If we don't have children... then we're
   // a leaf at the bottom of the cell quadtree
   // and we should just update our bounds.
   if ( !mChildren[0] )
   {
      if ( !opacityOnly )
         _updateBounds(); 

      _updateMaterials();
      return;
   }

   // Otherwise, we must call updateGrid on our children
   // and then update our bounds/materials AFTER to contain them.

   mMaterials = 0;

   for ( U32 i = 0; i < 4; i++ )
   {
      TerrCell *cell = mChildren[i];

      // The overlap test doesn't hit shared edges
      // so grow it a bit when we create it.
      const RectI cellRect( cell->mPoint.x - 1,
                            cell->mPoint.y - 1,
                            cell->mSize + 2, 
                            cell->mSize + 2 );

      // We do an overlap and containment test as it 
      // properly handles zero sized rects.
      if (  cellRect.contains( gridRect ) ||
            cellRect.overlaps( gridRect ) )
         cell->updateGrid( gridRect, opacityOnly );

      // Update the bounds from our children.
      if ( !opacityOnly )
      {
         if ( i == 0 )
            mBounds = mChildren[i]->getBounds();
         else
            mBounds.intersect( mChildren[i]->getBounds() );

         mRadius = mBounds.len() * 0.5f;
      }

      // Update the material flags.
      mMaterials |= mChildren[i]->getMaterials();
   }

   if ( mMaterial )
      mMaterial->init( mTerrain, mMaterials );
}