Merge() public method

public Merge ( Rectangle rhs ) : Rectangle
rhs Rectangle
return Rectangle
Example #1
0
		public void HandleResponse( WorkQueue.Response res, WorkQueue srcq )
		{
			// Main thread
			var ddres = (DerivedDataResponse)res.Data;
			var ddreq = (DerivedDataRequest)res.Request.Data;

			// only deal with own requests
			if ( ddreq.Terrain != this )
			{
				return;
			}

			if ( ( ( ddreq.TypeMask & DERIVED_DATA_DELTAS ) == ddreq.TypeMask ) &&
				 ( ( ddres.RemainingTypeMask & DERIVED_DATA_DELTAS ) != DERIVED_DATA_DELTAS ) )
			{
				FinalizeHeightDeltas( ddres.DeltaUpdateRect, false );
			}
			if ( ( ( ddreq.TypeMask & DERIVED_DATA_NORMALS ) == ddreq.TypeMask ) &&
				 ( ( ddres.RemainingTypeMask & DERIVED_DATA_NORMALS ) != DERIVED_DATA_NORMALS ) )
			{
				FinalizeNormals( ddres.NormalUpdateRect, ddres.NormalMapBox );
				this.mCompositeMapDirtyRect.Merge( ddreq.DirtyRect );
			}
			if ( ( ( ddreq.TypeMask & DERIVED_DATA_LIGHTMAP ) == ddreq.TypeMask ) &&
				 ( ( ddres.RemainingTypeMask & DERIVED_DATA_LIGHTMAP ) != DERIVED_DATA_LIGHTMAP ) )
			{
				FinalizeLightMap( ddres.LightMapUpdateRect, ddres.LightMapPixelBox );
				this.mCompositeMapDirtyRect.Merge( ddreq.DirtyRect );
				this.mCompositeMapDirtyRectLightmapUpdate = true;
			}

			IsDerivedDataUpdateInProgress = false;

			// Re-trigger another request if there are still things to do, or if
			// we had a new request since this one
			var newRect = new Rectangle( 0, 0, 0, 0 );
			if ( ddres.RemainingTypeMask != 0 )
			{
				newRect.Merge( ddreq.DirtyRect );
			}

			if ( this.mDerivedUpdatePendingMask != 0 )
			{
				newRect.Merge( this.mDirtyDerivedDataRect );
				this.mDirtyDerivedDataRect.IsNull = true;
			}

			var newLightmapExtraRext = new Rectangle( 0, 0, 0, 0 );
			if ( ddres.RemainingTypeMask != 0 )
			{
				newLightmapExtraRext.Merge( ddreq.LightmapExtraDirtyRect );
			}
			if ( this.mDerivedUpdatePendingMask != 0 )
			{
				newLightmapExtraRext.Merge( this.mDirtyLightmapFromNeighboursRect );
				this.mDirtyLightmapFromNeighboursRect.IsNull = true;
			}
			var newMask = (byte)( ddres.RemainingTypeMask | this.mDerivedUpdatePendingMask );
			if ( newMask != 0 )
			{
				// trigger again
				UpdateDerivedDataImpl( newRect, newLightmapExtraRext, false, newMask );
			}
			else
			{
				// we've finished all the background processes
				// update the composite map if enabled
				if ( this.mCompositeMapRequired )
				{
					UpdateCompositeMap();
				}
			}
		}
Example #2
0
		public void WidenRectByVector( Vector3 vec, Rectangle inRect, Real minHeight, Real maxHeight, ref Rectangle outRect )
		{
			outRect = inRect;

			var p = new Plane();
			switch ( Alignment )
			{
				case Alignment.Align_X_Y:
					p.Redefine( Vector3.UnitZ, new Vector3( 0, 0, vec.z < 0.0f ? minHeight : maxHeight ) );
					break;

				case Alignment.Align_X_Z:
					p.Redefine( Vector3.UnitY, new Vector3( 0, vec.y < 0.0f ? minHeight : maxHeight, 0 ) );
					break;

				case Alignment.Align_Y_Z:
					p.Redefine( Vector3.UnitX, new Vector3( vec.x < 0.0f ? minHeight : maxHeight, 0, 0 ) );
					break;
			}
			var verticalVal = vec.Dot( p.Normal );

			if ( Utility.RealEqual( verticalVal, 0.0f ) )
			{
				return;
			}

			var corners = new Vector3[4];
			var startHeight = verticalVal < 0.0f ? maxHeight : minHeight;
			GetPoint( inRect.Left, inRect.Top, startHeight, ref corners[ 0 ] );
			GetPoint( inRect.Right - 1, inRect.Top, startHeight, ref corners[ 1 ] );
			GetPoint( inRect.Left, inRect.Bottom - 1, startHeight, ref corners[ 2 ] );
			GetPoint( inRect.Right - 1, inRect.Bottom - 1, startHeight, ref corners[ 3 ] );

			for ( int i = 0; i < 4; ++i )
			{
				var ray = new Ray( corners[ i ] + this.mPos, vec );
				var rayHit = ray.Intersects( p );
				if ( rayHit.Hit )
				{
					var pt = ray.GetPoint( rayHit.Distance );
					// convert back to terrain point
					var terrainHitPos = Vector3.Zero;
					GetTerrainPosition( pt, ref terrainHitPos );
					// build rectangle which has rounded down & rounded up values
					// remember right & bottom are exclusive
					var mergeRect = new Rectangle( (long)terrainHitPos.x*( this.mSize - 1 ), (long)terrainHitPos.y*( this.mSize - 1 ),
												   (long)( terrainHitPos.x*(float)( this.mSize - 1 ) + 0.5f ) + 1,
												   (long)( terrainHitPos.y*(float)( this.mSize - 1 ) + 0.5f ) + 1 );
					outRect.Merge( mergeRect );
				}
			}
		}
Example #3
0
		public PixelBox CalculateLightMap( Rectangle rect, Rectangle extraTargetRect, ref Rectangle outFinalRect )
		{
			// as well as calculating the lighting changes for the area that is
			// dirty, we also need to calculate the effect on casting shadow on
			// other areas. To do this, we project the dirt rect by the light direction
			// onto the minimum height

			var lightVec = TerrainGlobalOptions.LightMapDirection;
			var widenedRect = new Rectangle();
			WidenRectByVector( lightVec, rect, ref widenedRect );

			//merge in the extra area (e.g. from neighbours)
			widenedRect.Merge( extraTargetRect );

			// widenedRect now contains terrain point space version of the area we
			// need to calculate. However, we need to calculate in lightmap image space
			var terrainToLightmapScale = (float)this.mLightmapSizeActual/(float)this.mSize;
			widenedRect.Left = (long)( widenedRect.Left*terrainToLightmapScale );
			widenedRect.Right = (long)( widenedRect.Right*terrainToLightmapScale );
			widenedRect.Top = (long)( widenedRect.Top*terrainToLightmapScale );
			widenedRect.Bottom = (long)( widenedRect.Bottom*terrainToLightmapScale );

			//clamp
			widenedRect.Left = Utility.Max( 0L, widenedRect.Left );
			widenedRect.Top = Utility.Max( 0L, widenedRect.Top );
			widenedRect.Right = Utility.Min( (long)this.mLightmapSizeActual, widenedRect.Right );
			widenedRect.Bottom = Utility.Min( (long)this.mLightmapSizeActual, widenedRect.Bottom );

			outFinalRect = widenedRect;

			// allocate memory (L8)
			var pData = new byte[widenedRect.Width*widenedRect.Height];
			var pDataPtr = BufferBase.Wrap( pData );
			var pixbox = new PixelBox( (int)widenedRect.Width, (int)widenedRect.Height, 1, PixelFormat.L8, pDataPtr );

			var heightPad = ( MaxHeight - MinHeight )*1.0e-3f;

			for ( var y = widenedRect.Top; y < widenedRect.Bottom; ++y )
			{
				for ( var x = widenedRect.Left; x < widenedRect.Right; ++x )
				{
					var litVal = 1.0f;

					// convert to terrain space (not points, allow this to go between points)
					var Tx = (float)x/(float)( this.mLightmapSizeActual - 1 );
					var Ty = (float)y/(float)( this.mLightmapSizeActual - 1 );

					// get world space point
					// add a little height padding to stop shadowing self
					var wpos = Vector3.Zero;
					GetPosition( Tx, Ty, GetHeightAtTerrainPosition( Tx, Ty ) + heightPad, ref wpos );
					wpos += Position;
					// build ray, cast backwards along light direction
					var ray = new Ray( wpos, -lightVec );

					// Cascade into neighbours when casting, but don't travel further
					// than world size
					var rayHit = RayIntersects( ray, true, this.mWorldSize );

					if ( rayHit.Key )
					{
						litVal = 0.0f;
					}

					// encode as L8
					// invert the Y to deal with image space
					var storeX = x - widenedRect.Left;
					var storeY = widenedRect.Bottom - y - 1;

					using ( var wrap = pDataPtr + ( ( storeY*widenedRect.Width ) + storeX ) )
					{
						var pStore = (ITypePointer<byte>)wrap;
						pStore[ 0 ] = (byte)( litVal*255.0 );
					}
				}
			}
			pDataPtr.Dispose();
			return pixbox;
		}
Example #4
0
		public Rectangle CalculateHeightDeltas( Rectangle rect )
		{
			var clampedRect = new Rectangle( rect );

			clampedRect.Left = Utility.Max( 0L, clampedRect.Left );
			clampedRect.Top = Utility.Max( 0L, clampedRect.Top );
			clampedRect.Right = Utility.Min( (long)this.mSize, clampedRect.Right );
			clampedRect.Bottom = Utility.Min( (long)this.mSize, clampedRect.Bottom );

			var finalRect = new Rectangle( clampedRect );
			QuadTree.PreDeltaCalculation( clampedRect );

			// Iterate over target levels, 
			for ( var targetLevel = 1; targetLevel < NumLodLevels; ++targetLevel )
			{
				var sourceLevel = targetLevel - 1;
				var step = 1 << targetLevel;

				// need to widen the dirty rectangle since change will affect surrounding
				// vertices at lower LOD
				var widendRect = rect;
				widendRect.Left = Utility.Max( 0L, widendRect.Left - step );
				widendRect.Top = Utility.Max( 0L, widendRect.Top - step );
				widendRect.Right = Utility.Min( (long)this.mSize, widendRect.Right + step );
				widendRect.Bottom = Utility.Min( (long)this.mSize, widendRect.Bottom + step );

				// keep a merge of the widest
				finalRect = finalRect.Merge( widendRect );

				// now round the rectangle at this level so that it starts & ends on 
				// the step boundaries
				var lodRect = new Rectangle( widendRect );
				lodRect.Left -= lodRect.Left%step;
				lodRect.Top -= lodRect.Top%step;
				if ( lodRect.Right%step != 0 )
				{
					lodRect.Right += step - ( lodRect.Right%step );
				}
				if ( lodRect.Bottom%step != 0 )
				{
					lodRect.Bottom += step - ( lodRect.Bottom%step );
				}

				for ( var j = (int)lodRect.Top; j < lodRect.Bottom - step; j += step )
				{
					for ( var i = (int)lodRect.Left; i < lodRect.Right - step; i += step )
					{
						// Form planes relating to the lower detail tris to be produced
						// For even tri strip rows, they are this shape:
						// 2---3
						// | / |
						// 0---1
						// For odd tri strip rows, they are this shape:
						// 2---3
						// | \ |
						// 0---1
						var v0 = Vector3.Zero;
						var v1 = Vector3.Zero;
						var v2 = Vector3.Zero;
						var v3 = Vector3.Zero;

						GetPointAlign( i, j, Alignment.Align_X_Y, ref v0 );
						GetPointAlign( i + step, j, Alignment.Align_X_Y, ref v1 );
						GetPointAlign( i, j + step, Alignment.Align_X_Y, ref v2 );
						GetPointAlign( i + step, j + step, Alignment.Align_X_Y, ref v3 );

						var t1 = new Plane();
						var t2 = new Plane();
						var backwardTri = false;
						// Odd or even in terms of target level
						if ( ( j/step )%2 == 0 )
						{
							t1.Redefine( v0, v1, v3 );
							t2.Redefine( v0, v3, v2 );
						}
						else
						{
							t1.Redefine( v1, v3, v2 );
							t2.Redefine( v0, v1, v2 );
							backwardTri = true;
						}

						//include the bottommost row of vertices if this is the last row
						var yubound = ( j == ( this.mSize - step ) ? step : step - 1 );
						for ( var y = 0; y <= yubound; y++ )
						{
							// include the rightmost col of vertices if this is the last col
							var xubound = ( i == ( this.mSize - step ) ? step : step - 1 );
							for ( var x = 0; x <= xubound; x++ )
							{
								var fulldetailx = i + x;
								var fulldetaily = j + y;
								if ( fulldetailx%step == 0 && fulldetaily%step == 0 )
								{
									// Skip, this one is a vertex at this level
									continue;
								}
								var ypct = (Real)y/(Real)step;
								var xpct = (Real)x/(Real)step;

								//interpolated height
								var actualPos = Vector3.Zero;
								GetPointAlign( fulldetailx, fulldetaily, Alignment.Align_X_Y, ref actualPos );
								Real interp_h = 0;
								// Determine which tri we're on 
								if ( ( xpct > ypct && !backwardTri ) || ( xpct > ( 1 - ypct ) && backwardTri ) )
								{
									// Solve for x/z
									interp_h = ( -t1.Normal.x*actualPos.x - t1.Normal.y*actualPos.y - t1.D )/t1.Normal.z;
								}
								else
								{
									// Second tri
									interp_h = ( -t2.Normal.x*actualPos.x - t2.Normal.y*actualPos.y - t2.D )/t2.Normal.z;
								}

								var actual_h = actualPos.z;
								var delta = interp_h - actual_h;

								// max(delta) is the worst case scenario at this LOD
								// compared to the original heightmap
								if ( delta == float.NaN )
								{
								}
								// tell the quadtree about this 
								QuadTree.NotifyDelta( (ushort)fulldetailx, (ushort)fulldetaily, (ushort)sourceLevel, delta );


								// If this vertex is being removed at this LOD, 
								// then save the height difference since that's the move
								// it will need to make. Vertices to be removed at this LOD
								// are halfway between the steps, but exclude those that
								// would have been eliminated at earlier levels
								int halfStep = step/2;
								if ( ( ( fulldetailx%step ) == halfStep && ( fulldetaily%halfStep ) == 0 ) ||
									 ( ( fulldetaily%step ) == halfStep && ( fulldetailx%halfStep ) == 0 ) )
								{
#if !AXIOM_SAFE_ONLY
									unsafe
#endif
									{
										// Save height difference 
										var pDest = GetDeltaData( fulldetailx, fulldetaily ).ToFloatPointer();
										pDest[ 0 ] = delta;
									}
								}
							} //x
						} //y
					}
				} //j
			} //targetlevel

			QuadTree.PostDeltaCalculation( clampedRect );

			return finalRect;
		}