示例#1
0
		public Rectangle Intersect( Rectangle rhs )
		{
			return Intersect( this, rhs );
		}
示例#2
0
		internal static Rectangle Intersect( Rectangle lhs, Rectangle rhs )
		{
			Rectangle r;

			r._left = lhs._left > rhs._left ? lhs._left : rhs._left;
			r._top = lhs._top > rhs._top ? lhs._top : rhs._top;
			r._right = lhs._right < rhs._right ? lhs._right : rhs._right;
			r._bottom = lhs._bottom < rhs._bottom ? lhs._bottom : rhs._bottom;

			return r;
		}
		public void PreDeltaCalculation( Rectangle rect )
		{
			if ( rect.Left <= this.mBoundaryX || rect.Right > this.mOffsetX || rect.Top <= this.mBoundaryY ||
			     rect.Bottom > this.mOffsetY )
			{
				// relevant to this node (overlaps)

				// if the rect covers the whole node, reset the max height
				// this means that if you recalculate the deltas progressively, end up keeping
				// a max height that's no longer the case (ie more conservative lod), 
				// but that's the price for not recaculating the whole node. If a 
				// complete recalculation is required, just dirty the entire node. (or terrain)

				// Note we use the 'calc' field here to avoid interfering with any
				// ongoing LOD calculations (this can be in the background)

				if ( rect.Left <= this.mOffsetX && rect.Right > this.mBoundaryX && rect.Top <= this.mOffsetY &&
				     rect.Bottom > this.mBoundaryY )
				{
					for ( int i = 0; i < this.mLodLevels.Count; i++ )
					{
						LodLevel tmp = this.mLodLevels[ i ];
						tmp.CalcMaxHeightDelta = 0.0f;
					}
				}

				//pass on to children
				if ( !IsLeaf )
				{
					for ( int i = 0; i < 4; i++ )
					{
						this.mChildren[ i ].PreDeltaCalculation( rect );
					}
				}
			}
		}
		public void FinaliseDeltaValues( Rectangle rect )
		{
			if ( rect.Left <= this.mBoundaryX || rect.Right > this.mOffsetX || rect.Top <= this.mBoundaryY ||
			     rect.Bottom > this.mOffsetY )
			{
				// relevant to this node (overlaps)

				// Children
				if ( !IsLeaf )
				{
					for ( int i = 0; i < 4; i++ )
					{
						TerrainQuadTreeNode child = this.mChildren[ i ];
						child.FinaliseDeltaValues( rect );
					}
				}

				// self
				LodLevel[] lvls = this.mLodLevels.ToArray();
				for ( int i = 0; i < lvls.Length; i++ )
				{
					LodLevel tmp = lvls[ i ];
					// copy from 'calc' area to runtime value
					tmp.MaxHeightDelta = tmp.CalcMaxHeightDelta;
					// also trash stored cfactor
					tmp.LastCFactor = 0;
				}
			}
		}
		public bool RectIntersectsNode( Rectangle rect )
		{
			return ( rect.Right >= this.mOffsetX && rect.Left <= this.mBoundaryX && rect.Bottom >= this.mOffsetY &&
			         rect.Top <= this.mBoundaryY );
		}
		protected void CreateCpuVertexData()
		{
			if ( this.mVertexDataRecord != null )
			{
				DestroyCpuVertexData();

				// create vertex structure, not using GPU for now (these are CPU structures)
				var dcl = new VertexDeclaration();
				var bufbind = new VertexBufferBinding();

				this.mVertexDataRecord.CpuVertexData = new VertexData( dcl, bufbind );

				// Vertex declaration
				// TODO: consider vertex compression
				int offset = 0;
				// POSITION 
				// float3(x, y, z)
				offset += dcl.AddElement( POSITION_BUFFER, offset, VertexElementType.Float3, VertexElementSemantic.Position ).Size;
				// UV0
				// float2(u, v)
				// TODO - only include this if needing fixed-function
				offset +=
					dcl.AddElement( POSITION_BUFFER, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 0 ).Size;
				// UV1 delta information
				// float2(delta, deltaLODthreshold)
				offset = 0;
				offset += dcl.AddElement( DELTA_BUFFER, offset, VertexElementType.Float2, VertexElementSemantic.TexCoords, 1 ).Size;

				// Calculate number of vertices
				// Base geometry size * size
				var baseNumVerts = (int)Utility.Sqr( this.mVertexDataRecord.Size );
				var numVerts = baseNumVerts;
				// Now add space for skirts
				// Skirts will be rendered as copies of the edge vertices translated downwards
				// Some people use one big fan with only 3 vertices at the bottom, 
				// but this requires creating them much bigger that necessary, meaning
				// more unnecessary overdraw, so we'll use more vertices 
				// You need 2^levels + 1 rows of full resolution (max 129) vertex copies, plus
				// the same number of columns. There are common vertices at intersections
				var levels = this.mVertexDataRecord.TreeLevels;
				this.mVertexDataRecord.NumSkirtRowsCols = (ushort)( System.Math.Pow( 2, levels ) + 1 );
				this.mVertexDataRecord.SkirtRowColSkip =
					(ushort)( ( this.mVertexDataRecord.Size - 1 )/( this.mVertexDataRecord.NumSkirtRowsCols - 1 ) );
				numVerts += this.mVertexDataRecord.Size*this.mVertexDataRecord.NumSkirtRowsCols;
				numVerts += this.mVertexDataRecord.Size*this.mVertexDataRecord.NumSkirtRowsCols;

				//manually create CPU-side buffer
				var posBuf = HardwareBufferManager.Instance.CreateVertexBuffer( dcl.Clone( POSITION_BUFFER ), numVerts,
				                                                                BufferUsage.StaticWriteOnly, false );
				var deltabuf = HardwareBufferManager.Instance.CreateVertexBuffer( dcl.Clone( DELTA_BUFFER ), numVerts,
				                                                                  BufferUsage.StaticWriteOnly, false );

				this.mVertexDataRecord.CpuVertexData.vertexStart = 0;
				this.mVertexDataRecord.CpuVertexData.vertexCount = numVerts;

				var updateRect = new Rectangle( this.mOffsetX, this.mOffsetY, this.mBoundaryX, this.mBoundaryY );
				UpdateVertexBuffer( posBuf, deltabuf, updateRect );
				this.mVertexDataRecord.IsGpuVertexDataDirty = true;
				bufbind.SetBinding( POSITION_BUFFER, posBuf );
				bufbind.SetBinding( DELTA_BUFFER, deltabuf );
			}
		}
示例#7
0
		public void NeighbourModified( NeighbourIndex index, Rectangle edgerect, Rectangle shadowrect )
		{
			// We can safely assume that we would not have been contacted if it wasn't 
			// important
			var neighbour = GetNeighbour( index );
			if ( neighbour == null )
			{
				return; // bogus request
			}

			var updateGeom = false;
			byte updateDerived = 0;

			if ( !edgerect.IsNull )
			{
				// update edges; match heights first, then recalculate normals
				// reduce to just single line / corner
				var heightMatchRect = new Rectangle();
				GetEdgeRect( index, 1, ref heightMatchRect );
				heightMatchRect = heightMatchRect.Intersect( edgerect );

				for ( var y = heightMatchRect.Top; y < heightMatchRect.Bottom; ++y )
				{
					for ( var x = heightMatchRect.Left; x < heightMatchRect.Right; ++x )
					{
						long nx = 0, ny = 0;
						GetNeighbourPoint( index, x, y, ref nx, ref ny );
						var neighbourHeight = neighbour.GetHeightAtPoint( nx, ny );
						if ( !Utility.RealEqual( neighbourHeight, GetHeightAtPoint( x, y ), 1e-3f ) )
						{
							SetHeightAtPoint( x, y, neighbourHeight );
							if ( !updateGeom )
							{
								updateGeom = true;
								updateDerived |= DERIVED_DATA_ALL;
							}
						}
					}
				}
				// if we didn't need to update heights, we still need to update normals
				// because this was called only if neighbor changed
				if ( !updateGeom )
				{
					// ideally we would deal with normal dirty rect separately (as we do with
					// lightmaps) because a dirty geom rectangle will actually grow by one 
					// element in each direction for normals recalculation. However for
					// the sake of one row/column it's really not worth it.
					this.mDirtyDerivedDataRect.Merge( edgerect );
					updateDerived |= DERIVED_DATA_NORMALS;
				}
			}

			if ( !shadowrect.IsNull )
			{
				// update shadows
				// here we need to widen the rect passed in based on the min/max height 
				// of the *neighbour*
				var lightVec = TerrainGlobalOptions.LightMapDirection;
				var widenedRect = new Rectangle();
				WidenRectByVector( lightVec, shadowrect, neighbour.MinHeight, neighbour.MaxHeight, ref widenedRect );

				// set the special-case lightmap dirty rectangle
				this.mDirtyLightmapFromNeighboursRect.Merge( widenedRect );
				updateDerived |= DERIVED_DATA_LIGHTMAP;
			}

			if ( updateGeom )
			{
				UpdateGeometry();
			}
			if ( updateDerived != 0 )
			{
				UpdateDerivedData( false, updateDerived );
			}
		}
		public void ResetBounds( Rectangle rect )
		{
			if ( RectContainsNode( rect ) )
			{
				this.mAABB.IsNull = true;
				this.mBoundingRadius = 0;

				if ( !IsLeaf )
				{
					for ( int i = 0; i < 4; ++i )
					{
						this.mChildren[ i ].ResetBounds( rect );
					}
				}
			}
		}
示例#9
0
		public void SetNeighbour( NeighbourIndex index, Terrain neighbour, bool recalculate, bool notifyOther )
#endif
		{
			if ( this.mNeighbours[ (int)index ] != neighbour )
			{
				System.Diagnostics.Debug.Assert( neighbour != this, "Can't set self as own neighbour!" );

				// detach existing
				if ( this.mNeighbours[ (int)index ] != null && notifyOther )
				{
					this.mNeighbours[ (int)index ].SetNeighbour( GetOppositeNeighbour( index ), null, false, false );
				}

				this.mNeighbours[ (int)index ] = neighbour;
				if ( neighbour != null && notifyOther )
				{
					this.mNeighbours[ (int)index ].SetNeighbour( GetOppositeNeighbour( index ), this, recalculate, false );
				}

				if ( recalculate )
				{
					//recalculate, pass OUR edge rect
					var edgerect = new Rectangle();
					GetEdgeRect( index, 2, ref edgerect );
					NeighbourModified( index, edgerect, edgerect );
				}
			}
		}
示例#10
0
		public void NotifyNeighbours()
		{
			// There are 3 things that can need updating:
			// Height at edge - match to neighbour (first one to update 'loses' to other since read-only)
			// Normal at edge - use heights from across boundary too
			// Shadows across edge
			// The extent to which these can affect the current tile vary:
			// Height at edge - only affected by a change at the adjoining edge / corner
			// Normal at edge - only affected by a change to the 2 rows adjoining the edge / corner
			// Shadows across edge - possible effect extends based on the projection of the
			// neighbour AABB along the light direction (worst case scenario)
			if ( !this.mDirtyGeometryRectForNeighbours.IsNull )
			{
				var dirtyRectForNeighbours = new Rectangle( this.mDirtyGeometryRectForNeighbours );
				this.mDirtyGeometryRectForNeighbours.IsNull = true;
				// calculate light update rectangle
				var lightVec = TerrainGlobalOptions.LightMapDirection;
				var lightmapRect = new Rectangle();
				WidenRectByVector( lightVec, dirtyRectForNeighbours, MinHeight, MaxHeight, ref lightmapRect );

				for ( var i = 0; i < (int)NeighbourIndex.Count; ++i )
				{
					var ni = (NeighbourIndex)( i );
					var neighbour = GetNeighbour( ni );
					if ( neighbour == null )
					{
						continue;
					}

					// Intersect the incoming rectangles with the edge regions related to this neighbour
					var edgeRect = new Rectangle();
					GetEdgeRect( ni, 2, ref edgeRect );
					var heightEdgeRect = edgeRect.Intersect( dirtyRectForNeighbours );
					var lightmapEdgeRect = edgeRect.Intersect( lightmapRect );

					if ( !heightEdgeRect.IsNull || !lightmapRect.IsNull )
					{
						// ok, we have something valid to pass on
						var neighbourHeightEdgeRect = new Rectangle();
						var neighbourLightmapEdgeRect = new Rectangle();
						if ( !heightEdgeRect.IsNull )
						{
							GetNeighbourEdgeRect( ni, heightEdgeRect, ref neighbourHeightEdgeRect );
						}

						if ( !lightmapRect.IsNull )
						{
							GetNeighbourEdgeRect( ni, lightmapEdgeRect, ref neighbourLightmapEdgeRect );
						}

						neighbour.NeighbourModified( GetOppositeNeighbour( ni ), neighbourHeightEdgeRect, neighbourLightmapEdgeRect );
					}
				}
			}
		}
示例#11
0
		public void UpdateCompositeMap()
		{
			// All done in the render thread
			if ( this.mCompositeMapRequired && !this.mCompositeMapDirtyRect.IsNull )
			{
				IsModified = true;
				CreateOrDestroyGPUCompositeMap();
				if ( this.mCompositeMapDirtyRectLightmapUpdate &&
					 ( this.mCompositeMapDirtyRect.Width < this.mSize || this.mCompositeMapDirtyRect.Height < this.mSize ) )
				{
					// widen the dirty rectangle since lighting makes it wider
					var widenedRect = new Rectangle();
					WidenRectByVector( TerrainGlobalOptions.LightMapDirection, this.mCompositeMapDirtyRect, ref widenedRect );
					// clamp
					widenedRect.Left = Utility.Max( widenedRect.Left, 0L );
					widenedRect.Top = Utility.Max( widenedRect.Top, 0L );
					widenedRect.Right = Utility.Min( widenedRect.Right, (long)this.mSize );
					widenedRect.Bottom = Utility.Min( widenedRect.Bottom, (long)this.mSize );
					this.mMaterialGenerator.UpdateCompositeMap( this, widenedRect );
				}
				else
				{
					this.mMaterialGenerator.UpdateCompositeMap( this, this.mCompositeMapDirtyRect );
				}

				this.mCompositeMapDirtyRectLightmapUpdate = false;
				this.mCompositeMapDirtyRect.IsNull = true;
			}
		}
示例#12
0
		public void FinalizeLightMap( Rectangle rect, PixelBox lightmapBox )
		{
			CreateOrDestroyGPULightmap();
			// deal with race condition where lm has been disabled while we were working!
			if ( LightMap != null )
			{
				// blit the normals into the texture
				if ( rect.Left == 0 && rect.Top == 0 && rect.Bottom == this.mLightmapSizeActual &&
					 rect.Right == this.mLightmapSizeActual )
				{
					LightMap.GetBuffer().BlitFromMemory( lightmapBox );
				}
				else
				{
					// content of PixelBox is already inverted in Y, but rect is still 
					// in terrain space for dealing with sub-rect, so invert
					var dstBox = new BasicBox();
					dstBox.Left = (int)rect.Left;
					dstBox.Right = (int)rect.Right;
					dstBox.Top = (int)( this.mLightmapSizeActual - rect.Bottom );
					dstBox.Bottom = (int)( this.mLightmapSizeActual - rect.Top );
					LightMap.GetBuffer().BlitFromMemory( lightmapBox, dstBox );
				}
			}

			// delete memory
			if ( lightmapBox.Data != null )
			{
				lightmapBox.Data.Dispose();
				lightmapBox.Data = null;
			}
			lightmapBox = null;
		}
示例#13
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;
		}
示例#14
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 );
				}
			}
		}
示例#15
0
		public void GetEdgeRect( NeighbourIndex index, long range, ref Rectangle outRect )
		{
			// We make the edge rectangle 2 rows / columns at the edge of the tile
			// 2 because this copes with normal changes and potentially filtered
			// shadows.
			// all right / bottom values are exclusive
			// terrain origin is bottom-left remember so north is highest value

			// set left/right
			switch ( index )
			{
				case NeighbourIndex.East:
				case NeighbourIndex.NorthEast:
				case NeighbourIndex.SouthEast:
					outRect.Left = this.mSize - range;
					outRect.Right = this.mSize;
					break;

				case NeighbourIndex.West:
				case NeighbourIndex.NorthWest:
				case NeighbourIndex.SouthWest:
					outRect.Left = 0;
					outRect.Right = range;
					break;

				case NeighbourIndex.North:
				case NeighbourIndex.South:
					outRect.Left = 0;
					outRect.Right = this.mSize;
					break;

				case NeighbourIndex.Count:
				default:
					break;
			}
			;

			// set top / bottom
			switch ( index )
			{
				case NeighbourIndex.North:
				case NeighbourIndex.NorthEast:
				case NeighbourIndex.NorthWest:
					outRect.Top = this.mSize - range;
					outRect.Bottom = this.mSize;
					break;

				case NeighbourIndex.South:
				case NeighbourIndex.SouthWest:
				case NeighbourIndex.SouthEast:
					outRect.Top = 0;
					outRect.Bottom = range;
					break;

				case NeighbourIndex.East:
				case NeighbourIndex.West:
					outRect.Top = 0;
					outRect.Bottom = this.mSize;
					break;

				case NeighbourIndex.Count:
				default:
					break;
			}
			;
		}
示例#16
0
		public void UpdateVertexData( bool positions, bool deltas, Rectangle rect, bool cpuData )
		{
			if ( rect.Left <= this.mBoundaryX || rect.Right > this.mOffsetX || rect.Top <= this.mBoundaryY ||
			     rect.Bottom > this.mOffsetY )
			{
				// Do we have vertex data?
				if ( this.mVertexDataRecord != null )
				{
					// Trim to our bounds
					var updateRect = new Rectangle( this.mOffsetX, this.mOffsetY, this.mBoundaryX, this.mBoundaryY );
					updateRect.Left = System.Math.Max( updateRect.Left, rect.Left );
					updateRect.Right = System.Math.Min( updateRect.Right, rect.Right );
					updateRect.Top = System.Math.Max( updateRect.Top, rect.Top );
					updateRect.Bottom = System.Math.Min( updateRect.Bottom, rect.Bottom );

					// update the GPU buffer directly
#warning TODO: do we have no use for CPU vertex data after initial load?
					// if so, destroy it to free RAM, this should be fast enough to 
					// to direct

					HardwareVertexBuffer posbuf = null, deltabuf = null;
					var targetData = cpuData ? this.mVertexDataRecord.CpuVertexData : this.mVertexDataRecord.GpuVertexData;

					if ( positions )
					{
						posbuf = targetData.vertexBufferBinding.GetBuffer( POSITION_BUFFER );
					}
					if ( deltas )
					{
						deltabuf = targetData.vertexBufferBinding.GetBuffer( DELTA_BUFFER );
					}

					UpdateVertexBuffer( posbuf, deltabuf, updateRect );
				}

				// pass on to children
				if ( !IsLeaf )
				{
					for ( int i = 0; i < 4; ++i )
					{
						this.mChildren[ i ].UpdateVertexData( positions, deltas, rect, cpuData );

						// merge bounds from children
						var childBox = new AxisAlignedBox( this.mChildren[ i ].AABB );

						// this box is relative to child centre
						var boxoffset = this.mChildren[ i ].LocalCentre - LocalCentre;
						childBox.Minimum = childBox.Minimum + boxoffset;
						childBox.Maximum = childBox.Maximum + boxoffset;
						this.mAABB.Merge( childBox );
					}
				}

				// Make sure node knows to update
				if ( this.mMovable != null && this.mMovable.IsAttached )
				{
					this.mMovable.ParentSceneNode.NeedUpdate();
				}
			}
		}
示例#17
0
		public void GetNeighbourEdgeRect( NeighbourIndex index, Rectangle inRect, ref Rectangle outRect )
		{
			System.Diagnostics.Debug.Assert( this.mSize == GetNeighbour( index ).Size,
											 "Neighbour has not the same size as this instance" );

			// Basically just reflect the rect 
			// remember index is neighbour relationship from OUR perspective so
			// arrangement is backwards to getEdgeRect

			// left/right
			switch ( index )
			{
				case NeighbourIndex.East:
				case NeighbourIndex.NorthEast:
				case NeighbourIndex.SouthEast:
				case NeighbourIndex.West:
				case NeighbourIndex.NorthWest:
				case NeighbourIndex.SouthWest:
					outRect.Left = this.mSize - inRect.Right;
					outRect.Right = this.mSize - inRect.Left;
					break;

				default:
					outRect.Left = inRect.Left;
					outRect.Right = inRect.Right;
					break;
			}
			;

			// top / bottom
			switch ( index )
			{
				case NeighbourIndex.North:
				case NeighbourIndex.NorthEast:
				case NeighbourIndex.NorthWest:
				case NeighbourIndex.South:
				case NeighbourIndex.SouthWest:
				case NeighbourIndex.SouthEast:
					outRect.Top = this.mSize - inRect.Bottom;
					outRect.Bottom = this.mSize - inRect.Top;
					break;

				default:
					outRect.Top = inRect.Top;
					outRect.Bottom = inRect.Bottom;
					break;
			}
			;
		}
示例#18
0
		public bool RectContainsNode( Rectangle rect )
		{
			return ( rect.Left <= this.mOffsetX && rect.Right > this.mBoundaryX && rect.Top <= this.mOffsetY &&
			         rect.Bottom > this.mBoundaryY );
		}
示例#19
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();
				}
			}
		}
示例#20
0
		protected void UpdateVertexBuffer( HardwareVertexBuffer posBuf, HardwareVertexBuffer deltaBuf, Rectangle rect )
		{
			Debug.Assert( rect.Left >= this.mOffsetX && rect.Right <= this.mBoundaryX && rect.Top >= this.mOffsetY &&
			              rect.Bottom <= this.mBoundaryY );

			// potentially reset our bounds depending on coverage of the update
			ResetBounds( rect );

			//main data
			var inc = (ushort)( ( this.mTerrain.Size - 1 )/( this.mVertexDataRecord.Resolution - 1 ) );
			long destOffsetX = rect.Left <= this.mOffsetX ? 0 : ( rect.Left - this.mOffsetX )/inc;
			long destOffsetY = rect.Top <= this.mOffsetY ? 0 : ( rect.Top - this.mOffsetY )/inc;
			// Fill the buffers

			BufferLocking lockmode;
			if ( destOffsetX != 0 || destOffsetY != 0 || rect.Width < this.mSize || rect.Height < this.mSize )
			{
				lockmode = BufferLocking.Normal;
			}
			else
			{
				lockmode = BufferLocking.Discard;
			}
			Real uvScale = 1.0f/( this.mTerrain.Size - 1 );
			var pBaseHeight = this.mTerrain.GetHeightData( rect.Left, rect.Top );
			var pBaseDelta = this.mTerrain.GetDeltaData( rect.Left, rect.Top );
			var rowskip = (ushort)( this.mTerrain.Size*inc );
			ushort destPosRowSkip = 0, destDeltaRowSkip = 0;
			BufferBase pRootPosBuf = null;
			BufferBase pRootDeltaBuf = null;
			BufferBase pRowPosBuf = null;
			BufferBase pRowDeltaBuf = null;

			if ( posBuf != null )
			{
				destPosRowSkip = (ushort)( this.mVertexDataRecord.Size*posBuf.VertexSize );
				pRootPosBuf = posBuf.Lock( lockmode );
				pRowPosBuf = pRootPosBuf;
				// skip dest buffer in by left/top
				pRowPosBuf += destOffsetY*destPosRowSkip + destOffsetX*posBuf.VertexSize;
			}
			if ( deltaBuf != null )
			{
				destDeltaRowSkip = (ushort)( this.mVertexDataRecord.Size*deltaBuf.VertexSize );
				pRootDeltaBuf = deltaBuf.Lock( lockmode );
				pRowDeltaBuf = pRootDeltaBuf;
				// skip dest buffer in by left/top
				pRowDeltaBuf += destOffsetY*destDeltaRowSkip + destOffsetX*deltaBuf.VertexSize;
			}
			Vector3 pos = Vector3.Zero;

			for ( var y = (ushort)rect.Top; y < rect.Bottom; y += inc )
			{
#if !AXIOM_SAFE_ONLY
				unsafe
#endif
				{
					var pHeight = pBaseHeight.ToFloatPointer();
					var pHIdx = 0;
					var pDelta = pBaseDelta.ToFloatPointer();
					var pDeltaIdx = 0;
					var pPosBuf = pRowPosBuf != null ? pRowPosBuf.ToFloatPointer() : null;
					var pPosBufIdx = 0;
					var pDeltaBuf = pRowDeltaBuf != null ? pRowDeltaBuf.ToFloatPointer() : null;
					var pDeltaBufIdx = 0;
					for ( var x = (ushort)rect.Left; x < rect.Right; x += inc )
					{
						if ( pPosBuf != null )
						{
							this.mTerrain.GetPoint( x, y, pHeight[ pHIdx ], ref pos );
							// Update bounds *before* making relative
							MergeIntoBounds( x, y, pos );
							// relative to local centre
							pos -= this.mLocalCentre;
							pHIdx += inc;

							pPosBuf[ pPosBufIdx++ ] = pos.x;
							pPosBuf[ pPosBufIdx++ ] = pos.y;
							pPosBuf[ pPosBufIdx++ ] = pos.z;

							// UVs - base UVs vary from 0 to 1, all other values
							// will be derived using scalings
							pPosBuf[ pPosBufIdx++ ] = x*uvScale;
							pPosBuf[ pPosBufIdx++ ] = 1.0f - ( y*uvScale );
						}

						if ( pDeltaBuf != null )
						{
							//delta
							pDeltaBuf[ pDeltaBufIdx++ ] = pDelta[ pDeltaIdx ];
							pDeltaIdx += inc;
							// delta LOD threshold
							// we want delta to apply to LODs no higher than this value
							// at runtime this will be combined with a per-renderable parameter
							// to ensure we only apply morph to the correct LOD
							pDeltaBuf[ pDeltaBufIdx++ ] = (float)this.mTerrain.GetLODLevelWhenVertexEliminated( x, y ) - 1.0f;
						}
					} // end unsafe
				} //end for

				pBaseHeight += rowskip;
				pBaseDelta += rowskip;
				if ( pRowPosBuf != null )
				{
					pRowPosBuf += destPosRowSkip;
				}
				if ( pRowDeltaBuf != null )
				{
					pRowDeltaBuf += destDeltaRowSkip;
				}
			} //end for

			// Skirts now
			// skirt spacing based on top-level resolution (* inc to cope with resolution which is not the max)
			var skirtSpacing = (ushort)( this.mVertexDataRecord.SkirtRowColSkip*inc );
			var skirtOffset = Vector3.Zero;
			this.mTerrain.GetVector( 0, 0, -this.mTerrain.SkirtSize, ref skirtOffset );

			// skirt rows
			// clamp rows to skirt spacing (round up)
			var skirtStartX = rect.Left;
			var skirtStartY = rect.Top;
			// for rows, clamp Y to skirt frequency, X to inc (LOD resolution vs top)
			if ( skirtStartY%skirtSpacing != 0 )
			{
				skirtStartY += skirtSpacing - ( skirtStartY%skirtSpacing );
			}
			if ( skirtStartX%inc != 0 )
			{
				skirtStartX += inc - ( skirtStartX%inc );
			}

			skirtStartY = System.Math.Max( skirtStartY, (long)this.mOffsetY );
			pBaseHeight = this.mTerrain.GetHeightData( skirtStartX, skirtStartY );
			if ( posBuf != null )
			{
				// position dest buffer just after the main vertex data
				pRowPosBuf = pRootPosBuf + posBuf.VertexSize*this.mVertexDataRecord.Size*this.mVertexDataRecord.Size;
				// move it onwards to skip the skirts we don't need to update
				pRowPosBuf += destPosRowSkip*( ( skirtStartY - this.mOffsetY )/skirtSpacing );
				pRowPosBuf += posBuf.VertexSize*( skirtStartX - this.mOffsetX )/inc;
			}
			if ( deltaBuf != null )
			{
				// position dest buffer just after the main vertex data
				pRowDeltaBuf = pRootDeltaBuf + deltaBuf.VertexSize*this.mVertexDataRecord.Size*this.mVertexDataRecord.Size;
				// move it onwards to skip the skirts we don't need to update
				pRowDeltaBuf += destDeltaRowSkip*( skirtStartY - this.mOffsetY )/skirtSpacing;
				pRowDeltaBuf += deltaBuf.VertexSize*( skirtStartX - this.mOffsetX )/inc;
			}

			for ( var y = (ushort)skirtStartY; y < (ushort)rect.Bottom; y += skirtSpacing )
			{
#if !AXIOM_SAFE_ONLY
				unsafe
#endif
				{
					var pHeight = pBaseHeight.ToFloatPointer();
					var pHIdx = 0;
					var pPosBuf = pRowPosBuf != null ? pRowPosBuf.ToFloatPointer() : null;
					var pPosIdx = 0;
					var pDeltaBuf = pRowDeltaBuf != null ? pRowDeltaBuf.ToFloatPointer() : null;
					var pDeltaIdx = 0;
					for ( var x = (ushort)skirtStartX; x < (ushort)rect.Right; x += inc )
					{
						if ( pPosBuf != null )
						{
							this.mTerrain.GetPoint( x, y, pHeight[ pHIdx ], ref pos );
							// relative to local centre
							pos -= this.mLocalCentre;
							pHIdx += inc;
							pos += skirtOffset;
							pPosBuf[ pPosIdx++ ] = pos.x;
							pPosBuf[ pPosIdx++ ] = pos.y;
							pPosBuf[ pPosIdx++ ] = pos.z;

							// UVs - same as base
							pPosBuf[ pPosIdx++ ] = x*uvScale;
							pPosBuf[ pPosIdx++ ] = 1.0f - ( y*uvScale );
						}
						if ( pDeltaBuf != null )
						{
							// delta (none)
							pDeltaBuf[ pDeltaIdx++ ] = 0;
							// delta threshold (irrelevant)
							pDeltaBuf[ pDeltaIdx++ ] = 99;
						}
					} //end for
					pBaseHeight += this.mTerrain.Size*skirtSpacing;
					if ( pRowPosBuf != null )
					{
						pRowPosBuf += destPosRowSkip;
					}
					if ( pRowDeltaBuf != null )
					{
						pRowDeltaBuf += destDeltaRowSkip;
					}
				} // end unsafe
			} //end for

			// skirt cols
			// clamp cols to skirt spacing (round up)
			skirtStartX = rect.Left;
			if ( skirtStartX%skirtSpacing != 0 )
			{
				skirtStartX += skirtSpacing - ( skirtStartX%skirtSpacing );
			}
			// clamp Y to inc (LOD resolution vs top)
			skirtStartY = rect.Top;
			if ( skirtStartY%inc != 0 )
			{
				skirtStartY += inc - ( skirtStartY%inc );
			}
			skirtStartX = System.Math.Max( skirtStartX, (long)this.mOffsetX );

			if ( posBuf != null )
			{
				// position dest buffer just after the main vertex data and skirt rows
				pRowPosBuf = pRootPosBuf + posBuf.VertexSize*this.mVertexDataRecord.Size*this.mVertexDataRecord.Size;
				// skip the row skirts
				pRowPosBuf += this.mVertexDataRecord.NumSkirtRowsCols*this.mVertexDataRecord.Size*posBuf.VertexSize;
				// move it onwards to skip the skirts we don't need to update
				pRowPosBuf += destPosRowSkip*( skirtStartX - this.mOffsetX )/skirtSpacing;
				pRowPosBuf += posBuf.VertexSize*( skirtStartY - this.mOffsetY )/inc;
			}
			if ( deltaBuf != null )
			{
				// Deltaition dest buffer just after the main vertex data and skirt rows
				pRowDeltaBuf = pRootDeltaBuf + deltaBuf.VertexSize*this.mVertexDataRecord.Size*this.mVertexDataRecord.Size;

				// skip the row skirts
				pRowDeltaBuf += this.mVertexDataRecord.NumSkirtRowsCols*this.mVertexDataRecord.Size*deltaBuf.VertexSize;
				// move it onwards to skip the skirts we don't need to update
				pRowDeltaBuf += destDeltaRowSkip*( skirtStartX - this.mOffsetX )/skirtSpacing;
				pRowDeltaBuf += deltaBuf.VertexSize*( skirtStartY - this.mOffsetY )/inc;
			}

			for ( var x = (ushort)skirtStartX; x < (ushort)rect.Right; x += skirtSpacing )
			{
#if !AXIOM_SAFE_ONLY
				unsafe
#endif
				{
					var pPosBuf = pRowPosBuf != null ? pRowPosBuf.ToFloatPointer() : null;
					var pPosIdx = 0;
					var pDeltaBuf = pRowDeltaBuf != null ? pRowDeltaBuf.ToFloatPointer() : null;
					var pDeltaIdx = 0;
					for ( var y = (ushort)skirtStartY; y < (ushort)rect.Bottom; y += inc )
					{
						if ( pPosBuf != null )
						{
							this.mTerrain.GetPoint( x, y, this.mTerrain.GetHeightAtPoint( x, y ), ref pos );
							// relative to local centre
							pos -= this.mLocalCentre;
							pos += skirtOffset;

							pPosBuf[ pPosIdx++ ] = pos.x;
							pPosBuf[ pPosIdx++ ] = pos.y;
							pPosBuf[ pPosIdx++ ] = pos.z;

							// UVs - same as base
							pPosBuf[ pPosIdx++ ] = x*uvScale;
							pPosBuf[ pPosIdx++ ] = 1.0f - ( y*uvScale );
						}
						if ( pDeltaBuf != null )
						{
							// delta (none)
							pDeltaBuf[ pDeltaIdx++ ] = 0;
							// delta threshold (irrelevant)
							pDeltaBuf[ pDeltaIdx++ ] = 99;
						}
					} //end for
					if ( pRowPosBuf != null )
					{
						pRowPosBuf += destPosRowSkip;
					}
					if ( pRowDeltaBuf != null )
					{
						pRowDeltaBuf += destDeltaRowSkip;
					}
				} // end unsafe
			} //end for

			if ( posBuf != null )
			{
				posBuf.Unlock();
			}
			if ( deltaBuf != null )
			{
				deltaBuf.Unlock();
			}
		}
示例#21
0
		public static System.Drawing.Rectangle ToRectangle( Rectangle rect )
		{
			return new System.Drawing.Rectangle( new System.Drawing.Point( (int)rect.Left, (int)rect.Top ),
												 new System.Drawing.Size( (int)rect.Width, (int)rect.Height ) );
		}
示例#22
0
		public void Prepare( StreamSerializer stream )
		{
			// load LOD data we need
			for ( int i = 0; i < this.mLodLevels.Count; ++i )
			{
				var ll = this.mLodLevels[ i ];
				// only read 'calc' and then copy to final (separation is only for
				// real-time calculation
				// Basically this is what finaliseHeightDeltas does in calc path
				stream.Read( out ll.CalcMaxHeightDelta );
				ll.MaxHeightDelta = ll.CalcMaxHeightDelta;
				ll.LastCFactor = 0;
			}

			if ( !IsLeaf )
			{
				for ( int i = 0; i < 4; ++i )
				{
					this.mChildren[ i ].Prepare( stream );
				}
			}

			// If this is the root, do the post delta calc to finish
			if ( this.mParent == null )
			{
				var rect = new Rectangle();
				rect.Top = this.mOffsetY;
				rect.Bottom = this.mBoundaryY;
				rect.Left = this.mOffsetX;
				rect.Right = this.mBoundaryX;
				PostDeltaCalculation( rect );
			}
		}
			/// <summary>
			/// Update the composite map for a terrain
			/// </summary>
			/// <param name="terrain"></param>
			/// <param name="rect"></param>
			public virtual void UpdateCompositeMap( Terrain terrain, Rectangle rect )
			{
				// convert point-space rect into image space
				int compSize = terrain.CompositeMap.Width;
				var imgRect = new Rectangle();
				Vector3 inVec = Vector3.Zero, outVec = Vector3.Zero;
				inVec.x = rect.Left;
				inVec.y = rect.Bottom - 1; // this is 'top' in image space, also make inclusive
				terrain.ConvertPosition( Space.PointSpace, inVec, Space.TerrainSpace, ref outVec );
				float left = ( outVec.x*compSize );
				float top = ( ( 1.0f - outVec.y )*compSize );
				;
				imgRect.Left = (long)left;
				imgRect.Top = (long)top;
				inVec.x = rect.Right - 1;
				inVec.y = rect.Top; // this is 'bottom' in image space
				terrain.ConvertPosition( Space.PointSpace, inVec, Space.TerrainSpace, ref outVec );
				float right = ( outVec.x*(float)compSize + 1 );
				imgRect.Right = (long)right;
				float bottom = ( ( 1.0f - outVec.y )*compSize + 1 );
				imgRect.Bottom = (long)bottom;

				imgRect.Left = System.Math.Max( 0L, imgRect.Left );
				imgRect.Top = System.Math.Max( 0L, imgRect.Top );
				imgRect.Right = System.Math.Min( (long)compSize, imgRect.Right );
				imgRect.Bottom = System.Math.Min( (long)compSize, imgRect.Bottom );

#warning enable rendercompositemap
#if false
mParent.RenderCompositeMap(compSize, imgRect,
terrain.CompositeMapMaterial,
terrain.CompositeMap);
#endif
				update = true;
			}
示例#24
0
		public void PostDeltaCalculation( Rectangle rect )
		{
			if ( rect.Left <= this.mBoundaryX || rect.Right > this.mOffsetX || rect.Top <= this.mBoundaryY ||
			     rect.Bottom > this.mOffsetY )
			{
				// relevant to this node (overlaps)

				// each non-leaf node should know which of its children transitions
				// to the lower LOD level last, because this is the one which controls
				// when the parent takes over
				if ( !IsLeaf )
				{
					float maxChildDelta = -1;
					TerrainQuadTreeNode childWithMaxHeightDelta = null;
					for ( int i = 0; i < 4; i++ )
					{
						TerrainQuadTreeNode child = this.mChildren[ i ];
						child.PostDeltaCalculation( rect );
						float childData = child.GetLodLevel( (ushort)( child.LodCount - 1 ) ).CalcMaxHeightDelta;

						if ( childData > maxChildDelta )
						{
							childWithMaxHeightDelta = child;
							maxChildDelta = childData;
						}
					}

					// make sure that our highest delta value is greater than all children's
					// otherwise we could have some crossover problems
					// for a non-leaf, there is only one LOD level
					LodLevel tmp = this.mLodLevels[ 0 ];
					tmp.CalcMaxHeightDelta = System.Math.Max( tmp.CalcMaxHeightDelta, maxChildDelta*(Real)1.05 );
					this.mChildWithMaxHeightDelta = childWithMaxHeightDelta;
				}
				else
				{
					// make sure own LOD levels delta values ascend
					for ( int i = 0; i < this.mLodLevels.Count - 1; i++ )
					{
						// the next LOD after this one should have a higher delta
						// otherwise it won't come into affect further back like it should!
						LodLevel tmp = this.mLodLevels[ i ];
						LodLevel tmpPlus = this.mLodLevels[ i + 1 ];
						tmpPlus.CalcMaxHeightDelta = System.Math.Max( tmpPlus.CalcMaxHeightDelta, tmp.CalcMaxHeightDelta*(Real)1.05 );
					}
				}
			}
		}
		/// <summary>
		/// Update the composite map for a terrain.
		/// The composite map for a terrain must match what the terrain should look like
		/// at distance. This method will only be called in the render thread so the
		/// generator is free to render into a texture to support this, so long as 
		/// the results are blitted into the Terrain's own composite map afterwards.
		/// </summary>
		/// <param name="terrain"></param>
		/// <param name="rect"></param>
		public virtual void UpdateCompositeMap( Terrain terrain, Rectangle rect )
		{
			Profile p = ActiveProfile;
			if ( p == null )
			{
				return;
			}
			else
			{
				p.UpdateCompositeMap( terrain, rect );
			}
		}
示例#26
0
		public Rectangle( Rectangle copy )
		{
			_left = copy._left;
			_top = copy._top;
			_right = copy._right;
			_bottom = copy._bottom;
		}
		/// <summary>
		/// Helper method to render a composite map.
		/// </summary>
		/// <param name="size"> The requested composite map size</param>
		/// <param name="rect"> The region of the composite map to update, in image space</param>
		/// <param name="mat">The material to use to render the map</param>
		/// <param name="destCompositeMap"></param>
		public virtual void RenderCompositeMap( int size, Rectangle rect, Material mat, Texture destCompositeMap )
		{
			//return;
			if ( this.mCompositeMapSM == null )
			{
				//dedicated SceneManager

				this.mCompositeMapSM = Root.Instance.CreateSceneManager( SceneType.ExteriorClose,
				                                                         "TerrainMaterialGenerator_SceneManager" );
				float camDist = 100;
				float halfCamDist = camDist*0.5f;
				this.mCompositeMapCam = this.mCompositeMapSM.CreateCamera( "TerrainMaterialGenerator_Camera" );
				this.mCompositeMapCam.Position = new Vector3( 0, 0, camDist );
				//mCompositeMapCam.LookAt(Vector3.Zero);
				this.mCompositeMapCam.ProjectionType = Projection.Orthographic;
				this.mCompositeMapCam.Near = 10;
				this.mCompositeMapCam.Far = 999999*3;
				//mCompositeMapCam.AspectRatio = camDist / camDist;
				this.mCompositeMapCam.SetOrthoWindow( camDist, camDist );
				// Just in case material relies on light auto params
				this.mCompositeMapLight = this.mCompositeMapSM.CreateLight( "TerrainMaterialGenerator_Light" );
				this.mCompositeMapLight.Type = LightType.Directional;

				RenderSystem rSys = Root.Instance.RenderSystem;
				float hOffset = rSys.HorizontalTexelOffset/(float)size;
				float vOffset = rSys.VerticalTexelOffset/(float)size;

				//setup scene
				this.mCompositeMapPlane = this.mCompositeMapSM.CreateManualObject( "TerrainMaterialGenerator_ManualObject" );
				this.mCompositeMapPlane.Begin( mat.Name, OperationType.TriangleList );
				this.mCompositeMapPlane.Position( -halfCamDist, halfCamDist, 0 );
				this.mCompositeMapPlane.TextureCoord( 0 - hOffset, 0 - vOffset );
				this.mCompositeMapPlane.Position( -halfCamDist, -halfCamDist, 0 );
				this.mCompositeMapPlane.TextureCoord( 0 - hOffset, 1 - vOffset );
				this.mCompositeMapPlane.Position( halfCamDist, -halfCamDist, 0 );
				this.mCompositeMapPlane.TextureCoord( 1 - hOffset, 1 - vOffset );
				this.mCompositeMapPlane.Position( halfCamDist, halfCamDist, 0 );
				this.mCompositeMapPlane.TextureCoord( 1 - hOffset, 0 - vOffset );
				this.mCompositeMapPlane.Quad( 0, 1, 2, 3 );
				this.mCompositeMapPlane.End();
				this.mCompositeMapSM.RootSceneNode.AttachObject( this.mCompositeMapPlane );
			} //end if

			// update
			this.mCompositeMapPlane.SetMaterialName( 0, mat.Name );
			this.mCompositeMapLight.Direction = TerrainGlobalOptions.LightMapDirection;
			this.mCompositeMapLight.Diffuse = TerrainGlobalOptions.CompositeMapDiffuse;
			this.mCompositeMapSM.AmbientLight = TerrainGlobalOptions.CompositeMapAmbient;


			//check for size change (allow smaller to be reused)
			if ( this.mCompositeMapRTT != null && size != this.mCompositeMapRTT.Width )
			{
				TextureManager.Instance.Remove( this.mCompositeMapRTT );
				this.mCompositeMapRTT = null;
			}
			if ( this.mCompositeMapRTT == null )
			{
				this.mCompositeMapRTT = TextureManager.Instance.CreateManual( this.mCompositeMapSM.Name + "/compRTT",
				                                                              ResourceGroupManager.DefaultResourceGroupName,
				                                                              TextureType.TwoD, size, size, 0, PixelFormat.BYTE_RGBA,
				                                                              TextureUsage.RenderTarget );

				RenderTarget rtt = this.mCompositeMapRTT.GetBuffer().GetRenderTarget();
				// don't render all the time, only on demand
				rtt.IsAutoUpdated = false;
				Viewport vp = rtt.AddViewport( this.mCompositeMapCam );
				// don't render overlays
				vp.ShowOverlays = false;
			}

			// calculate the area we need to update
			float vpleft = (float)rect.Left/(float)size;
			float vptop = (float)rect.Top/(float)size;
			float vpright = (float)rect.Right/(float)size;
			float vpbottom = (float)rect.Bottom/(float)size;
			float vpwidth = (float)rect.Width/(float)size;
			float vpheight = (float)rect.Height/(float)size;

			RenderTarget rtt2 = this.mCompositeMapRTT.GetBuffer().GetRenderTarget();
			Viewport vp2 = rtt2.GetViewport( 0 );
			this.mCompositeMapCam.SetWindow( vpleft, vptop, vpright, vpbottom );
			rtt2.Update();
			vp2.Update();
			// We have an RTT, we want to copy the results into a regular texture
			// That's because in non-update scenarios we don't want to keep an RTT
			// around. We use a single RTT to serve all terrain pages which is more
			// efficient.
			var box = new BasicBox( (int)rect.Left, (int)rect.Top, (int)rect.Right, (int)rect.Bottom );
			destCompositeMap.GetBuffer().Blit( this.mCompositeMapRTT.GetBuffer(), box, box );
		}
示例#28
0
		public Rectangle Merge( Rectangle rhs )
		{
			if ( Width == 0 )
			{
				this = rhs;
			}
			else
			{
				Left = System.Math.Min( Left, rhs.Left );
				Right = System.Math.Max( Right, rhs.Right );
				Top = System.Math.Min( Top, rhs.Top );
				Bottom = System.Math.Max( Bottom, rhs.Bottom );
			}

			return this;
		}
示例#29
0
        public override void CopyContentsToMemory(PixelBox dst, FrameBuffer buffer)
        {
            if ((dst.Left < 0) || (dst.Right > Width) ||
                (dst.Top < 0) || (dst.Bottom > Height) ||
                (dst.Front != 0) || (dst.Back != 1))
            {
                throw new Exception("Invalid box.");
            }

            var device = Driver.XnaDevice;
            //in 3.1, this was ResolveTexture2D, an actual RenderTarget provides the exact same
            //functionality, especially seeing as RenderTarget2D is a texture now.
            //the difference is surface is actually set on the device -DoubleA
            RenderTarget2D surface;
            var            data  = new byte[dst.ConsecutiveSize];
            var            pitch = 0;

            if (buffer == FrameBuffer.Auto)
            {
                buffer = FrameBuffer.Front;
            }

#if SILVERLIGHT
            var mode = ((XnaRenderSystem)Root.Instance.RenderSystem).DisplayMode;
            surface = new RenderTarget2D(device, mode.Width, mode.Height, false, SurfaceFormat.Color, DepthFormat.Depth24Stencil8);
#else
            var mode = device.DisplayMode;
            surface = new RenderTarget2D(device, mode.Width, mode.Height, false, SurfaceFormat.Rgba64, DepthFormat.Depth24Stencil8);
#endif
            //ResolveTexture2D( device, mode.Width, mode.Height, 0, SurfaceFormat.Rgba32 );

#if !SILVERLIGHT
            if (buffer == FrameBuffer.Front)
            {
                // get the entire front buffer.  This is SLOW!!
                device.SetRenderTarget(surface);

                if (IsFullScreen)
                {
                    if ((dst.Left == 0) && (dst.Right == Width) && (dst.Top == 0) && (dst.Bottom == Height))
                    {
                        surface.GetData(data);
                    }
                    else
                    {
                        var rect = new Rectangle();
                        rect.Left   = dst.Left;
                        rect.Right  = dst.Right;
                        rect.Top    = dst.Top;
                        rect.Bottom = dst.Bottom;

                        surface.GetData(0, XnaHelper.ToRectangle(rect), data, 0, 255);
                    }
                }
#if !(XBOX || XBOX360 || WINDOWS_PHONE)
                else
                {
                    var srcRect = new Rectangle();
                    srcRect.Left   = dst.Left;
                    srcRect.Right  = dst.Right;
                    srcRect.Top    = dst.Top;
                    srcRect.Bottom = dst.Bottom;
                    // Adjust Rectangle for Window Menu and Chrome
                    var point = new Point();
                    point.X = (int)srcRect.Left;
                    point.Y = (int)srcRect.Top;
                    var control = Control.FromHandle(_windowHandle);
                    point           = control.PointToScreen(point);
                    srcRect.Top     = (long)point.Y;
                    srcRect.Left    = (long)point.X;
                    srcRect.Bottom += (long)point.Y;
                    srcRect.Right  += (long)point.X;

                    surface.GetData(0, XnaHelper.ToRectangle(srcRect), data, 0, 255);
                }
#endif
            }
            else
            {
                device.SetRenderTarget(surface);

                if ((dst.Left == 0) && (dst.Right == Width) && (dst.Top == 0) && (dst.Bottom == Height))
                {
                    surface.GetData(data);
                }
                else
                {
                    var rect = new Rectangle();
                    rect.Left   = dst.Left;
                    rect.Right  = dst.Right;
                    rect.Top    = dst.Top;
                    rect.Bottom = dst.Bottom;

                    surface.GetData(0, XnaHelper.ToRectangle(rect), data, 0, 255);
                }
            }
#endif

            var format = XnaHelper.Convert(surface.Format);

            if (format == PixelFormat.Unknown)
            {
                throw new Exception("Unsupported format");
            }

            var dataPtr = Memory.PinObject(data);
            var src     = new PixelBox(dst.Width, dst.Height, 1, format, dataPtr);
            src.RowPitch   = pitch / PixelUtil.GetNumElemBytes(format);
            src.SlicePitch = surface.Height * src.RowPitch;

            PixelConverter.BulkPixelConversion(src, dst);

            Memory.UnpinObject(data);
            surface.Dispose();
        }
示例#30
0
		/// <summary>
		///    Updates this elements transform based on it's parent.
		/// </summary>
		public virtual void UpdateFromParent()
		{
			float parentLeft, parentTop, parentBottom, parentRight;

			parentLeft = parentTop = parentBottom = parentRight = 0;

			if ( parent != null )
			{
				parentLeft = parent.DerivedLeft;
				parentTop = parent.DerivedTop;

				// derive right position
				if ( horzAlign == HorizontalAlignment.Center || horzAlign == HorizontalAlignment.Right )
				{
					parentRight = parentLeft + parent.width;
				}
				// derive bottom position
				if ( vertAlign == VerticalAlignment.Center || vertAlign == VerticalAlignment.Bottom )
				{
					parentBottom = parentTop + parent.height;
				}
			}
			else
			{
				// with no real parent, the "parent" is actually the full viewport size
				//                parentLeft = parentTop = 0.0f;
				//                parentRight = parentBottom = 1.0f;

				RenderSystem rSys = Root.Instance.RenderSystem;
				OverlayManager oMgr = OverlayManager.Instance;

				// Calculate offsets required for mapping texel origins to pixel origins in the
				// current rendersystem
				float hOffset = rSys.HorizontalTexelOffset / oMgr.ViewportWidth;
				float vOffset = rSys.VerticalTexelOffset / oMgr.ViewportHeight;

				parentLeft = 0.0f + hOffset;
				parentTop = 0.0f + vOffset;
				parentRight = 1.0f + hOffset;
				parentBottom = 1.0f + vOffset;
			}

			// sort out position based on alignment
			// all we do is derived the origin, we don't automatically sort out the position
			// This is more flexible than forcing absolute right & middle

			switch ( horzAlign )
			{
				case HorizontalAlignment.Center:
					derivedLeft = ( ( parentLeft + parentRight ) * 0.5f ) + left;
					break;

				case HorizontalAlignment.Left:
					derivedLeft = parentLeft + left;
					break;

				case HorizontalAlignment.Right:
					derivedLeft = parentRight + left;
					break;
			}

			switch ( vertAlign )
			{
				case VerticalAlignment.Center:
					derivedTop = ( ( parentTop + parentBottom ) * 0.5f ) + top;
					break;

				case VerticalAlignment.Top:
					derivedTop = parentTop + top;
					break;

				case VerticalAlignment.Bottom:
					derivedTop = parentBottom + top;
					break;
			}

			isDerivedOutOfDate = false;
			if ( parent != null )
			{
				Rectangle parentRect;

				parentRect = parent.ClippingRegion;

				Rectangle childRect = new Rectangle( (long)derivedLeft, (long)derivedTop, (long)( derivedLeft + width ), (long)( derivedTop + height ) );

				this.clippingRegion = Rectangle.Intersect( parentRect, childRect );
			}
			else
			{
				clippingRegion = new Rectangle( (long)derivedLeft, (long)derivedTop, (long)( derivedLeft + width ), (long)( derivedTop + height ) );
			}
		}
示例#31
0
		public void WidenRectByVector( Vector3 vec, Rectangle inRect, ref Rectangle outRect )
		{
			WidenRectByVector( vec, inRect, MinHeight, MaxHeight, ref outRect );
		}