private void ConvertConfigToRules( AutoSplatConfig autoSplatConfig ) { // Initialize textures layerTextureNames[ SAND_INDEX ] = autoSplatConfig.SandTextureName; layerTextureNames[ GRASS_INDEX ] = autoSplatConfig.GrassTextureName; layerTextureNames[ ROCK_INDEX ] = autoSplatConfig.RockTextureName; layerTextureNames[ SNOW_INDEX ] = autoSplatConfig.SnowTextureName; // Create height angle ranges bottom-up; in all cases we use rock for // the vertical -- the steeper the rockier. Actually, more accurately, // we don't use full vertical; in the auto splat normal rules, we only // go up to one radian. So each of these is actually a triplet, where // we use the same texture for up to 57.2 degrees, then start adding rock. AutoSplatHeightAngleRange range; float angleStart = 0f; float angleMid = 90f - 57.2957795f; float angleEnd = 90f; // Min height - Sand range = new AutoSplatHeightAngleRange( Math.Min( MinHeightMM, 0 ) ); range.AddAngleTexturePair( angleStart, SAND_INDEX ); range.AddAngleTexturePair( angleMid, SAND_INDEX ); range.AddAngleTexturePair( angleEnd, ROCK_INDEX ); InternalAddHeightAngleRange( range ); // Grass - blend inflection point for grass range = new AutoSplatHeightAngleRange( (long) autoSplatConfig.SandToGrassHeight ); range.AddAngleTexturePair( angleStart, GRASS_INDEX ); range.AddAngleTexturePair( angleMid, GRASS_INDEX ); range.AddAngleTexturePair( angleEnd, ROCK_INDEX ); InternalAddHeightAngleRange( range ); // Rock - blend inflection point for rock range = new AutoSplatHeightAngleRange( (long) autoSplatConfig.GrassToRockHeight ); range.AddAngleTexturePair( angleStart, ROCK_INDEX ); range.AddAngleTexturePair( angleEnd, ROCK_INDEX ); InternalAddHeightAngleRange( range ); // Snow - blend inflection point for snow range = new AutoSplatHeightAngleRange( (long) autoSplatConfig.RockToSnowHeight ); range.AddAngleTexturePair( angleStart, SNOW_INDEX ); range.AddAngleTexturePair( angleMid, SNOW_INDEX ); range.AddAngleTexturePair( angleEnd, ROCK_INDEX ); InternalAddHeightAngleRange( range ); // Max height - Snow! if( MaxHeightMM > autoSplatConfig.RockToSnowHeight ) { // Max height - Snow! range = new AutoSplatHeightAngleRange( MaxHeightMM ); range.AddAngleTexturePair( angleStart, SNOW_INDEX ); range.AddAngleTexturePair( angleEnd, SNOW_INDEX ); InternalAddHeightAngleRange( range ); } }
private void InternalAddHeightAngleRange( AutoSplatHeightAngleRange range ) { if( range == null ) { throw new NullReferenceException(); } // Make sure the height angle range to be added is not duplicated foreach( AutoSplatHeightAngleRange angleRange in m_RangeList ) { if( angleRange.HeightMM == range.HeightMM ) { throw new ArgumentException( "Duplicate heights are not allowed." + range ); } } #if REJECT_OUT_OF_BOUNDS_RANGES // A properly configured world will never have a range outside of the // height limits, but it is possible that a legacy world will not have // saved the AutoSplatConfig, so it uses the default--and the default // config might have ranges outside the world's limits. Rather than // try to guess how to fit it, we'll just discard it, and leave it to // the user to set up a configuration that they want. if( range.HeightMM <= MaxHeightMM && range.HeightMM >= MinHeightMM ) { m_RangeList.Add( range ); m_RangeList.Sort(); // Keep sorted by height m_IdToRange.Add( range.Id, range ); FireHeightRangeAdded( range ); } #else m_RangeList.Add( range ); m_RangeList.Sort(); // Keep sorted by height m_IdToRange.Add( range.Id, range ); // TODO: This is not right yet, but useful in the short term // For legacy worlds, we may have ranges outside the min/max // that occurs in the world. We'll stretch the bounds for // auto-splatting, but now they are out of sync with the terrain. AdjustMinMax(); FireHeightRangeAdded( range ); #endif }
protected void FireHeightRangeRemoved( AutoSplatHeightAngleRange range ) { if( null != HeightRangeRemoved ) { HeightRangeRemoved( this, range ); } }
public void UndoRemoveHeightRange( AutoSplatHeightAngleRange range ) { InternalAddHeightAngleRange( range ); }
public void MoveHeight( Guid id, long newHeightMM ) { if( m_IdToRange.ContainsKey( id ) ) { AutoSplatHeightAngleRange targetRange = m_IdToRange[ id ]; if( newHeightMM.Equals( targetRange.HeightMM ) ) { // This move isn't going to change anything, so get out early. return; } int index = m_RangeList.IndexOf( targetRange ); AutoSplatHeightAngleRange splitRange = null; if( 0 == index || (m_RangeList.Count - 1) == index ) { // This move alters a range at an extreme, which implicitly splits the // range as we must always keep a range at each extreme. splitRange = new AutoSplatHeightAngleRange( targetRange.HeightMM, targetRange ); } else { // Guaranteed to be neither the first nor last AutoSplatHeightAngleRange prev = m_RangeList[ index - 1 ]; AutoSplatHeightAngleRange next = m_RangeList[ index + 1 ]; if( newHeightMM < prev.HeightMM || next.HeightMM < newHeightMM ) { throw new ConstraintException( "MoveHeight would change ordering of HeightAngleRange list;" + " only Add and Remove should change the sort ordering." ); } // If the move would make the height coincide with one of its // neighbors, back it off slightly to make things sort nicely. if( newHeightMM.Equals( prev.HeightMM ) ) { ++newHeightMM; } else if( newHeightMM.Equals( next.HeightMM ) ) { --newHeightMM; } } targetRange.HeightMM = newHeightMM; FireHeightRangeMoved( targetRange ); if( null != splitRange ) { // Add the result of the split InternalAddHeightAngleRange( splitRange ); } } }
public AutoSplatHeightAngleRange AddHeight( long heightMM, AutoSplatHeightAngleRange slopesTemplate ) { AutoSplatHeightAngleRange range = new AutoSplatHeightAngleRange( heightMM, slopesTemplate ); InternalAddHeightAngleRange( range ); return range; }
public AutoSplatHeightAngleRange AddHeight( long heightMM, int textureIndex ) { AutoSplatHeightAngleRange range = new AutoSplatHeightAngleRange( heightMM, textureIndex, textureIndex ); InternalAddHeightAngleRange( range ); return range; }