示例#1
0
void TerrCell::cullCells(  const SceneRenderState *state,
                           const Point3F &objLodPos,
                           Vector<TerrCell*> *outCells  )
{
   // If we have a VB and no children then just add 
   // ourselves to the results and return.
   if ( mVertexBuffer.isValid() && !mChildren[0]  )               
   {
      outCells->push_back( this );
      return;
   }

   const F32 screenError = mTerrain->getScreenError();
   const BitVector &zoneState = state->getCullingState().getZoneVisibilityFlags();

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

      // Test cell visibility for interior zones.
      
      const bool visibleInside = !cell->getZoneOverlap().empty() ? zoneState.testAny( cell->getZoneOverlap() ) : false;

      // Test cell visibility for outdoor zone, but only
      // if we need to.

      bool visibleOutside = false;
      if( !mIsInteriorOnly && !visibleInside )
      {         
         U32 outdoorZone = SceneZoneSpaceManager::RootZoneId;
         visibleOutside = !state->getCullingState().isCulled( cell->mOBB, &outdoorZone, 1 );
      }

      // Skip cell if neither visible indoors nor outdoors.

      if( !visibleInside && !visibleOutside )
         continue;

      // Lod based on screen error...
      // If far enough, just add this child cells vb ( skipping its children ).
      F32 dist = cell->getDistanceTo( objLodPos );
      F32 errorMeters = ( cell->mSize / smMinCellSize ) * mTerrain->getSquareSize();
      U32 errorPixels = mCeil( state->projectRadius( dist, errorMeters ) );

      if ( errorPixels < screenError )
      {
         if ( cell->mVertexBuffer.isValid() )
            outCells->push_back( cell );       
      }
      else      
         cell->cullCells( state, objLodPos, outCells );
   }
}
示例#2
0
	/**
	 * Expands the capacity of the array so that it automatically has
	 * enough space. It is 1.5x size growth
	 */
	void expand()
	{
		mAllocSize = mCeil(mMax(1, mAllocSize) * 1.5f);

		mArray = reinterpret_cast<T*>(realloc(mArray, mAllocSize * sizeof(T)));
		
		// we could potentially be allocating a LOT of memory. Check to make sure
		// the allocation was successful.
		if (mArray == nullptr)
		{
			// TODO: Implement some message box in here to say we are out of
			// memory.
			exit(-1);
		}
	}
示例#3
0
bool LightAnimData::AnimValue<COUNT>::animate(F32 time, F32 *output, bool multiply)
{
   F32 scaledTime, lerpFactor, valueRange, keyFrameLerp;
   U32 posFrom, posTo;
   S32 keyFrameFrom, keyFrameTo;
   F32 initialValue = *output;
   if (!multiply)
      initialValue = 1;

   bool wasAnimated = false;

   for ( U32 i=0; i < COUNT; i++ )
   {
      if ( mIsZero( timeScale[i] ) )
         continue;

      wasAnimated = true;

      scaledTime = mFmod( time, period[i] ) * timeScale[i];

	   posFrom = mFloor( scaledTime );
	   posTo = mCeil( scaledTime );

      keyFrameFrom = dToupper( keys[i][posFrom] ) - 65;
      keyFrameTo = dToupper( keys[i][posTo] ) - 65;
	   valueRange = ( value2[i] - value1[i] ) / 25.0f;

      if ( !smooth[i] )
         output[i] = (value1[i] + (keyFrameFrom * valueRange)) * initialValue;
      else
      {
         lerpFactor = scaledTime - posFrom;
   	   keyFrameLerp = ( keyFrameTo - keyFrameFrom ) * lerpFactor;

         output[i] = (value1[i] + ((keyFrameFrom + keyFrameLerp) * valueRange)) * initialValue;
      }
   }

   return wasAnimated;
}
示例#4
0
void DecalRoad::_generateEdges()
{      
   PROFILE_SCOPE( DecalRoad_generateEdges );

   //Con::warnf( "%s - generateEdges", isServerObject() ? "server" : "client" );

   if ( mNodes.size() > 0 )
   {
      // Set our object position to the first node.
      const Point3F &nodePt = mNodes.first().point;
      MatrixF mat( true );
      mat.setPosition( nodePt );
      Parent::setTransform( mat );

      // The server object has global bounds, which Parent::setTransform 
      // messes up so we must reset it.
      if ( isServerObject() )
      {
         mObjBox.minExtents.set(-1e10, -1e10, -1e10);
         mObjBox.maxExtents.set( 1e10,  1e10,  1e10);
      }
   }


   if ( mNodes.size() < 2 )
      return;

   // Ensure nodes are above the terrain height at their xy position
   for ( U32 i = 0; i < mNodes.size(); i++ )
   {
      _getTerrainHeight( mNodes[i].point );
   }

   // Now start generating edges...

   U32 nodeCount = mNodes.size();
   Point3F *positions = new Point3F[nodeCount];

   for ( U32 i = 0; i < nodeCount; i++ )
   {
      const RoadNode &node = mNodes[i];
      positions[i].set( node.point.x, node.point.y, node.width );
   }

   CatmullRom<Point3F> spline;
   spline.initialize( nodeCount, positions );
   delete [] positions;

   mEdges.clear();

   Point3F lastBreakVector(0,0,0);      
   RoadEdge slice;
   Point3F lastBreakNode;
   lastBreakNode = spline.evaluate(0.0f);

   for ( U32 i = 1; i < mNodes.size(); i++ )
   {
      F32 t1 = spline.getTime(i);
      F32 t0 = spline.getTime(i-1);

      F32 segLength = spline.arcLength( t0, t1 );

      U32 numSegments = mCeil( segLength / MIN_METERS_PER_SEGMENT );
      numSegments = getMax( numSegments, (U32)1 );
      F32 tstep = ( t1 - t0 ) / numSegments; 

      U32 startIdx = 0;
      U32 endIdx = ( i == nodeCount - 1 ) ? numSegments + 1 : numSegments;

      for ( U32 j = startIdx; j < endIdx; j++ )
      {
         F32 t = t0 + tstep * j;
         Point3F splineNode = spline.evaluate(t);
         F32 width = splineNode.z;
         _getTerrainHeight( splineNode );

         Point3F toNodeVec = splineNode - lastBreakNode;
         toNodeVec.normalizeSafe();

         if ( lastBreakVector.isZero() )
            lastBreakVector = toNodeVec;

         F32 angle = mRadToDeg( mAcos( mDot( toNodeVec, lastBreakVector ) ) );

         if ( j == startIdx || 
            ( j == endIdx - 1 && i == mNodes.size() - 1 ) ||
            angle > mBreakAngle )
         {
            // Push back a spline node
            //slice.p1.set( splineNode.x, splineNode.y, 0.0f );
            //_getTerrainHeight( slice.p1 );
            slice.p1 = splineNode;
            slice.uvec.set(0,0,1);
            slice.width = width;            
            slice.parentNodeIdx = i-1;
            mEdges.push_back( slice );         

            lastBreakVector = splineNode - lastBreakNode;
            lastBreakVector.normalizeSafe();

            lastBreakNode = splineNode;
         }          
      }
   }

   /*
   for ( U32 i = 1; i < nodeCount; i++ )
   {
      F32 t0 = spline.getTime( i-1 );
      F32 t1 = spline.getTime( i );

      F32 segLength = spline.arcLength( t0, t1 );

      U32 numSegments = mCeil( segLength / mBreakAngle );
      numSegments = getMax( numSegments, (U32)1 );
      F32 tstep = ( t1 - t0 ) / numSegments;

      AssertFatal( numSegments > 0, "DecalRoad::_generateEdges, got zero segments!" );   

      U32 startIdx = 0;
      U32 endIdx = ( i == nodeCount - 1 ) ? numSegments + 1 : numSegments;

      for ( U32 j = startIdx; j < endIdx; j++ )
      {
         F32 t = t0 + tstep * j;
         Point3F val = spline.evaluate(t);

         RoadEdge edge;         
         edge.p1.set( val.x, val.y, 0.0f );    
         _getTerrainHeight( val.x, val.y, edge.p1.z );    
         edge.uvec.set(0,0,1);
         edge.width = val.z;
         edge.parentNodeIdx = i-1;
         mEdges.push_back( edge );
      }   
   }
   */

   //
   // Calculate fvec and rvec for all edges
   //
   RoadEdge *edge = NULL;
   RoadEdge *nextEdge = NULL;

   for ( U32 i = 0; i < mEdges.size() - 1; i++ )
   {
      edge = &mEdges[i];
      nextEdge = &mEdges[i+1];

      edge->fvec = nextEdge->p1 - edge->p1;
      edge->fvec.normalize();

      edge->rvec = mCross( edge->fvec, edge->uvec );
      edge->rvec.normalize();
   }

   // Must do the last edge outside the loop
   RoadEdge *lastEdge = &mEdges[mEdges.size()-1];
   RoadEdge *prevEdge = &mEdges[mEdges.size()-2];
   lastEdge->fvec = prevEdge->fvec;
   lastEdge->rvec = prevEdge->rvec;


   //
   // Calculate p0/p2 for all edges
   //      
   for ( U32 i = 0; i < mEdges.size(); i++ )
   {
      RoadEdge *edge = &mEdges[i];
      edge->p0 = edge->p1 - edge->rvec * edge->width * 0.5f;
      edge->p2 = edge->p1 + edge->rvec * edge->width * 0.5f;
      _getTerrainHeight( edge->p0 );
      _getTerrainHeight( edge->p2 );
   }   
}
示例#5
0
void GroundPlane::createGeometry( const Frustum& frustum )
{
   PROFILE_SCOPE( GroundPlane_createGeometry );
   
   enum { MAX_WIDTH = 256, MAX_HEIGHT = 256 };
   
   // Project the frustum onto the XY grid.

   Point2F min;
   Point2F max;

   projectFrustum( frustum, mSquareSize, min, max );
   
   // Early out if the grid projection hasn't changed.

   if(   mVertexBuffer.isValid() && 
         min == mMin && 
         max == mMax )
      return;

   mMin = min;
   mMax = max;

   // Determine the grid extents and allocate the buffers.
   // Adjust square size permanently if with the given frustum,
   // we end up producing more than a certain limit of geometry.
   // This is to prevent this code from causing trouble with
   // long viewing distances.
   // This only affects the client object, of course, and thus
   // has no permanent effect.
   
   U32 width = mCeil( ( max.x - min.x ) / mSquareSize );
   if( width > MAX_WIDTH )
   {
      mSquareSize = mCeil( ( max.x - min.x ) / MAX_WIDTH );
      width = MAX_WIDTH;
   }
   else if( !width )
      width = 1;
   
   U32 height = mCeil( ( max.y - min.y ) / mSquareSize );
   if( height > MAX_HEIGHT )
   {
      mSquareSize = mCeil( ( max.y - min.y ) / MAX_HEIGHT );
      height = MAX_HEIGHT;
   }
   else if( !height )
      height = 1;

   const U32 numVertices   = ( width + 1 ) * ( height + 1 );
   const U32 numTriangles  = width * height * 2;

   // Only reallocate if the buffers are too small.
   if ( mVertexBuffer.isNull() || numVertices > mVertexBuffer->mNumVerts )
   {
#if defined(TORQUE_OS_XENON)
      mVertexBuffer.set( GFX, numVertices, GFXBufferTypeVolatile );
#else
      mVertexBuffer.set( GFX, numVertices, GFXBufferTypeDynamic );
#endif
   }
   if ( mPrimitiveBuffer.isNull() || numTriangles > mPrimitiveBuffer->mPrimitiveCount )
   {
#if defined(TORQUE_OS_XENON)
      mPrimitiveBuffer.set( GFX, numTriangles*3, numTriangles, GFXBufferTypeVolatile );
#else
      mPrimitiveBuffer.set( GFX, numTriangles*3, numTriangles, GFXBufferTypeDynamic );
#endif
   }

   // Generate the grid.

   generateGrid( width, height, mSquareSize, min, max, mVertexBuffer, mPrimitiveBuffer );

   // Set up GFX primitive.

   mPrimitive.type            = GFXTriangleList;
   mPrimitive.numPrimitives   = numTriangles;
   mPrimitive.numVertices     = numVertices;
}
示例#6
0
bool TerrainBlock::buildPolyList(AbstractPolyList* polyList, const Box3F &box, const SphereF&)
{
   if (box.maxExtents.z < -TerrainThickness || box.minExtents.z > fixedToFloat(gridMap[BlockShift]->maxHeight))
      return false;

   // Transform the bounding sphere into the object's coord space.  Note that this
   //  not really optimal.
   Box3F osBox = box;
   mWorldToObj.mul(osBox);
   AssertWarn(mObjScale == Point3F::One, "Error, handle the scale transform on the terrain");

   // Setup collision state data
   polyList->setTransform(&getTransform(), getScale());
   polyList->setObject(this);

   S32 xStart = (S32)mFloor( osBox.minExtents.x / mSquareSize );
   S32 xEnd   = (S32)mCeil ( osBox.maxExtents.x / mSquareSize );
   S32 yStart = (S32)mFloor( osBox.minExtents.y / mSquareSize );
   S32 yEnd   = (S32)mCeil ( osBox.maxExtents.y / mSquareSize );
   if (!mTile && xStart<0)
      xStart = 0;
   S32 xExt = xEnd - xStart;
   if (xExt > MaxExtent)
      xExt = MaxExtent;
   xEnd = xStart + xExt;

   mHeightMax = floatToFixed(osBox.maxExtents.z);
   mHeightMin = (osBox.minExtents.z < 0.0f)? 0.0f: floatToFixed(osBox.minExtents.z);

   // Index of shared points
   U32 bp[(MaxExtent + 1) * 2],*vb[2];
   vb[0] = &bp[0];
   vb[1] = &bp[xExt + 1];
   clrbuf(vb[1],xExt + 1);

   bool emitted = false;
   for (S32 y = yStart; y < yEnd; y++) 
   {
      S32 yi = y & BlockMask;

      swap(vb[0],vb[1]);
      clrbuf(vb[1],xExt + 1);
      //
      for (S32 x = xStart; x < xEnd; x++) 
      {
         S32 xi = x & BlockMask;
         GridSquare *gs = findSquare(0, Point2I(xi, yi));

         // If we disable repeat, then skip non-primary
         if(!mTile && (x!=xi || y!=yi))
            continue;

         // holes only in the primary terrain block
         if (((gs->flags & GridSquare::Empty) && x == xi && y == yi) || gs->minHeight > mHeightMax || gs->maxHeight < mHeightMin)
            continue;
         emitted = true;

         // Add the missing points
         U32 vi[5];
         for (int i = 0; i < 4 ; i++) 
         {
            S32 dx = i >> 1;
            S32 dy = dx ^ (i & 1);
            U32* vp = &vb[dy][x - xStart + dx];
            if (*vp == U32_MAX) 
            {
               Point3F pos;
               pos.x = (F32)((x + dx) * mSquareSize);
               pos.y = (F32)((y + dy) * mSquareSize);
               pos.z = fixedToFloat(getHeight(xi + dx, yi + dy));
               *vp = polyList->addPoint(pos);
            }
            vi[i] = *vp;
         }

         U32* vp = &vi[0];
         if (!(gs->flags & GridSquare::Split45))
            vi[4] = vi[0], vp++;

         BaseMatInstance* material = getMaterialInst( xi, yi );
         U32 surfaceKey = ((xi << 16) + yi) << 1;
         polyList->begin(material,surfaceKey);
         polyList->vertex(vp[0]);
         polyList->vertex(vp[1]);
         polyList->vertex(vp[2]);
         polyList->plane(vp[0],vp[1],vp[2]);
         polyList->end();
         polyList->begin(material,surfaceKey + 1);
         polyList->vertex(vp[0]);
         polyList->vertex(vp[2]);
         polyList->vertex(vp[3]);
         polyList->plane(vp[0],vp[2],vp[3]);
         polyList->end();
      }
   }
   return emitted;
}
示例#7
0
void TerrainBlock::buildConvex(const Box3F& box,Convex* convex)
{
   sTerrainConvexList.collectGarbage();

   //
   if (box.maxExtents.z < -TerrainThickness || box.minExtents.z > fixedToFloat(gridMap[BlockShift]->maxHeight))
      return;

   // Transform the bounding sphere into the object's coord space.  Note that this
   // not really optimal.
   Box3F osBox = box;
   mWorldToObj.mul(osBox);
   AssertWarn(mObjScale == Point3F(1, 1, 1), "Error, handle the scale transform on the terrain");

   S32 xStart = (S32)mFloor( osBox.minExtents.x / mSquareSize );
   S32 xEnd   = (S32)mCeil ( osBox.maxExtents.x / mSquareSize );
   S32 yStart = (S32)mFloor( osBox.minExtents.y / mSquareSize );
   S32 yEnd   = (S32)mCeil ( osBox.maxExtents.y / mSquareSize );
   S32 xExt = xEnd - xStart;
   if (xExt > MaxExtent)
      xExt = MaxExtent;

   mHeightMax = floatToFixed(osBox.maxExtents.z);
   mHeightMin = (osBox.minExtents.z < 0)? 0: floatToFixed(osBox.minExtents.z);

   for (S32 y = yStart; y < yEnd; y++) {
      S32 yi = y & BlockMask;

      //
      for (S32 x = xStart; x < xEnd; x++) {
         S32 xi = x & BlockMask;
         GridSquare *gs = findSquare(0, Point2I(xi, yi));

         // If we disable repeat, then skip non-primary
         if(!mTile && (x!=xi || y!=yi))
            continue;

         // holes only in the primary terrain block
         if (((gs->flags & GridSquare::Empty) && x == xi && y == yi) ||
             gs->minHeight > mHeightMax || gs->maxHeight < mHeightMin)
            continue;

         U32 sid = (x << 16) + (y & ((1 << 16) - 1));
         Convex* cc = 0;

         // See if the square already exists as part of the working set.
         CollisionWorkingList& wl = convex->getWorkingList();
         for (CollisionWorkingList* itr = wl.wLink.mNext; itr != &wl; itr = itr->wLink.mNext)
            if (itr->mConvex->getType() == TerrainConvexType &&
                static_cast<TerrainConvex*>(itr->mConvex)->squareId == sid) {
               cc = itr->mConvex;
               break;
            }
         if (cc)
            continue;

         // Create a new convex.
         TerrainConvex* cp = new TerrainConvex;
         sTerrainConvexList.registerObject(cp);
         convex->addToWorkingList(cp);
         cp->halfA = true;
         cp->square = 0;
         cp->mObject = this;
         cp->squareId = sid;
         cp->material = getMaterial(xi,yi)->index;//RDTODO
         cp->box.minExtents.set((F32)(x * mSquareSize), (F32)(y * mSquareSize), fixedToFloat(gs->minHeight));
         cp->box.maxExtents.x = cp->box.minExtents.x + mSquareSize;
         cp->box.maxExtents.y = cp->box.minExtents.y + mSquareSize;
         cp->box.maxExtents.z = fixedToFloat(gs->maxHeight);
         mObjToWorld.mul(cp->box);

         // Build points
         Point3F* pos = cp->point;
         for (int i = 0; i < 4 ; i++,pos++) {
            S32 dx = i >> 1;
            S32 dy = dx ^ (i & 1);
            pos->x = (F32)((x + dx) * mSquareSize);
            pos->y = (F32)((y + dy) * mSquareSize);
            pos->z = fixedToFloat(getHeight(xi + dx, yi + dy));
         }

         // Build normals, then split into two Convex objects if the
         // square is concave
         if ((cp->split45 = gs->flags & GridSquare::Split45) == true) {
            VectorF *vp = cp->point;
            mCross(vp[0] - vp[1],vp[2] - vp[1],&cp->normal[0]);
            cp->normal[0].normalize();
            mCross(vp[2] - vp[3],vp[0] - vp[3],&cp->normal[1]);
            cp->normal[1].normalize();
            if (mDot(vp[3] - vp[1],cp->normal[0]) > 0) {
               TerrainConvex* nc = new TerrainConvex(*cp);
               sTerrainConvexList.registerObject(nc);
               convex->addToWorkingList(nc);
               nc->halfA = false;
               nc->square = cp;
               cp->square = nc;
            }
         }
         else {
            VectorF *vp = cp->point;
            mCross(vp[3] - vp[0],vp[1] - vp[0],&cp->normal[0]);
            cp->normal[0].normalize();
            mCross(vp[1] - vp[2],vp[3] - vp[2],&cp->normal[1]);
            cp->normal[1].normalize();
            if (mDot(vp[2] - vp[0],cp->normal[0]) > 0) {
               TerrainConvex* nc = new TerrainConvex(*cp);
               sTerrainConvexList.registerObject(nc);
               convex->addToWorkingList(nc);
               nc->halfA = false;
               nc->square = cp;
               cp->square = nc;
            }
         }
      }
   }
}
示例#8
0
bool TerrainBlock::buildPolyList(PolyListContext, AbstractPolyList* polyList, const Box3F &box, const SphereF&)
{
	PROFILE_SCOPE( TerrainBlock_buildPolyList );

   // First check to see if the query misses the 
   // terrain elevation range.
   const Point3F &terrainPos = getPosition();
   if (  box.maxExtents.z - terrainPos.z < -TerrainThickness || 
         box.minExtents.z - terrainPos.z > fixedToFloat( mFile->getMaxHeight() ) )
      return false;

   // Transform the bounding sphere into the object's coord 
   // space.  Note that this is really optimal.
   Box3F osBox = box;
   mWorldToObj.mul(osBox);
   AssertWarn(mObjScale == Point3F::One, "Error, handle the scale transform on the terrain");

   // Setup collision state data
   polyList->setTransform(&getTransform(), getScale());
   polyList->setObject(this);

   S32 xStart = (S32)mFloor( osBox.minExtents.x / mSquareSize );
   S32 xEnd   = (S32)mCeil ( osBox.maxExtents.x / mSquareSize );
   S32 yStart = (S32)mFloor( osBox.minExtents.y / mSquareSize );
   S32 yEnd   = (S32)mCeil ( osBox.maxExtents.y / mSquareSize );
   if ( xStart < 0 )
      xStart = 0;
   S32 xExt = xEnd - xStart;
   if ( xExt > MaxExtent )
      xExt = MaxExtent;
   xEnd = xStart + xExt;

   U32 heightMax = floatToFixed(osBox.maxExtents.z);
   U32 heightMin = (osBox.minExtents.z < 0.0f)? 0.0f: floatToFixed(osBox.minExtents.z);

   // Index of shared points
   U32 bp[(MaxExtent + 1) * 2],*vb[2];
   vb[0] = &bp[0];
   vb[1] = &bp[xExt + 1];
   clrbuf(vb[1],xExt + 1);

   const U32 BlockMask = mFile->mSize - 1;

   bool emitted = false;
   for (S32 y = yStart; y < yEnd; y++) 
   {
      S32 yi = y & BlockMask;

      swap(vb[0],vb[1]);
      clrbuf(vb[1],xExt + 1);
      //
      for (S32 x = xStart; x < xEnd; x++) 
      {
         S32 xi = x & BlockMask;
         const TerrainSquare *sq = mFile->findSquare( 0, xi, yi );

         if ( x != xi || y != yi )
            continue;

         // holes only in the primary terrain block
         if (  ( ( sq->flags & TerrainSquare::Empty ) && x == xi && y == yi ) || 
               sq->minHeight > heightMax || 
               sq->maxHeight < heightMin )
            continue;

         emitted = true;

         // Add the missing points
         U32 vi[5];
         for (int i = 0; i < 4 ; i++) 
         {
            S32 dx = i >> 1;
            S32 dy = dx ^ (i & 1);
            U32* vp = &vb[dy][x - xStart + dx];
            if (*vp == U32_MAX) 
            {
               Point3F pos;
               pos.x = (F32)((x + dx) * mSquareSize);
               pos.y = (F32)((y + dy) * mSquareSize);
               pos.z = fixedToFloat( mFile->getHeight(xi + dx, yi + dy) );
               *vp = polyList->addPoint(pos);
            }
            vi[i] = *vp;
         }

         U32* vp = &vi[0];
         if ( !( sq->flags & TerrainSquare::Split45 ) )
            vi[4] = vi[0], vp++;

         BaseMatInstance *material = NULL; //getMaterialInst( xi, yi );
         U32 surfaceKey = ((xi << 16) + yi) << 1;
         polyList->begin(material,surfaceKey);
         polyList->vertex(vp[0]);
         polyList->vertex(vp[1]);
         polyList->vertex(vp[2]);
         polyList->plane(vp[0],vp[1],vp[2]);
         polyList->end();
         polyList->begin(material,surfaceKey + 1);
         polyList->vertex(vp[0]);
         polyList->vertex(vp[2]);
         polyList->vertex(vp[3]);
         polyList->plane(vp[0],vp[2],vp[3]);
         polyList->end();
      }
   }

   return emitted;
}
void TerrainFile::import(  const GBitmap &heightMap, 
                           F32 heightScale,
                           const Vector<U8> &layerMap, 
                           const Vector<String> &materials,
                           bool flipYAxis )
{
   AssertFatal( heightMap.getWidth() == heightMap.getHeight(), "TerrainFile::import - Height map is not square!" );
   AssertFatal( isPow2( heightMap.getWidth() ), "TerrainFile::import - Height map is not power of two!" );

   const U32 newSize = heightMap.getWidth();
   if ( newSize != mSize )
   {
      mHeightMap.setSize( newSize * newSize );
      mHeightMap.compact();
      mSize = newSize;
   }

   // Convert the height map to heights.
   U16 *oBits = mHeightMap.address();
   if ( heightMap.getFormat() == GFXFormatR5G6B5 )
   {
      const F32 toFixedPoint = ( 1.0f / (F32)U16_MAX ) * floatToFixed( heightScale );
      const U16 *iBits = (const U16*)heightMap.getBits();
      if ( flipYAxis )
      {
         for ( U32 i = 0; i < mSize * mSize; i++ )
         {
            U16 height = convertBEndianToHost( *iBits );
            *oBits = (U16)mCeil( (F32)height * toFixedPoint );
            ++oBits;
            ++iBits;
         }
      }
      else
      {
         for(S32 y = mSize - 1; y >= 0; y--) {
            for(U32 x = 0; x < mSize; x++) {
               U16 height = convertBEndianToHost( *iBits );
               mHeightMap[x + y * mSize] = (U16)mCeil( (F32)height * toFixedPoint );
               ++iBits;
            }
         }
      }
   }
   else
   {
      const F32 toFixedPoint = ( 1.0f / (F32)U8_MAX ) * floatToFixed( heightScale );
      const U8 *iBits = heightMap.getBits();
      if ( flipYAxis )
      {
         for ( U32 i = 0; i < mSize * mSize; i++ )
         {
            *oBits = (U16)mCeil( ((F32)*iBits) * toFixedPoint );
            ++oBits;
            iBits += heightMap.getBytesPerPixel();
         }
      }
      else
      {
         for(S32 y = mSize - 1; y >= 0; y--) {
            for(U32 x = 0; x < mSize; x++) {
               mHeightMap[x + y * mSize] = (U16)mCeil( ((F32)*iBits) * toFixedPoint );
               iBits += heightMap.getBytesPerPixel();
            }
         }
      }
   }

   // Copy over the layer map.
   AssertFatal( layerMap.size() == mHeightMap.size(), "TerrainFile::import - Layer map is the wrong size!" );
   mLayerMap = layerMap;
   mLayerMap.compact();

   // Resolve the materials.
   _resolveMaterials( materials );

   // Rebuild the collision grid map.
   _buildGridMap();
}
void TerrainFile::smooth( F32 factor, U32 steps, bool updateCollision )
{
   const U32 blockSize = mSize * mSize;

   // Grab some temp buffers for our smoothing results.
   Vector<F32> h1, h2;
   h1.setSize( blockSize );
   h2.setSize( blockSize );

   // Fill the first buffer with the current heights.   
   for ( U32 i=0; i < blockSize; i++ )
      h1[i] = (F32)mHeightMap[i];

   // factor of 0.0 = NO Smoothing
   // factor of 1.0 = MAX Smoothing
   const F32 matrixM = 1.0f - getMax(0.0f, getMin(1.0f, factor));
   const F32 matrixE = (1.0f-matrixM) * (1.0f/12.0f) * 2.0f;
   const F32 matrixC = matrixE * 0.5f;

   // Now loop for our interations.
   F32 *src = h1.address();
   F32 *dst = h2.address();
   for ( U32 s=0; s < steps; s++ )
   {
      for ( S32 y=0; y < mSize; y++ )
      {
         for ( S32 x=0; x < mSize; x++ )
         {
            F32 samples[9];

            S32 c = 0;
            for (S32 i = y-1; i < y+2; i++)
               for (S32 j = x-1; j < x+2; j++)
               {
                  if ( i < 0 || j < 0 || i >= mSize || j >= mSize )
                     samples[c++] = src[ x + ( y * mSize ) ];
                  else
                     samples[c++] = src[ j + ( i * mSize ) ];
               }

            //  0  1  2
            //  3 x,y 5
            //  6  7  8

            dst[ x + ( y * mSize ) ] =
               ((samples[0]+samples[2]+samples[6]+samples[8]) * matrixC) +
               ((samples[1]+samples[3]+samples[5]+samples[7]) * matrixE) +
               (samples[4] * matrixM);
         }
      }

      // Swap!
      F32 *tmp = dst;
      dst = src;
      src = tmp;
   }

   // Copy the results back to the height map.
   for ( U32 i=0; i < blockSize; i++ )
      mHeightMap[i] = (U16)mCeil( (F32)src[i] );

   if ( updateCollision )
      _buildGridMap();
}
示例#11
0
void GFXUtil::DistanceField::makeDistanceField( const U8 * sourceData, S32 sourceSizeX, S32 sourceSizeY, U8 * targetData, S32 targetSizeX, S32 targetSizeY, F32 radius )
{
   static Vector<DistanceFieldSearchSpaceStruct> searchSpace;

   S32 targetToSourceScalarX = sourceSizeX / targetSizeX;
   S32 targetToSourceScalarY = sourceSizeY / targetSizeY;
   S32 targetToSourcePixOffsetX = targetToSourceScalarX / 2;
   S32 targetToSourcePixOffsetY = targetToSourceScalarY / 2;

   F32 radius2 = radius * 2.f;

   {
      S32 intRange = mCeil(radius);
      for(S32 spaceY = -intRange; spaceY < intRange; spaceY++)
      {
         for(S32 spaceX = -intRange; spaceX < intRange; spaceX++)
         {
            if(spaceX == 0 && spaceY == 0)
               continue;

            F32 distance = Point2F(spaceX,spaceY).len();
            if(distance <= radius)
            {
               searchSpace.increment();
               searchSpace.last().distance = distance;
               searchSpace.last().xOffset = spaceX;
               searchSpace.last().yOffset = spaceY;
            }
         }
      }
   }
   dQsort(searchSpace.address(), searchSpace.size(), sizeof(DistanceFieldSearchSpaceStruct), cmpSortDistanceFieldSearchSpaceStruct);

   for(S32 y = 0; y < targetSizeY; y++)
   {
      for(S32 x = 0; x < targetSizeX; x++)
      {
         S32 sourceX = x * targetToSourceScalarX + targetToSourcePixOffsetX;
         S32 sourceY = y * targetToSourceScalarY + targetToSourcePixOffsetY;

         bool thisPixelEmpty = sourceData[sourceY * sourceSizeX + sourceX] < 127;

         F32 closestDist = F32_MAX;

         for(DistanceFieldSearchSpaceStruct * seachSpaceStructPtr = searchSpace.begin(); seachSpaceStructPtr <= searchSpace.end(); seachSpaceStructPtr++)
         {
            DistanceFieldSearchSpaceStruct & searchSpaceStruct = *seachSpaceStructPtr;
            S32 cx = sourceX + searchSpaceStruct.xOffset;
            if(cx < 0 || cx >= sourceSizeX)
               continue;

            S32 cy = sourceY + searchSpaceStruct.yOffset;
            if(cy < 0 || cy >= sourceSizeY)
               continue;

            if((sourceData[cy * sourceSizeX + cx] < 127) != thisPixelEmpty)
            {
               closestDist = searchSpaceStruct.distance;
               break;
            }
         }

         F32 diff = thisPixelEmpty ? getMax(-0.5f,-(closestDist / radius2)) : getMin(0.5f,closestDist / radius2);
         F32 targetValue = 0.5f + diff;

         *targetData = targetValue * 255;
         targetData++;
      }
   }

   searchSpace.clear();
}
示例#12
0
void SFXEmitter::_render3DVisualFeedback()
{
   GFXTransformSaver saver;
   
   GFX->multWorld( getRenderTransform() );
   
   GFXStateBlockDesc desc;
   desc.setZReadWrite( true, false );
   desc.setBlend( true );
   desc.setCullMode( GFXCullNone );

   if( mRenderSB == NULL )
      mRenderSB = GFX->createStateBlock( desc );
   
   GFX->setStateBlock( mRenderSB );
   
   // Render the max range sphere.
   
   if( smRenderColorRangeSphere.alpha > 0 )
      GFX->getDrawUtil()->drawSphere( desc, mDescription.mMaxDistance, Point3F( 0.f, 0.f, 0.f ), smRenderColorRangeSphere );
   
   //TODO: some point size support in GFX would be nice

   // Prepare primitive list.  Make sure we stay within limits.
   
   F32 radialIncrements = smRenderRadialIncrements;
   F32 sweepIncrements = smRenderSweepIncrements;
   F32 pointDistance = smRenderPointDistance;
   
   F32 numPoints;
   while( 1 )
   {
      numPoints = mCeil( 360.f / radialIncrements ) *
                  mCeil( 360.f / sweepIncrements ) *
                  ( mDescription.mMaxDistance / pointDistance );
                  
      if( numPoints < 65536 )
         break;
         
      radialIncrements *= 1.1f;
      sweepIncrements *= 1.1f;
      pointDistance *= 1.5;
   }
                           
   PrimBuild::begin( GFXPointList, numPoints );

   // Render inner cone.
   
   _renderCone(
      radialIncrements,
      sweepIncrements,
      pointDistance,
      mDescription.mConeInsideAngle, 0.f,
      mDescription.mVolume, mDescription.mVolume,
      smRenderColorInnerCone );

   // Outer Cone and Outside volume only get rendered if mConeOutsideVolume > 0
   
   if( mDescription.mConeOutsideVolume > 0.f )
   {
      const F32 outsideVolume = mDescription.mVolume * mDescription.mConeOutsideVolume;
      
      // Render outer cone.
      
      _renderCone(
         radialIncrements,
         sweepIncrements,
         pointDistance,
         mDescription.mConeOutsideAngle, mDescription.mConeInsideAngle,
         outsideVolume, mDescription.mVolume,
         smRenderColorOuterCone );
      
      // Render outside volume.
      
      _renderCone(
         radialIncrements,
         sweepIncrements,
         pointDistance,
         360.f, mDescription.mConeOutsideAngle,
         outsideVolume, outsideVolume,
         smRenderColorOutsideVolume );
   }
   
   // Commit primitive list.
   
   PrimBuild::end();
}
示例#13
0
   bool NavMesh::generateMesh()
   {
      // Parse objects from level into RC-compatible format
      NavModelData data = NavMeshLoader::mergeModels(
         NavMeshLoader::parseTerrainData(getWorldBox(), 0),
         NavMeshLoader::parseStaticObjects(getWorldBox()),
         true);

      // Check for no geometry
      if(!data.getVertCount())
         return false;

      // Free intermediate and final results
      freeIntermediates(true);

      // Create mInPolys if we don't have one already
      if(!mInPolys && mSaveIntermediates)
         mInPolys = new ConcretePolyList();

      // Reconstruct input geometry from out data
      if(mSaveIntermediates)
         RCtoPolyList(&data, mInPolys);

      // Recast initialisation data
      rcContext ctx(false);
      rcConfig cfg;

      dMemset(&cfg, 0, sizeof(cfg));
      cfg.cs = mCellSize;
      cfg.ch = mCellHeight;
      rcCalcBounds(data.verts, data.getVertCount(), cfg.bmin, cfg.bmax);
      rcCalcGridSize(cfg.bmin, cfg.bmax, cfg.cs, &cfg.width, &cfg.height);
      cfg.walkableHeight = mCeil(mWalkableHeight / mCellHeight);
      cfg.walkableClimb = mCeil(mWalkableClimb / mCellHeight);
      cfg.walkableRadius = mCeil(mWalkableRadius / mCellSize);
      cfg.walkableSlopeAngle = mWalkableSlope;
      cfg.borderSize = mBorderSize;
      cfg.detailSampleDist = mDetailSampleDist;
      cfg.detailSampleMaxError = mDetailSampleMaxError;
      cfg.maxEdgeLen = mMaxEdgeLen;
      cfg.maxSimplificationError = mMaxSimplificationError;
      cfg.maxVertsPerPoly = 3;
      cfg.minRegionArea = mMinRegionArea;
      cfg.mergeRegionArea = mMergeRegionArea;
      cfg.tileSize = mTileSize;

      if(!createPolyMesh(cfg, data, &ctx))
         return false;

      //Detour initialisation data
      dtNavMeshCreateParams params;
      dMemset(&params, 0, sizeof(params));

      params.walkableHeight = cfg.walkableHeight;
      params.walkableRadius = cfg.walkableRadius;
      params.walkableClimb = cfg.walkableClimb;
      params.tileX = 0;
      params.tileY = 0;
      params.tileLayer = 0;
      rcVcopy(params.bmax, cfg.bmax);
      rcVcopy(params.bmin, cfg.bmin);
      params.buildBvTree = true;
      params.ch = cfg.ch;
      params.cs = cfg.cs;

      params.verts = pm->verts;
      params.vertCount = pm->nverts;
      params.polys = pm->polys;
      params.polyAreas = pm->areas;
      params.polyFlags = pm->flags;
      params.polyCount = pm->npolys;
      params.nvp = pm->nvp;

      params.detailMeshes = pmd->meshes;
      params.detailVerts = pmd->verts;
      params.detailVertsCount = pmd->nverts;
      params.detailTris = pmd->tris;
      params.detailTriCount = pmd->ntris;

      if(!createNavMesh(params))
         return false;

      return true;
   }