Welcome, Guest! Log In | Create Account

Changeset 1900

Show
Ignore:
Timestamp:
11/18/09 18:52:29 (3 months ago)
Author:
bostich1983
Message:

updated terrain to newest version.

Location:
branches/ogre_1.7_update/Projects/Components/Terrain
Files:
3 modified

Legend:

Unmodified
Added
Removed
  • branches/ogre_1.7_update/Projects/Components/Terrain/Terrain.cs

    r1841 r1900  
    4747        public byte TypeMask; 
    4848        public Rectangle DirtyRect; 
     49        public Rectangle LightmapExtraDirtyRect; 
    4950    } 
    5051    /// <summary> 
     
    116117        /// </summary> 
    117118        PointSpace = 3 
     119    } 
     120    /// <summary> 
     121    /// Neighbour index enumeration - indexed anticlockwise from East like angles 
     122    /// </summary> 
     123    public enum NeighbourIndex 
     124    { 
     125        East = 0, 
     126        NorthEast = 1, 
     127        North = 2, 
     128        NorthWest = 3, 
     129        West = 4, 
     130        SouthWest = 5, 
     131        South = 6, 
     132        SouthEast = 7, 
     133        Count = 8 
    118134    } 
    119135    /// <summary> 
     
    522538        /// </summary> 
    523539        protected FloatList mLayerUVMultiplier = new FloatList(); 
     540 
    524541        /// <summary> 
    525542        ///  
     
    661678        ///  
    662679        /// </summary> 
    663         protected static NameGenerator<Texture> msBlendTextureGenerator; 
    664         /// <summary> 
    665         ///  
    666         /// </summary> 
    667         protected static NameGenerator<Texture> msNormalMapNameGenerator; 
    668         /// <summary> 
    669         ///  
    670         /// </summary> 
    671         protected static NameGenerator<Texture> msLightmapNameGenerator; 
    672         /// <summary> 
    673         ///  
    674         /// </summary> 
    675         protected static NameGenerator<Texture> msCompositeMapNameGenerator; 
     680        protected static NameGenerator msBlendTextureGenerator; 
     681        /// <summary> 
     682        ///  
     683        /// </summary> 
     684        protected static NameGenerator msNormalMapNameGenerator; 
     685        /// <summary> 
     686        ///  
     687        /// </summary> 
     688        protected static NameGenerator msLightmapNameGenerator; 
     689        /// <summary> 
     690        ///  
     691        /// </summary> 
     692        protected static NameGenerator msCompositeMapNameGenerator; 
    676693        /// <summary> 
    677694        ///  
     
    710727        /// </summary> 
    711728        protected ulong mLastLODFrame; 
    712  
     729        /// <summary> 
     730        ///  
     731        /// </summary> 
     732        protected Rectangle mLightmapExtraDirtyRect; 
     733        /// <summary> 
     734        ///  
     735        /// </summary> 
     736        protected Terrain[] mNeighbours = new Terrain[(int)NeighbourIndex.Count]; 
     737        /// <summary> 
     738        ///  
     739        /// </summary> 
     740        protected Rectangle mDirtyGeometryRectForNeighbours; 
     741        /// <summary> 
     742        ///  
     743        /// </summary> 
     744        protected Rectangle mDirtyLightmapFromNeighboursRect; 
     745        /// <summary> 
     746        ///  
     747        /// </summary> 
     748        protected static uint mVisibilityFlags; 
     749        /// <summary> 
     750        ///  
     751        /// </summary> 
     752        protected static uint mQueryFlags; 
    713753       IntPtr mHeightDataPtr; 
    714754        IntPtr mDeltaDataPtr; 
     
    717757 
    718758        #region - properties - 
     759        /// <summary> 
     760        /// Get's or set's the visbility flags that terrains will be rendered with 
     761        /// </summary> 
     762        public static uint VisibilityFlags 
     763        { 
     764            set { mVisibilityFlags = value; } 
     765            get { return mVisibilityFlags; } 
     766        } 
     767        /// <summary> 
     768        ///  
     769        /// </summary> 
     770        public static uint QueryFlags 
     771        { 
     772            get { return mQueryFlags; } 
     773            set { mQueryFlags = value; } 
     774        } 
    719775        /// <summary> 
    720776        /// Get's the scenemanager of the terrain 
     
    11581214        { 
    11591215             
    1160             TerrainGlobalOptions.SkirtSize = 10; 
     1216            TerrainGlobalOptions.SkirtSize = 30; 
    11611217            Vector3 normalized = new Vector3(1, -1, 0); 
    11621218            normalized.Normalize(); 
     
    11651221            TerrainGlobalOptions.MaxPixelError = 8.0f; 
    11661222            TerrainGlobalOptions.RenderQueueGroupID = RenderQueueGroupID.Main; 
     1223            TerrainGlobalOptions.VisibilityFlags = 0xFFFFFFFF; 
     1224            TerrainGlobalOptions.QueryFlags = 0xFFFFFFFF; 
    11671225            TerrainGlobalOptions.IsUseRayBoxDistanceCalculation = false; 
    11681226            TerrainGlobalOptions.DefaultMaterialGenerator = new TerrainMaterialGeneratorA(); 
     
    11761234            TerrainGlobalOptions.CompositeMapDistance = 3000; 
    11771235            mLightMapShadowsOnly = true; 
    1178             msBlendTextureGenerator = new NameGenerator<Texture>("TerrBlend"); 
     1236            msBlendTextureGenerator = new NameGenerator("TerrBlend"); 
    11791237            TerrainGlobalOptions.DefaultMaterialGenerator.DebugLevel = 0; 
    11801238            mSceneMgr = sm; 
     
    11821240 
    11831241            mRootNode = sm.RootSceneNode.CreateChildSceneNode(); 
    1184              
     1242            mDirtyGeometryRect = new Rectangle(0, 0, 0, 0); 
     1243            mDirtyDerivedDataRect = new Rectangle(0, 0, 0, 0); 
     1244            mDirtyGeometryRectForNeighbours = new Rectangle(0, 0, 0, 0); 
     1245            mDirtyLightmapFromNeighboursRect = new Rectangle(0, 0, 0, 0); 
    11851246           // mSceneMgr.PreFindVisibleObjects += new FindVisibleObject(PreFindVisibleObjects); 
    11861247            mSceneMgr.PreFindVisibleObjects += new FindVisibleObjectsEvent(PreFindVisibleObjects); 
     
    17841845            if (importData.InputFloat != null) 
    17851846            { 
    1786                 if ( Utility.FloatEqual( importData.InputBias, 0.0f ) && Utility.FloatEqual( importData.InputScale, 1.0f ) ) 
     1847                if (Utils.RealEquals(importData.InputBias, 0.0f) && Utils.RealEquals(importData.InputScale, 1.0f)) 
    17871848                { 
    17881849                    //straigt copy 
     
    18091870            { 
    18101871                Image img = importData.InputImage; 
    1811                 if (img.Width != mSize || img.Height != mSize) 
    1812                      img.Resize(mSize, mSize); 
     1872                //if (img.Width != mSize || img.Height != mSize) 
     1873                //     img.Resize(mSize, mSize); 
    18131874                 
    18141875                // convert image data to floats 
     
    18381899                    } 
    18391900                } 
    1840                 if ( !Utility.FloatEqual( importData.InputBias, 0.0f ) || !Utility.FloatEqual( importData.InputScale, 1.0f ) ) 
     1901                if (!Utils.RealEquals(importData.InputBias, 0.0f) || !Utils.RealEquals(importData.InputScale, 1.0f)) 
    18411902                { 
    18421903                    unsafe 
     
    19692030        { 
    19702031            //clamp 
    1971             x = System.Math.Min(x, (long)mSize - 1L); 
    1972             x = System.Math.Max(x, 0L); 
    1973             y = System.Math.Min(y, (long)mSize - 1L); 
    1974             y = System.Math.Max(y, 0L); 
     2032            x = Math.Min(x, (long)mSize - 1L); 
     2033            x = Math.Max(x, 0L); 
     2034            y = Math.Min(y, (long)mSize - 1L); 
     2035            y = Math.Max(y, 0L); 
    19752036            float ret = 0; 
    19762037            unsafe 
     
    19952056        { 
    19962057            //clamp 
    1997             x = System.Math.Min(x, (long)mSize - 1L); 
    1998             x = System.Math.Max(x, 0L); 
    1999             y = System.Math.Min(y, (long)mSize - 1L); 
    2000             y = System.Math.Max(y, 0L); 
     2058            x = Math.Min(x, (long)mSize - 1L); 
     2059            x = Math.Max(x, 0L); 
     2060            y = Math.Min(y, (long)mSize - 1L); 
     2061            y = Math.Max(y, 0L); 
    20012062            unsafe 
    20022063            { 
     
    21392200                return (IntPtr)(float*)&val[y * mSize + x]; 
    21402201            } 
    2141             //return new IntPtr( mHeightDataPtr + (y * mSize + x)); 
     2202            //return new IntPtr( (float*)mHeightDataPtr + (y * mSize + x)); 
    21422203            //return Memory.PinObject(mHeightData[y * mSize + x]); 
    21432204        } 
     
    26802741#warning Rectangle.Merge is missing! 
    26812742            mDirtyGeometryRect.Merge(rect); 
     2743            mDirtyGeometryRectForNeighbours.Merge(rect); 
    26822744            mDirtyDerivedDataRect.Merge(rect); 
    26832745            mCompositeMapDirtyRect.Merge(rect); 
     
    27602822        { 
    27612823            //CalculateCurrentLod(mSceneMgr.Cameras[0].Viewport); 
    2762             if (mDirtyGeometryRect.Width != 0 && mDirtyGeometryRect.Height != 0) 
     2824            if (mDirtyGeometryRect.Width != 0 && mDirtyGeometryRect.Height != 0 && mDirtyLightmapFromNeighboursRect.Left != 0 && mDirtyLightmapFromNeighboursRect.Right != 0) 
     2825             
    27632826            { 
    27642827                mQuadTree.UpdateVertexData(true, false, mDirtyGeometryRect, false); 
    2765                 mDirtyGeometryRect.Left = mDirtyGeometryRect.Top = 
    2766                     mDirtyGeometryRect.Right = mDirtyGeometryRect.Bottom = 0; 
    2767             } 
     2828                //mDirtyGeometryRect.Left = mDirtyGeometryRect.Top = 
     2829                //    mDirtyGeometryRect.Right = mDirtyGeometryRect.Bottom = 0; 
     2830                mDirtyGeometryRect = new Rectangle(0, 0, 0, 0); 
     2831            } 
     2832 
     2833            //propagate changes 
     2834            NotifyNeighbours(); 
    27682835        } 
    27692836        /// <summary> 
     
    28052872        { 
    28062873            if (mDirtyDerivedDataRect.Width != 0 && mDirtyDerivedDataRect.Height != 0) 
     2874            //if((mDirtyDerivedDataRect.Left != 0 && mDirtyDerivedDataRect.Right != 0 && mDirtyDerivedDataRect.Height != 0 && mDirtyDerivedDataRect.Width != 0) 
     2875            //    || (mDirtyLightmapFromNeighboursRect.Left != 0 && mDirtyLightmapFromNeighboursRect.Right != 0 && mDirtyLightmapFromNeighboursRect.Height != 0 && mDirtyLightmapFromNeighboursRect.Width != 0)) 
    28072876            { 
    28082877                if (mDerivedDataUpdateInProgress) 
     
    28142883                else 
    28152884                { 
    2816                     UpdateDerivedDataImpl(mDirtyDerivedDataRect, synchrounus, typeMask); 
    2817                     mDirtyDerivedDataRect.Left = mDirtyDerivedDataRect.Top = 
    2818                         mDirtyDerivedDataRect.Right = mDirtyDerivedDataRect.Bottom = 0; 
     2885                    UpdateDerivedDataImpl(mDirtyDerivedDataRect, mDirtyLightmapFromNeighboursRect, 
     2886                        synchrounus, typeMask); 
     2887                    //mDirtyDerivedDataRect.Left = mDirtyDerivedDataRect.Top = 
     2888                    //    mDirtyDerivedDataRect.Right = mDirtyDerivedDataRect.Bottom = 0; 
     2889                    mDirtyDerivedDataRect = new Rectangle(0, 0, 0, 0); 
     2890                    mDirtyLightmapFromNeighboursRect = new Rectangle(0, 0, 0, 0); 
    28192891                } 
    28202892            } 
     
    28472919            else if ((ddr.TypeMask & (byte)DERIVED_DATA_LIGHTMAP) == ddr.TypeMask) 
    28482920            { 
    2849                 ddres.LightMapPixelBox = CalculateLightMap(ddr.DirtyRect, ref ddres.LightMapUpdateRect); 
     2921                ddres.LightMapPixelBox = CalculateLightMap(ddr.DirtyRect,ddr.LightmapExtraDirtyRect, ref ddres.LightMapUpdateRect); 
    28502922                ddres.RemainingTypeMask &= (byte)~DERIVED_DATA_LIGHTMAP; 
    28512923            } 
     
    28882960                mDirtyDerivedDataRect = new Rectangle(0, 0, 0, 0); 
    28892961            } 
     2962            Rectangle newLightmapExtraRext = new Rectangle(0,0,0,0); 
     2963            if(ddrs.RemainingTypeMask != 0) 
     2964                newLightmapExtraRext.Merge(ddreq.LightmapExtraDirtyRect); 
     2965            if(mDerivedUpdatePendingMask != 0) 
     2966            { 
     2967                newLightmapExtraRext.Merge(mDirtyLightmapFromNeighboursRect); 
     2968                mDirtyLightmapFromNeighboursRect = new Rectangle(0,0,0,0); 
     2969            } 
    28902970            byte newMask = (byte)(ddrs.RemainingTypeMask | mDerivedUpdatePendingMask); 
    28912971            if (newMask != 0) 
    28922972            { 
    2893                UpdateDerivedDataImpl(newRect, true, newMask); 
     2973               UpdateDerivedDataImpl(newRect, newLightmapExtraRext, true, newMask); 
    28942974            } 
    28952975            else 
     
    29243004                    WidenRectByVector(TerrainGlobalOptions.LightMapDirection, mCompositeMapDirtyRect, ref widenedRect); 
    29253005                    // clamp 
    2926                     widenedRect.Left = System.Math.Max(widenedRect.Left, 0L); 
    2927                     widenedRect.Top = System.Math.Max(widenedRect.Top, 0L); 
    2928                     widenedRect.Right = System.Math.Min(widenedRect.Right, (long)mSize); 
    2929                     widenedRect.Bottom = System.Math.Min(widenedRect.Bottom, (long)mSize); 
     3006                    widenedRect.Left = Math.Max(widenedRect.Left, 0L); 
     3007                    widenedRect.Top = Math.Max(widenedRect.Top, 0L); 
     3008                    widenedRect.Right = Math.Min(widenedRect.Right, (long)mSize); 
     3009                    widenedRect.Bottom = Math.Min(widenedRect.Bottom, (long)mSize); 
    29303010                    mMaterialGenerator.UpdateCompositeMap(this, widenedRect); 
    29313011                } 
     
    29903070            Rectangle clampedRect = new Rectangle(rect); 
    29913071 
    2992             clampedRect.Left = System.Math.Max(0L, clampedRect.Left); 
    2993             clampedRect.Top = System.Math.Max(0L, clampedRect.Top); 
    2994             clampedRect.Right = System.Math.Min((long)mSize, clampedRect.Right); 
    2995             clampedRect.Bottom = System.Math.Min((long)mSize, clampedRect.Bottom); 
     3072            clampedRect.Left = Math.Max(0L, clampedRect.Left); 
     3073            clampedRect.Top = Math.Max(0L, clampedRect.Top); 
     3074            clampedRect.Right = Math.Min((long)mSize, clampedRect.Right); 
     3075            clampedRect.Bottom = Math.Min((long)mSize, clampedRect.Bottom); 
    29963076 
    29973077            Rectangle finalRect = new Rectangle(clampedRect); 
     
    30073087                // vertices at lower LOD 
    30083088                Rectangle widendRect = rect; 
    3009                 widendRect.Left = System.Math.Max(0L, widendRect.Left - step); 
    3010                 widendRect.Top = System.Math.Max(0L, widendRect.Top - step); 
    3011                 widendRect.Right = System.Math.Min((long)mSize, widendRect.Right + step); 
    3012                 widendRect.Bottom = System.Math.Min((long)mSize, widendRect.Bottom + step); 
     3089                widendRect.Left = Math.Max(0L, widendRect.Left - step); 
     3090                widendRect.Top = Math.Max(0L, widendRect.Top - step); 
     3091                widendRect.Right = Math.Min((long)mSize, widendRect.Right + step); 
     3092                widendRect.Bottom = Math.Min((long)mSize, widendRect.Bottom + step); 
    30133093 
    30143094                // keep a merge of the widest 
     
    31563236        { 
    31573237            Rectangle clampedRect = new Rectangle(rect); 
    3158             clampedRect.Left = System.Math.Max(0L, clampedRect.Left); 
    3159             clampedRect.Top = System.Math.Max(0L, clampedRect.Top); 
    3160             clampedRect.Right = System.Math.Min((long)mSize, clampedRect.Right); 
    3161             clampedRect.Bottom = System.Math.Min((long)mSize, clampedRect.Bottom); 
     3238            clampedRect.Left = Math.Max(0L, clampedRect.Left); 
     3239            clampedRect.Top = Math.Max(0L, clampedRect.Top); 
     3240            clampedRect.Right = Math.Min((long)mSize, clampedRect.Right); 
     3241            clampedRect.Bottom = Math.Min((long)mSize, clampedRect.Bottom); 
    31623242 
    31633243            // min/max information 
     
    31673247        } 
    31683248        /// <summary> 
     3249        ///  
     3250        /// </summary> 
     3251        /// <param name="x"></param> 
     3252        /// <param name="y"></param> 
     3253        /// <param name="outpos"></param> 
     3254        public void GetPointFromSelfOrNeighbour(long x, long y, ref Vector3 outpos) 
     3255        { 
     3256            if (x >= 0 && y >= 0 && x < mSize && y < mSize) 
     3257                GetPoint(x, y, ref outpos); 
     3258            else 
     3259            { 
     3260                long nx, ny; 
     3261                NeighbourIndex ni; 
     3262                GetNeighbourPointOverflow(x, y, out ni, out nx, out ny); 
     3263                Terrain neighbour = GetNeighbour(ni); 
     3264                if (neighbour != null) 
     3265                { 
     3266                    Vector3 neighbourPos = Vector3.Zero; 
     3267                    neighbour.GetPoint(nx, ny, ref neighbourPos); 
     3268                    // adjust to make it relative to our position 
     3269                    outpos = neighbourPos + neighbour.Position - Position; 
     3270                } 
     3271                else 
     3272                { 
     3273                    // use our getPoint() after all, just clamp 
     3274                    x = Utility.Min(x, mSize - 1L); 
     3275                    y = Utility.Min(y, mSize - 1L); 
     3276                    x = Utility.Max(x, 0L); 
     3277                    y = Utility.Max(y, 0L); 
     3278                    GetPoint(x, y, ref outpos); 
     3279                } 
     3280 
     3281            } 
     3282        } 
     3283        /// <summary> 
    31693284        /// Calculate (or recalculate) the normals on the terrain 
    31703285        /// </summary> 
     
    31773292            // changes affect neighbours normals 
    31783293            Rectangle widenedRect = new Rectangle( 
    3179                 System.Math.Max(0L, rect.Left - 1L), 
    3180                 System.Math.Max(0L, rect.Top - 1L), 
    3181                 System.Math.Min((long)mSize, rect.Right + 1L), 
    3182                 System.Math.Min((long)mSize, rect.Bottom + 1L)); 
     3294                Math.Max(0L, rect.Left - 1L), 
     3295                Math.Max(0L, rect.Top - 1L), 
     3296                Math.Min((long)mSize, rect.Right + 1L), 
     3297                Math.Min((long)mSize, rect.Bottom + 1L)); 
    31833298 
    31843299            // allocate memory for RGB 
     
    31863301            PixelBox pixbox = new PixelBox((int)widenedRect.Width, (int)widenedRect.Height, 1, PixelFormat.BYTE_RGB, Memory.PinObject(pData)); 
    31873302 
    3188             // sample the 6 triangles intersecting; there are 2 general options 
    3189             //      A           B 
    3190             //  6---7---8   6---7---8 
    3191             //  | \ | \ |   | / | / | 
    3192             //  3---4---5   3---4---5  <---- centre 
    3193             //  | / | / |   | \ | \ | 
    3194             //  0---1---2   0---1---2 
    3195             //  
    3196             //  Option A is where the centre point is on an odd row (ie previous row is even) 
    3197             //  Option B is where the centre point is on an even row (ie previous row is odd) 
    3198             //  Notice how only 6 of the 8 triangles are connected to the centre point,  
    3199             //  however we still include them since it gives a better overall result 
     3303            // Evaluate normal like this 
     3304                    //  3---2---1 
     3305                    //  | \ | / | 
     3306                    //  4---P---0 
     3307                    //  | / | \ | 
     3308                    //  5---6---7 
     3309 
     3310            Plane plane = new Plane(); 
    32003311            for (long y = widenedRect.Top; y < widenedRect.Bottom; ++y) 
    32013312            { 
    32023313                for (long x = widenedRect.Left; x < widenedRect.Right; ++x) 
    32033314                { 
    3204                     // Do them in 4 cells, since if centre point is at the edge then 
    3205                     // we skip cells 
    32063315                    Vector3 cumulativeNormal = Vector3.Zero; 
    3207                     for (long cy = -1; cy < 1; ++cy) 
     3316 
     3317                    // Build points to sample 
     3318                    Vector3 centrePoint = Vector3.Zero; 
     3319                    Vector3[] adjacentPoints = new Vector3[8]; 
     3320                    GetPointFromSelfOrNeighbour(x,y,ref centrePoint); 
     3321                    GetPointFromSelfOrNeighbour(x+1,y,ref adjacentPoints[0]); 
     3322                    GetPointFromSelfOrNeighbour(x+1,y+1,ref adjacentPoints[1]); 
     3323                    GetPointFromSelfOrNeighbour(x,y+1,ref adjacentPoints[2]); 
     3324                    GetPointFromSelfOrNeighbour(x-1,y+1,ref adjacentPoints[3]); 
     3325                    GetPointFromSelfOrNeighbour(x-1,y, ref adjacentPoints[4]); 
     3326                    GetPointFromSelfOrNeighbour(x-1,y-1,ref adjacentPoints[5]); 
     3327                    GetPointFromSelfOrNeighbour(x,y-1,ref adjacentPoints[6]); 
     3328                    GetPointFromSelfOrNeighbour(x+1,y-1, ref adjacentPoints[7]); 
     3329 
     3330                    for (int i = 0; i < 8; ++i) 
    32083331                    { 
    3209                         long cellY = y + cy; 
    3210                         if (cellY < 0 || cellY + 1 >= mSize) 
    3211                             continue; 
    3212                         for (long cx = -1; cx < 1; ++cx) 
    3213                         { 
    3214                             long cellX = x + cx; 
    3215                             if (cellX < 0 || cellX + 1 >= mSize) 
    3216                                 continue; 
    3217                             // cell X/Y is the bottom-left of the cell 
    3218  
    3219                             // get positions 
    3220                             Vector3[] pos = new Vector3[4]; 
    3221                             GetPoint(cellX, cellY, ref pos[0]); 
    3222                             GetPoint(cellX + 1, cellY, ref pos[1]); 
    3223                             GetPoint(cellX, cellY + 1, ref pos[2]); 
    3224                             GetPoint(cellX + 1, cellY + 1, ref pos[3]); 
    3225  
    3226                             bool backwardsTri = (cellY % 2) != 0; 
    3227  
    3228                             Plane p1 = new Plane(), 
    3229                                   p2 = new Plane(); 
    3230  
    3231                             if (backwardsTri) 
    3232                             { 
    3233                                 p1.Redefine(pos[0], pos[3], pos[2]); 
    3234                                 p2.Redefine(pos[0], pos[1], pos[3]); 
    3235                             } 
    3236                             else 
    3237                             { 
    3238                                 p1.Redefine(pos[0], pos[1], pos[2]); 
    3239                                 p2.Redefine(pos[1], pos[3], pos[2]); 
    3240                             } 
    3241  
    3242                             // which ones contribute? All except the 2 at the edge 
    3243                             // right edge for case A, left for case B 
    3244                             cumulativeNormal += p1.Normal; 
    3245                             cumulativeNormal += p2.Normal; 
    3246                         }//cx 
    3247                     }//cy 
     3332                        plane.Redefine(centrePoint, adjacentPoints[i], adjacentPoints[(i + 1) % 8]); 
     3333                        cumulativeNormal += plane.Normal; 
     3334                    } 
    32483335                    // normalise & store normal 
    32493336                    cumulativeNormal.Normalize(); 
     
    32973384                    dstBox.Left = (int)rect.Left; 
    32983385                    dstBox.Right = (int)rect.Bottom; 
    3299                     dstBox.Top = (int)(mSize - rect.Bottom - 1); 
    3300                     dstBox.Bottom = (int)(mSize - rect.Top - 1); 
     3386                    dstBox.Top = (int)(mSize - rect.Bottom); 
     3387                    dstBox.Bottom = (int)(mSize - rect.Top); 
    33013388                    mTerrainNormalMap.GetBuffer().BlitFromMemory(normalsBox, dstBox); 
    33023389                } 
     
    33113398        /// </summary> 
    33123399        /// <param name="rect">Rectangle describing the area of heights that were changed</param> 
     3400        /// <param name="extraTargetRect">extraTargetRect Rectangle describing a target area of the terrain that 
     3401        /// needs to be calculated additionally (e.g. from a neighbour) 
     3402        /// </param> 
    33133403        /// <param name="outFinalRect">Output rectangle describing the area updated in the lightmap</param> 
    33143404        /// <returns> PixelBox full of lighting data (caller responsible for deletion)</returns> 
    3315         public PixelBox CalculateLightMap(Rectangle rect, ref Rectangle outFinalRect) 
     3405        public PixelBox CalculateLightMap(Rectangle rect, Rectangle extraTargetRect, ref Rectangle outFinalRect) 
    33163406        { 
    33173407            // TODO - allow calculation of all lighting, not just shadows 
     
    33263416            Rectangle widenedRect = new Rectangle(); 
    33273417            WidenRectByVector(lightVec,rect,ref widenedRect); 
     3418 
     3419            //merge in the extra area (e.g. from neighbours) 
     3420            widenedRect.Merge(extraTargetRect); 
     3421 
    33283422            // widenedRect now contains terrain point space version of the area we 
    33293423                    // need to calculate. However, we need to calculate in lightmap image space 
     
    33393433            widenedRect = new Rectangle((long)left, (long)top, (long)right, (long)bottom); 
    33403434            //clamp 
    3341             widenedRect.Left = System.Math.Max(0L, widenedRect.Left); 
    3342             widenedRect.Top = System.Math.Max(0L, widenedRect.Top); 
    3343             widenedRect.Right = System.Math.Min((long)mLightmapSizeActual, widenedRect.Right); 
    3344             widenedRect.Bottom = System.Math.Min((long)mLightmapSizeActual, widenedRect.Bottom); 
     3435            widenedRect.Left = Math.Max(0L, widenedRect.Left); 
     3436            widenedRect.Top = Math.Max(0L, widenedRect.Top); 
     3437            widenedRect.Right = Math.Min((long)mLightmapSizeActual, widenedRect.Right); 
     3438            widenedRect.Bottom = Math.Min((long)mLightmapSizeActual, widenedRect.Bottom); 
    33453439 
    33463440            outFinalRect = widenedRect; 
     
    33683462                    // build ray, cast backwards along light direction 
    33693463                    Ray ray = new Ray(wpos, -lightVec); 
    3370  
    3371                     KeyValuePair<bool,Vector3> rayHit = RayIntersects(ray); 
     3464                    //cascade int neighbours when casting, but don't travel further 
     3465                    //than world size 
     3466                    KeyValuePair<bool, Vector3> rayHit = RayIntersects(ray, true, mWorldSize); 
    33723467 
    33733468                    // TODO - cast multiple rays to antialias? 
     
    34223517                    dstBox.Left = (int)rect.Left; 
    34233518                    dstBox.Right = (int)rect.Right; 
    3424                     dstBox.Top = (int)(mLightmapSizeActual - rect.Bottom - 1); 
    3425                     dstBox.Bottom = (int)(mLightmapSizeActual - rect.Top - 1); 
     3519                    dstBox.Top = (int)(mLightmapSizeActual - rect.Bottom); 
     3520                    dstBox.Bottom = (int)(mLightmapSizeActual - rect.Top); 
     3521                    mLightMap.GetBuffer().BlitFromMemory(lightmapBox, dstBox); 
    34263522                } 
    34273523            } 
     
    34473543        /// the heightmap data occurs. 
    34483544        /// </remarks> 
    3449         public KeyValuePair<bool, Vector3> RayIntersects(Ray ray) 
     3545        public KeyValuePair<bool, Vector3> RRayIntersects(Ray ray) 
    34503546        { 
    34513547            KeyValuePair<bool, Vector3> result = new KeyValuePair<bool, Vector3>(); 
     
    35133609 
    35143610            // now check every quad the ray touches 
    3515             int quadX = System.Math.Min(System.Math.Max((int)cur.x, 0), (int)mSize - 2); 
    3516             int quadZ = System.Math.Min(System.Math.Max((int)cur.z, 0), (int)mSize - 2); 
     3611            int quadX = Math.Min(Math.Max((int)cur.x, 0), (int)mSize - 2); 
     3612            int quadZ = Math.Min(Math.Max((int)cur.z, 0), (int)mSize - 2); 
    35173613            int flipX = (rayDirection.x < 0 ? 0 : 1); 
    35183614            int flipZ = (rayDirection.z < 0 ? 0 : 1); 
     
    35323628 
    35333629                // determine next quad to test 
     3630 
    35343631                float xDist = Utility.FloatEqual(ray.Direction.x, 0.0f) ? dummyHighValue : 
    35353632                    (quadX - cur.x + flipX) / rayDirection.x; 
     
    35833680            return result; 
    35843681        } 
     3682        /// <summary> 
     3683        ///  
     3684        /// </summary> 
     3685        /// <param name="ray"></param> 
     3686        /// <returns></returns> 
     3687        public KeyValuePair<bool, Vector3> RayIntersects(Ray ray) 
     3688        { 
     3689            return RayIntersects(ray, false, 0); 
     3690        } 
     3691        /// <summary> 
     3692        ///  
     3693        /// </summary> 
     3694        /// <param name="ray"></param> 
     3695        /// <param name="cascadeToNeighbours"></param> 
     3696        /// <param name="distanceLimit"></param> 
     3697        /// <returns></returns> 
     3698        public KeyValuePair<bool, Vector3> RayIntersects(Ray ray, bool cascadeToNeighbours, float distanceLimit) 
     3699        { 
     3700            KeyValuePair<bool, Vector3> Result; 
     3701            // first step: convert the ray to a local vertex space 
     3702            // we assume terrain to be in the x-z plane, with the [0,0] vertex 
     3703            // at origin and a plane distance of 1 between vertices. 
     3704            // This makes calculations easier. 
     3705            Vector3 rayOrigin = ray.Origin - Position; 
     3706            Vector3 rayDirection = ray.Direction; 
     3707            // change alignment 
     3708            Vector3 tmp; 
     3709            switch (Alignment) 
     3710            { 
     3711                case Alignment.Align_X_Y: 
     3712                    Utility.Swap<float>(ref rayOrigin.y, ref rayOrigin.z); 
     3713                    Utility.Swap<float>(ref rayDirection.y, ref rayDirection.z); 
     3714                    break; 
     3715                case Alignment.Align_Y_Z: 
     3716                    // x = z, z = y, y = -x 
     3717                    tmp.x = rayOrigin.z; 
     3718                    tmp.z = rayOrigin.y; 
     3719                    tmp.y = -rayOrigin.x; 
     3720                    rayOrigin = tmp; 
     3721                    tmp.x = rayDirection.z; 
     3722                    tmp.z = rayDirection.y; 
     3723                    tmp.y = -rayDirection.x; 
     3724                    rayDirection = tmp; 
     3725                    break; 
     3726                case Alignment.Align_X_Z: 
     3727                    // already in X/Z but values increase in -Z 
     3728                    rayOrigin.z = -rayOrigin.z; 
     3729                    rayDirection.z = -rayDirection.z; 
     3730                    break; 
     3731            } 
     3732            // readjust coordinate origin 
     3733            rayOrigin.x += mWorldSize / 2; 
     3734            rayOrigin.z += mWorldSize / 2; 
     3735            // scale down to vertex level 
     3736            rayOrigin.x /= mScale; 
     3737            rayOrigin.z /= mScale; 
     3738            rayDirection.x /= mScale; 
     3739            rayDirection.z /= mScale; 
     3740            rayDirection.Normalize(); 
     3741            Ray localRay = new Ray(rayOrigin, rayDirection); 
     3742 
     3743            // test if the ray actually hits the terrain's bounds 
     3744            Real maxHeight = MaxHeight; 
     3745            Real minHeight = MinHeight; 
     3746 
     3747            AxisAlignedBox aabb = new AxisAlignedBox(new Vector3(0, minHeight, 0), new Vector3(mSize, maxHeight, mSize)); 
     3748            IntersectResult aabbTest = localRay.Intersects(aabb); 
     3749            if (!aabbTest.Hit) 
     3750            { 
     3751                if (cascadeToNeighbours) 
     3752                { 
     3753                    Terrain neighbour = RaySelectNeighbour(ray, distanceLimit); 
     3754                    if (neighbour != null) 
     3755                        return neighbour.RayIntersects(ray, cascadeToNeighbours, distanceLimit); 
     3756                } 
     3757                return new KeyValuePair<bool, Vector3>(false, new Vector3()); 
     3758            } 
     3759            // get intersection point and move inside 
     3760            Vector3 cur = localRay.GetPoint(aabbTest.Distance); 
     3761 
     3762            // now check every quad the ray touches 
     3763            int quadX = Utility.Min(Utility.Max((int)(cur.x), 0), (int)mSize - 2); 
     3764            int quadZ = Utility.Min(Utility.Max((int)(cur.z), 0), (int)mSize - 2); 
     3765            int flipX = (rayDirection.x < 0 ? 0 : 1); 
     3766            int flipZ = (rayDirection.z < 0 ? 0 : 1); 
     3767            int xDir = (rayDirection.x < 0 ? -1 : 1); 
     3768            int zDir = (rayDirection.z < 0 ? -1 : 1); 
     3769 
     3770            Result = new KeyValuePair<bool, Vector3>(true, Vector3.Zero); 
     3771            float dummyHighValue = mSize * 10000; 
     3772 
     3773 
     3774            while (cur.y >= (minHeight - 1e-3) && cur.y <= (maxHeight + 1e-3)) 
     3775            { 
     3776                if (quadX < 0 || quadX >= (int)mSize - 1 || quadZ < 0 || quadZ >= (int)mSize - 1) 
     3777                    break; 
     3778 
     3779                Result = CheckQuadIntersection(quadX, quadZ, localRay); 
     3780                if (Result.Key) 
     3781                    break; 
     3782 
     3783                // determine next quad to test 
     3784                Real xDist = Utility.FloatEqual(rayDirection.x, 0.0f) ? dummyHighValue : 
     3785                    (quadX - cur.x + flipX) / rayDirection.x; 
     3786                Real zDist = Utility.FloatEqual(rayDirection.z, 0.0f) ? dummyHighValue : 
     3787                    (quadZ - cur.z + flipZ) / rayDirection.z; 
     3788                if (xDist < zDist) 
     3789                { 
     3790                    quadX += xDir; 
     3791                    cur += rayDirection * xDist; 
     3792                } 
     3793                else 
     3794                { 
     3795                    quadZ += zDir; 
     3796                    cur += rayDirection * zDist; 
     3797                } 
     3798 
     3799            } 
     3800            Vector3 resVec = Vector3.Zero; 
     3801            if (Result.Key) 
     3802            { 
     3803                // transform the point of intersection back to world space 
     3804                resVec = Result.Value; 
     3805                resVec.x *= mScale; 
     3806                resVec.z *= mScale; 
     3807                resVec.x -= mWorldSize / 2; 
     3808                resVec.z -= mWorldSize / 2; 
     3809                switch (Alignment) 
     3810                { 
     3811                    case Alignment.Align_X_Y: 
     3812                        Utility.Swap<float>(ref resVec.y, ref resVec.z); 
     3813                        break; 
     3814                    case Alignment.Align_Y_Z: 
     3815                        // z = x, y = z, x = -y 
     3816                        tmp.x = -rayOrigin.y; 
     3817                        tmp.y = rayOrigin.z; 
     3818                        tmp.z = rayOrigin.x; 
     3819                        rayOrigin = tmp; 
     3820                        break; 
     3821                    case Alignment.Align_X_Z: 
     3822                        resVec.z = -resVec.z; 
     3823                        break; 
     3824                } 
     3825                resVec += Position; 
     3826            } 
     3827            else if (cascadeToNeighbours) 
     3828            { 
     3829                Terrain neighbour = RaySelectNeighbour(ray, distanceLimit); 
     3830                if (neighbour != null) 
     3831                    Result = neighbour.RayIntersects(ray, cascadeToNeighbours, distanceLimit); 
     3832            } 
     3833            return new KeyValuePair<bool, Vector3>(Result.Key, resVec); 
     3834        } 
    35853835        void PreFindVisibleObjects(SceneManager source, IlluminationRenderStage irs, Viewport v) 
    35863836        { 
     
    36373887            if (mLayerBlendMapList[idx] == null) 
    36383888            { 
    3639                 if (mBlendTextureList.Count < idx / 4) 
     3889                if (mBlendTextureList.Count < (int)(idx / 4)) 
    36403890                    CheckLayers(true); 
    36413891 
     
    37403990        } 
    37413991        /// <summary> 
    3742         /// Widen a rectangular area of terrain to take into account an extrusion vector. 
    3743         /// </summary> 
    3744         /// <param name="vec"> A vector in world space</param> 
    3745         /// <param name="inRec">Input rectangle</param> 
    3746         /// <param name="outRect">Output rectangle</param> 
    3747         public void WidenRectByVector(Vector3 vec, Rectangle inRect, ref Rectangle outRect) 
     3992        ///  
     3993        /// </summary> 
     3994        /// <param name="vec"></param> 
     3995        /// <param name="inRect"></param> 
     3996        /// <param name="minHeight"></param> 
     3997        /// <param name="maxHeight"></param> 
     3998        /// <param name="outRect"></param> 
     3999        public void WidenRectByVector(Vector3 vec, Rectangle inRect, float minHeight, float maxHeight, ref Rectangle outRect) 
    37484000        { 
    37494001            outRect = inRect; 
     
    37554007                case Alignment.Align_X_Y: 
    37564008                    { 
    3757                         p.Redefine(Vector3.UnitZ, new Vector3(0, 0, vec.z < 0.0f ? MinHeight : MaxHeight)); 
     4009                        p.Redefine(Vector3.UnitZ, new Vector3(0, 0, vec.z < 0.0f ? minHeight : maxHeight)); 
    37584010                    } 
    37594011                    break; 
    37604012                case Alignment.Align_X_Z: 
    37614013                    { 
    3762                         p.Redefine(Vector3.UnitY, new Vector3(0, vec.y < 0.0f ? MinHeight : MaxHeight, 0)); 
     4014                        p.Redefine(Vector3.UnitY, new Vector3(0, vec.y < 0.0f ? minHeight : maxHeight, 0)); 
    37634015                    } 
    37644016                    break; 
    37654017                case Alignment.Align_Y_Z: 
    37664018                    { 
    3767                         p.Redefine(Vector3.UnitX, new Vector3(vec.x < 0.0f ? MinHeight : MaxHeight, 0, 0)); 
     4019                        p.Redefine(Vector3.UnitX, new Vector3(vec.x < 0.0f ? minHeight : maxHeight, 0, 0)); 
    37684020                    } 
    37694021                    break; 
     
    37714023            float verticalVal = vec.Dot(p.Normal); 
    37724024 
    3773             if (Utility.FloatEqual(verticalVal, 0.0f)) 
     4025            if (Utils.RealEquals(verticalVal, 0.0f)) 
    37744026                return; 
    37754027 
    37764028            Vector3[] corners = new Vector3[4]; 
    3777             float startHeight = verticalVal < 0.0f ? MaxHeight : MinHeight; 
     4029            float startHeight = verticalVal < 0.0f ? maxHeight : minHeight; 
    37784030            GetPoint(inRect.Left, inRect.Top, startHeight, ref corners[0]); 
    37794031            GetPoint(inRect.Right - 1, inRect.Top, startHeight, ref corners[1]); 
     
    38034055        } 
    38044056        /// <summary> 
     4057        /// Widen a rectangular area of terrain to take into account an extrusion vector. 
     4058        /// </summary> 
     4059        /// <param name="vec"> A vector in world space</param> 
     4060        /// <param name="inRec">Input rectangle</param> 
     4061        /// <param name="outRect">Output rectangle</param> 
     4062        public void WidenRectByVector(Vector3 vec, Rectangle inRect, ref Rectangle outRect) 
     4063        { 
     4064            WidenRectByVector(vec, inRect, MinHeight, MaxHeight, ref outRect); 
     4065        } 
     4066        /// <summary> 
    38054067        /// Free as many resources as possible for optimal run-time memory use. 
    38064068        /// </summary> 
     
    39154177        { 
    39164178            // gets eliminated by either row or column first 
    3917             return System.Math.Min(GetLODLevelWhenVertexEliminated(x), GetLODLevelWhenVertexEliminated(y)); 
     4179            return Math.Min(GetLODLevelWhenVertexEliminated(x), GetLODLevelWhenVertexEliminated(y)); 
    39184180        } 
    39194181        /// <summary> 
     
    39764238        { 
    39774239            //build the two planes belonging to the quad's triangles 
    3978             float v1F = 0; 
    3979             float v2F = 0; 
    3980             float v3F = 0; 
    3981             float v4F = 0; 
    39824240            unsafe 
    39834241            { 
    3984                 float* val = (float*)GetHeightData(x, z); 
    3985                 v1F = *val; 
    3986                 val = (float*)GetHeightData(x+1,z); 
    3987                 v2F = *val; 
    3988                         val = (float*)GetHeightData(x,z+1); 
    3989                 v3F = *val; 
    3990                 val = (float*)GetHeightData(x + 1, z + 1); 
    3991                 v4F = *val; 
    3992             } 
    3993             Vector3 v1 = new Vector3(x, v1F, z), 
    3994                     v2 = new Vector3(x + 1, v2F, z), 
    3995                     v3 = new Vector3(x, v3F, z + 1), 
    3996                     v4 = new Vector3(x + 1, v4F, z + 1); 
    3997  
    3998             Plane p1 = new Plane(), 
    3999                   p2 = new Plane(); 
    4000             bool oddRow = false; 
    4001             if (z % 2 != 0) 
    4002             { 
    4003                 /* odd 
    4004                             3---4 
    4005                             | \ | 
    4006                             1---2 
    4007                             */ 
    4008                 p1.Redefine(v2, v4, v3); 
    4009                 p2.Redefine(v1, v2, v3); 
    4010                 oddRow = true; 
    4011             } 
    4012             else 
    4013             { 
    4014                 /* even 
    4015                             3---4 
    4016                             | / | 
    4017                             1---2 
    4018                             */ 
    4019                 p1.Redefine(v1, v2, v4); 
    4020                 p2.Redefine(v1, v4, v3); 
    4021             } 
    4022             // Test for intersection with the two planes.  
    4023             // Then test that the intersection points are actually 
    4024             // still inside the triangle (with a small error margin) 
    4025             // Also check which triangle it is in 
    4026             IntersectResult planeInt = ray.Intersects(p1); 
    4027             if (planeInt.Hit) 
    4028             { 
    4029                 Vector3 where = ray.GetPoint(planeInt.Distance); 
    4030                 Vector3 rel = where - v1; 
    4031                 if (rel.x >= -0.01f && rel.x <= 1.01f && rel.z >= -0.01f && rel.z <= 1.01f // quad bounds 
    4032                 && ((rel.x >= rel.z && !oddRow) || (rel.x >= (1 - rel.z) && oddRow))) // triangle bounds 
    4033                     return new KeyValuePair<bool, Vector3>(true, where); 
    4034             } 
    4035             planeInt = ray.Intersects(p2); 
    4036             if (planeInt.Hit) 
    4037             { 
    4038                 Vector3 where = ray.GetPoint(planeInt.Distance); 
    4039                 Vector3 rel = where - v1; 
    4040                 if (rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 // quad bounds 
    4041                 && ((rel.x <= rel.z && !oddRow) || (rel.x <= (1 - rel.z) && oddRow))) // triangle bounds 
    4042                     return new KeyValuePair<bool, Vector3>(true, where); 
    4043             } 
    4044  
    4045             return new KeyValuePair<bool, Vector3>(false, Vector3.Zero); 
     4242                //float* val = (float*)GetHeightData(x, z); 
     4243                //v1F = *val; 
     4244                //val = (float*)GetHeightData(x+1,z); 
     4245                //v2F = *val; 
     4246                //val = (float*)GetHeightData(x,z+1); 
     4247                //v3F = *val; 
     4248                //val = (float*)GetHeightData(x + 1, z + 1); 
     4249                //v4F = *val; 
     4250                //float vv = ; 
     4251 
     4252 
     4253                Vector3 v1 = new Vector3(x, *((float*)GetHeightData(x, z)), z), 
     4254                        v2 = new Vector3(x + 1, *((float*)GetHeightData(x + 1, z)), z), 
     4255                        v3 = new Vector3(x, *((float*)GetHeightData(x, z + 1)), z + 1), 
     4256                        v4 = new Vector3(x + 1, *((float*)GetHeightData(x + 1, z + 1)), z + 1); 
     4257 
     4258                Plane p1 = new Plane(), 
     4259                      p2 = new Plane(); 
     4260                bool oddRow = false; 
     4261                if (z % 2 != 0) 
     4262                { 
     4263                    /* odd 
     4264                    3---4 
     4265                    | \ | 
     4266                    1---2 
     4267                    */ 
     4268                    p1.Redefine(v2, v4, v3); 
     4269                    p2.Redefine(v1, v2, v3); 
     4270                    oddRow = true; 
     4271                } 
     4272                else 
     4273                { 
     4274                    /* even 
     4275                    3---4 
     4276                    | / | 
     4277                    1---2 
     4278                    */ 
     4279                    p1.Redefine(v1, v2, v4); 
     4280                    p2.Redefine(v1, v4, v3); 
     4281                } 
     4282                // Test for intersection with the two planes.  
     4283                // Then test that the intersection points are actually 
     4284                // still inside the triangle (with a small error margin) 
     4285                // Also check which triangle it is in 
     4286                IntersectResult planeInt = ray.Intersects(p1); 
     4287                if (planeInt.Hit) 
     4288                { 
     4289                    Vector3 where = ray.GetPoint(planeInt.Distance); 
     4290                    Vector3 rel = where - v1; 
     4291                    if (rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 // quad bounds 
     4292                    && ((rel.x >= rel.z && !oddRow) || (rel.x >= (1 - rel.z) && oddRow))) // triangle bounds 
     4293                        return new KeyValuePair<bool, Vector3>(true, where); 
     4294                } 
     4295                planeInt = ray.Intersects(p2); 
     4296                if (planeInt.Hit) 
     4297                { 
     4298                    Vector3 where = ray.GetPoint(planeInt.Distance); 
     4299                    Vector3 rel = where - v1; 
     4300                    if (rel.x >= -0.01 && rel.x <= 1.01 && rel.z >= -0.01 && rel.z <= 1.01 // quad bounds 
     4301                    && ((rel.x <= rel.z && !oddRow) || (rel.x <= (1 - rel.z) && oddRow))) // triangle bounds 
     4302                        return new KeyValuePair<bool, Vector3>(true, where); 
     4303                } 
     4304 
     4305                return new KeyValuePair<bool, Vector3>(false, Vector3.Zero); 
     4306            } 
    40464307        } 
    40474308        /// <summary> 
     
    41314392                mTreeDepth = mNumLodLevels - mNumLodLevelsPerLeafNode + 1; 
    41324393         */ 
    4133             mNumLodLevelsPerLeafNode = (ushort)(Utility.Log2(mMaxBatchSize - 1) - Utility.Log2(mMinBatchSize - 1) + 1); 
    4134             mNumLodLevels = (ushort)( Utility.Log2( mSize - 1 ) - Utility.Log2( mMinBatchSize - 1 ) + 1 ); 
     4394            mNumLodLevelsPerLeafNode = (ushort)(Utils.Log2(mMaxBatchSize - 1) - Utils.Log2(mMinBatchSize - 1) + 1); 
     4395            mNumLodLevels = (ushort)(Utils.Log2(mSize - 1) - Utils.Log2(mMinBatchSize - 1) + 1); 
    41354396            mTreeDepth = (ushort)(mNumLodLevels - mNumLodLevelsPerLeafNode + 1); 
    41364397 
     
    42904551                // read it (if we've cleared local temp areas) so no WRITE_ONLY 
    42914552                mBlendTextureList.Add((Texture)tmgr.CreateManual( 
    4292                     msBlendTextureGenerator.GetNextUniqueName(), ResourceGroupManager.DefaultResourceGroupName, 
     4553                    msBlendTextureGenerator.Generate()+ Utility.RangeRandom(20,100).ToString(), ResourceGroupManager.DefaultResourceGroupName, 
    42934554                     TextureType.TwoD, mLayerBlendMapSize, mLayerBlendMapSize, 1, 0, fmt, TextureUsage.Static, null)); 
    42944555 
     
    45414802                //create 
    45424803                mCompositeMap = TextureManager.Instance.CreateManual( 
    4543                     mMaterial + "/comp", ResourceGroupManager.DefaultResourceGroupName, 
     4804                    mMaterialName + "/comp", ResourceGroupManager.DefaultResourceGroupName, 
    45444805                    TextureType.TwoD, mCompositeMapSize, mCompositeMapSize, 0, PixelFormat.BYTE_RGBA, TextureUsage.Static); 
    45454806 
     
    47525013        /// <param name="synchronous"></param> 
    47535014        /// <param name="typeMask"></param> 
     5015        protected void UpdateDerivedDataImpl(Rectangle rect,Rectangle lightmapExtraRect, bool synchronous, byte typeMask) 
     5016        { 
     5017            mDerivedDataUpdateInProgress = true; 
     5018            mDerivedUpdatePendingMask = 0; 
     5019 
     5020            DerivedDataRequest req = new DerivedDataRequest(); 
     5021            req.terrain = this; 
     5022            req.DirtyRect = rect; 
     5023            req.LightmapExtraDirtyRect = lightmapExtraRect; 
     5024            req.TypeMask = typeMask; 
     5025            if (!mNormalMapRequired) 
     5026                req.TypeMask = (byte)(req.TypeMask & ~DERIVED_DATA_NORMALS); 
     5027            if (!mLightMapRequired) 
     5028                req.TypeMask = (byte)(req.TypeMask & ~DERIVED_DATA_LIGHTMAP); 
     5029 
     5030            HandleRequest(req); 
     5031 
     5032#warning implement workqueue 
     5033#if false 
     5034            Root::getSingleton().getWorkQueue()->addRequest( 
     5035                        WORKQUEUE_CHANNEL, WORKQUEUE_DERIVED_DATA_REQUEST,  
     5036                        Any(req), 0, synchronous); 
     5037#endif 
     5038        } 
     5039        /// <summary> 
     5040        ///  
     5041        /// </summary> 
     5042        /// <param name="vp"></param> 
     5043        protected void CalculateCurrentLod(Viewport vp) 
     5044        { 
     5045            if (mQuadTree != null) 
     5046            { 
     5047                // calculate error terms 
     5048#warning implement Camera.LodCamera; 
     5049                Camera cam = vp.Camera; 
     5050 
     5051                // W. de Boer 2000 calculation 
     5052                // A = vp_near / abs(vp_top) 
     5053                // A = 1 / tan(fovy*0.5)    (== 1 for fovy=45*2) 
     5054                float A = (float)(1.0f / Math.Tan((double)(cam.FieldOfView * 0.5))); 
     5055                // T = 2 * maxPixelError / vertRes 
     5056                float maxPixelError = 8 * cam.InverseLodBias;//TerrainGlobalOptions.MaxPixelError * cam.InverseLodBias; 
     5057                float T = 2.0f * maxPixelError / (float)vp.ActualHeight; 
     5058 
     5059                // CFactor = A / T 
     5060                float cFactor = A / T; 
     5061                mQuadTree.CalculateCurrentLod(cam, cFactor); 
     5062            } 
     5063        } 
     5064        /// <summary> 
     5065        ///  
     5066        /// </summary> 
     5067        /// <param name="flags"></param> 
     5068        public static void AddQueryFlag(uint flags) 
     5069        { 
     5070            mQueryFlags |= flags; 
     5071        } 
     5072        /// <summary> 
     5073        ///  
     5074        /// </summary> 
     5075        /// <param name="flags"></param> 
     5076        public static void RemoveQueryFlags(uint flags) 
     5077        { 
     5078            mQueryFlags &= ~flags; 
     5079        } 
     5080 
     5081        /// <summary> 
     5082        ///  
     5083        /// </summary> 
     5084        /// <param name="index"></param> 
     5085        /// <returns></returns> 
     5086        public Terrain GetNeighbour(NeighbourIndex index) 
     5087        { 
     5088            return mNeighbours[(int)index]; 
     5089        } 
     5090        /// <summary> 
     5091        ///  
     5092        /// </summary> 
     5093        /// <param name="index"></param> 
     5094        /// <param name="neighbour"></param> 
     5095        public void SetNeighbour(NeighbourIndex index, Terrain neighbour) 
     5096        { 
     5097            SetNeighbour(index, neighbour, false, true); 
     5098        } 
     5099        /// <summary> 
     5100        ///  
     5101        /// </summary> 
     5102        /// <param name="index"></param> 
     5103        /// <param name="neighbour"></param> 
     5104        /// <param name="recalculate"></param> 
     5105        /// <param name="notifyOther"></param> 
     5106        public void SetNeighbour(NeighbourIndex index, Terrain neighbour, bool recalculate, bool notifyOther) 
     5107        { 
     5108            if (mNeighbours[(int)index] != neighbour) 
     5109            { 
     5110                // detach existing 
     5111                if (mNeighbours[(int)index] != null && notifyOther) 
     5112                    mNeighbours[(int)index].SetNeighbour(GetOppositeNeighbour(index), null, false, false); 
     5113 
     5114                mNeighbours[(int)index] = neighbour; 
     5115                if (mNeighbours[(int)index] != null && notifyOther) 
     5116                    mNeighbours[(int)index].SetNeighbour(GetOppositeNeighbour(index), this, recalculate, notifyOther); 
     5117 
     5118                if (recalculate) 
     5119                { 
     5120                    //recalculate, pass OUR edge rect 
     5121                    Rectangle edgerect = new Rectangle(); 
     5122                    GetEdgeRect(index, 2, ref edgerect); 
     5123                    NeighbourModified(index, edgerect, edgerect); 
     5124                } 
     5125            } 
     5126        } 
     5127        /// <summary> 
     5128        ///  
     5129        /// </summary> 
     5130        /// <param name="index"></param> 
     5131        /// <returns></returns> 
     5132        public NeighbourIndex GetOppositeNeighbour(NeighbourIndex index) 
     5133        { 
     5134            int intindex = (int)index; 
     5135            intindex += (int)(NeighbourIndex.Count) / 2; 
     5136            intindex = intindex % (int)NeighbourIndex.Count; 
     5137            return (NeighbourIndex)intindex; 
     5138        } 
     5139        /// <summary> 
     5140        ///  
     5141        /// </summary> 
     5142        public void NotifyNeighbours() 
     5143        { 
     5144            // There are 3 things that can need updating: 
     5145            // Height at edge - match to neighbour (first one to update 'loses' to other since read-only) 
     5146            // Normal at edge - use heights from across boundary too 
     5147            // Shadows across edge 
     5148            // The extent to which these can affect the current tile vary: 
     5149            // Height at edge - only affected by a change at the adjoining edge / corner 
     5150            // Normal at edge - only affected by a change to the 2 rows adjoining the edge / corner 
     5151            // Shadows across edge - possible effect extends based on the projection of the 
     5152            // neighbour AABB along the light direction (worst case scenario) 
     5153            if (!IsNull(mDirtyGeometryRectForNeighbours)) 
     5154            { 
     5155                Rectangle dirtyRect = new Rectangle(mDirtyGeometryRectForNeighbours); 
     5156                mDirtyGeometryRectForNeighbours = new Rectangle(); 
     5157                // calculate light update rectangle 
     5158                Vector3 lightVec = TerrainGlobalOptions.LightMapDirection; 
     5159                Rectangle lightmapRect = new Rectangle(); 
     5160                WidenRectByVector(lightVec, dirtyRect, MinHeight, MaxHeight, ref lightmapRect); 
     5161 
     5162                for (int i = 0; i < (int)NeighbourIndex.Count; ++i) 
     5163                { 
     5164                    NeighbourIndex ni = (NeighbourIndex)(i); 
     5165                    Terrain neighbour = GetNeighbour(ni); 
     5166                    if (neighbour == null) 
     5167                        continue; 
     5168 
     5169                    // Intersect the incoming rectangles with the edge regions related to this neighbour 
     5170                    Rectangle edgeRect = new Rectangle(); 
     5171                    GetEdgeRect(ni, 2, ref edgeRect); 
     5172                    Rectangle heightEdgeRect = edgeRect.Intersect(dirtyRect); 
     5173                    Rectangle lightmapEdgeRect = edgeRect.Intersect(lightmapRect); 
     5174 
     5175                    if (!IsNull(heightEdgeRect) || !IsNull(lightmapRect)) 
     5176                    { 
     5177                        // ok, we have something valid to pass on 
     5178                        Rectangle neighbourHeightEdgeRect = new Rectangle(), neighbourLightmapEdgeRect = new Rectangle(); 
     5179                        if (!IsNull(heightEdgeRect)) 
     5180                            GetNeighbourEdgeRect(ni, heightEdgeRect, ref neighbourHeightEdgeRect); 
     5181                        if (!IsNull(lightmapRect)) 
     5182                            GetNeighbourEdgeRect(ni, lightmapEdgeRect, ref neighbourLightmapEdgeRect); 
     5183 
     5184                        neighbour.NeighbourModified(GetOppositeNeighbour(ni), 
     5185                            neighbourHeightEdgeRect, neighbourLightmapEdgeRect); 
     5186 
     5187                    } 
     5188                } 
     5189            } 
     5190        } 
     5191        private bool IsNull(Rectangle rect) 
     5192        { 
     5193            return rect.Height == 0 && rect.Left == 0 && rect.Right == 0 && rect.Top == 0 && rect.Width == 0 && rect.Bottom == 0; 
     5194        } 
     5195        /// <summary> 
     5196        ///  
     5197        /// </summary> 
     5198        /// <param name="index"></param> 
     5199        /// <param name="edgeRect"></param> 
     5200        /// <param name="shadowRect"></param> 
     5201        public void NeighbourModified(NeighbourIndex index, Rectangle edgerect, Rectangle shadowrect) 
     5202        { 
     5203            // We can safely assume that we would not have been contacted if it wasn't  
     5204            // important 
     5205            Terrain neighbour = GetNeighbour(index); 
     5206            if (neighbour == null) 
     5207                return; // bogus request 
     5208 
     5209            bool updateGeom = false; 
     5210            byte updateDerived = 0; 
     5211 
     5212 
     5213            if (!IsNull(edgerect)) 
     5214            { 
     5215                // update edges; match heights first, then recalculate normals 
     5216                // reduce to just single line / corner 
     5217                Rectangle heightMatchRect = new Rectangle(); 
     5218                GetEdgeRect(index, 1, ref heightMatchRect); 
     5219                heightMatchRect = heightMatchRect.Intersect(edgerect); 
     5220 
     5221                for (long y = heightMatchRect.Top; y < heightMatchRect.Bottom; ++y) 
     5222                { 
     5223                    for (long x = heightMatchRect.Left; x < heightMatchRect.Right; ++x) 
     5224                    { 
     5225                        long nx = 0, ny = 0; 
     5226                        GetNeighbourPoint(index, x, y, ref nx, ref ny); 
     5227                        float neighbourHeight = neighbour.GetHeightAtPoint(nx, ny); 
     5228                        if (!Utility.FloatEqual(neighbourHeight, GetHeightAtPoint(x, y), 1e-3f)) 
     5229                        { 
     5230                            SetHeightAtPoint(x, y, neighbourHeight); 
     5231                            if (!updateGeom) 
     5232                            { 
     5233                                updateGeom = true; 
     5234                                updateDerived |= DERIVED_DATA_ALL; 
     5235                            } 
     5236 
     5237                        } 
     5238                    } 
     5239                } 
     5240                // if we didn't need to update heights, we still need to update normals 
     5241                // because this was called only if neighbor changed 
     5242                if (!updateGeom) 
     5243                { 
     5244                    // ideally we would deal with normal dirty rect separately (as we do with 
     5245                    // lightmaps) because a dirty geom rectangle will actually grow by one  
     5246                    // element in each direction for normals recalculation. However for 
     5247                    // the sake of one row/column it's really not worth it. 
     5248                    mDirtyDerivedDataRect.Merge(edgerect); 
     5249                    updateDerived |= DERIVED_DATA_NORMALS; 
     5250                } 
     5251            } 
     5252 
     5253            if (!IsNull(shadowrect)) 
     5254            { 
     5255                // update shadows 
     5256                // here we need to widen the rect passed in based on the min/max height  
     5257                // of the *neighbour* 
     5258                Vector3 lightVec = TerrainGlobalOptions.LightMapDirection; 
     5259                Rectangle widenedRect = new Rectangle(); 
     5260                WidenRectByVector(lightVec, shadowrect, neighbour.MinHeight, neighbour.MaxHeight, ref widenedRect); 
     5261 
     5262                // set the special-case lightmap dirty rectangle 
     5263                mDirtyLightmapFromNeighboursRect.Merge(widenedRect); 
     5264                updateDerived |= DERIVED_DATA_LIGHTMAP; 
     5265            } 
     5266 
     5267            if (updateGeom) 
     5268                UpdateGeometry(); 
     5269            if (updateDerived != 0) 
     5270                UpdateDerivedData(true, updateDerived); 
     5271        } 
     5272        /// <summary> 
     5273        ///  
     5274        /// </summary> 
     5275        /// <param name="ray"></param> 
     5276        /// <returns></returns> 
     5277        public Terrain RaySelectNeighbour(Ray ray) 
     5278        { 
     5279            return RaySelectNeighbour(ray, 0); 
     5280        } 
     5281        /// <summary> 
     5282        ///  
     5283        /// </summary> 
     5284        /// <param name="ray"></param> 
     5285        /// <param name="distanceLimit"></param> 
     5286        /// <returns></returns> 
     5287        public Terrain RaySelectNeighbour(Ray ray, float distanceLimit) 
     5288        { 
     5289            Real dNear = 0, dFar = 0; 
     5290            Ray localRay = new Ray(ray.Origin - Position, ray.Direction); 
     5291            // Move back half a square - if we're on the edge of the AABB we might 
     5292            // miss the intersection otherwise; it's ok for everywhere else since 
     5293            // we want the far intersection anyway 
     5294            localRay.Origin = localRay.GetPoint(-mWorldSize / mSize * 0.5f); 
     5295            IntersectResult res = new IntersectResult(); 
     5296            if(Utility.Intersects(localRay,AABB,ref dNear,ref dFar)) 
     5297            { 
     5298                // discard out of range 
     5299                if (dFar <= 0 || (distanceLimit != 0 && dFar > distanceLimit)) 
     5300                    return null; 
     5301 
     5302                // we're interested in the exit point 
     5303                // convert to standard form so we can use x/y always 
     5304                Ray terrainRay = new Ray(convertWorldToTerrainAxes(localRay.Origin), 
     5305                    convertWorldToTerrainAxes(localRay.Direction)); 
     5306 
     5307                Vector3 terrainIntersectPos = terrainRay.GetPoint(dFar); 
     5308                Real x = terrainIntersectPos.x; 
     5309                Real y = terrainIntersectPos.y; 
     5310                Real dx = terrainRay.Direction.x; 
     5311                Real dy = terrainRay.Direction.y; 
     5312 
     5313                if (Utility.FloatEqual(Utility.Abs(x), Utility.Abs(y))) 
     5314                { 
     5315                    if (x > 0 && y > 0 && dx > 0 && dy > 0) 
     5316                        return GetNeighbour(NeighbourIndex.NorthEast); 
     5317                    if (x > 0 && y < 0 && dx > 0 && dy < 0) 
     5318                        return GetNeighbour(NeighbourIndex.SouthEast); 
     5319                    if (x < 0 && y > 0 && dx < 0 && dy > 0) 
     5320                        return GetNeighbour(NeighbourIndex.NorthWest); 
     5321                    if (x < 0 && y < 0 && dx < 0 && dy < 0) 
     5322                        return GetNeighbour(NeighbourIndex.SouthWest); 
     5323                } 
     5324                if (x > 0 && x > y && dx > 0) 
     5325                    return GetNeighbour(NeighbourIndex.East); 
     5326                if (x < 0 && x < y && dx < 0) 
     5327                    return GetNeighbour(NeighbourIndex.West); 
     5328                if (y > 0 && y > x && dy > 0) 
     5329                    return GetNeighbour(NeighbourIndex.North); 
     5330                if (y < 0 && y < x && dy < 0) 
     5331                    return GetNeighbour(NeighbourIndex.South); 
     5332 
     5333            } 
     5334            return null; 
     5335        } 
     5336        /// <summary> 
     5337        ///  
     5338        /// </summary> 
     5339        /// <param name="prefix"></param> 
     5340        /// <param name="suffix"></param> 
     5341        public void DumpTextures(string prefix, string suffix) 
     5342        { 
     5343            throw new NotImplementedException(); 
     5344        } 
     5345        /// <summary> 
     5346        ///  
     5347        /// </summary> 
     5348        /// <param name="index"></param> 
     5349        /// <param name="range"></param> 
     5350        /// <param name="outRect"></param> 
     5351        public void GetEdgeRect(NeighbourIndex index, long range, ref Rectangle outRect) 
     5352        { 
     5353            // We make the edge rectangle 2 rows / columns at the edge of the tile 
     5354            // 2 because this copes with normal changes and potentially filtered 
     5355            // shadows. 
     5356            // all right / bottom values are exclusive 
     5357            // terrain origin is bottom-left remember so north is highest value 
     5358 
     5359            // set left/right 
     5360            switch (index) 
     5361            { 
     5362                case NeighbourIndex.East: 
     5363                case NeighbourIndex.NorthEast: 
     5364                case NeighbourIndex.SouthEast: 
     5365                    outRect.Left = mSize - range; 
     5366                    outRect.Right = mSize; 
     5367                    break; 
     5368                case NeighbourIndex.West: 
     5369                case NeighbourIndex.NorthWest: 
     5370                case NeighbourIndex.SouthWest: 
     5371                    outRect.Left = 0; 
     5372                    outRect.Right = range; 
     5373                    break; 
     5374                case NeighbourIndex.North: 
     5375                case NeighbourIndex.South: 
     5376                    outRect.Left = 0; 
     5377                    outRect.Right = mSize; 
     5378                    break; 
     5379            } 
     5380 
     5381            // set top / bottom 
     5382            switch (index) 
     5383            { 
     5384                case NeighbourIndex.North: 
     5385                case NeighbourIndex.NorthEast: 
     5386                case NeighbourIndex.NorthWest: 
     5387                    outRect.Top = mSize - range; 
     5388                    outRect.Bottom = mSize; 
     5389                    break; 
     5390                case NeighbourIndex.South: 
     5391                case NeighbourIndex.SouthEast: 
     5392                case NeighbourIndex.SouthWest: 
     5393                    outRect.Top = 0; 
     5394                    outRect.Bottom = range; 
     5395                    break; 
     5396                case NeighbourIndex.East: 
     5397                case NeighbourIndex.West: 
     5398                    outRect.Top = 0; 
     5399                    outRect.Bottom = mSize; 
     5400                    break; 
     5401            } 
     5402        } 
     5403        /// <summary> 
     5404        ///  
     5405        /// </summary> 
     5406        /// <param name="index"></param> 
     5407        /// <param name="range"></param> 
     5408        /// <param name="outRect"></param> 
     5409        public void GetNeighbourEdgeRect(NeighbourIndex index, Rectangle inRect, ref Rectangle outRect) 
     5410        { 
     5411            System.Diagnostics.Debug.Assert(mSize == GetNeighbour(index).Size, "Neighbour has not the same size as this instance"); 
     5412            // Basically just reflect the rect  
     5413            // remember index is neighbour relationship from OUR perspective so 
     5414            // arrangement is backwards to getEdgeRect 
     5415 
     5416            // left/right 
     5417            switch (index) 
     5418            { 
     5419                case NeighbourIndex.East: 
     5420                case NeighbourIndex.NorthEast: 
     5421                case NeighbourIndex.SouthEast: 
     5422                case NeighbourIndex.West: 
     5423                case NeighbourIndex.NorthWest: 
     5424                case NeighbourIndex.SouthWest: 
     5425                    outRect.Left = mSize - inRect.Right; 
     5426                    outRect.Right = mSize - inRect.Left; 
     5427                    break; 
     5428                default: 
     5429                    outRect.Left = inRect.Left; 
     5430                    outRect.Right = inRect.Right; 
     5431                    break; 
     5432            }; 
     5433 
     5434            // top / bottom 
     5435            switch (index) 
     5436            { 
     5437                case NeighbourIndex.North: 
     5438                case NeighbourIndex.NorthEast: 
     5439                case NeighbourIndex.NorthWest: 
     5440                case NeighbourIndex.South: 
     5441                case NeighbourIndex.SouthWest: 
     5442                case NeighbourIndex.SouthEast: 
     5443                    outRect.Top = mSize - inRect.Bottom; 
     5444                    outRect.Bottom = mSize - inRect.Top; 
     5445                    break; 
     5446                default: 
     5447                    outRect.Top = inRect.Top; 
     5448                    outRect.Bottom = inRect.Bottom; 
     5449                    break; 
     5450            } 
     5451        } 
     5452        /// <summary> 
     5453        ///  
     5454        /// </summary> 
     5455        /// <param name="index"></param> 
     5456        /// <param name="x"></param> 
     5457        /// <param name="y"></param> 
     5458        /// <param name="outX"></param> 
     5459        /// <param name="outY"></param> 
     5460        public void GetNeighbourPoint(NeighbourIndex index, long x, long y, ref long outx, ref long outy) 
     5461        { 
     5462            // Get the index of the point we should be looking at on a neighbour 
     5463            // in order to match up points 
     5464            System.Diagnostics.Debug.Assert(mSize == GetNeighbour(index).Size, "Neighbour has not the same size as this instance"); 
     5465 
     5466            // left/right 
     5467            switch (index) 
     5468            { 
     5469                case NeighbourIndex.East: 
     5470                case NeighbourIndex.NorthEast: 
     5471                case NeighbourIndex.SouthEast: 
     5472                case NeighbourIndex.West: 
     5473                case NeighbourIndex.NorthWest: 
     5474                case NeighbourIndex.SouthWest: 
     5475                    outx = mSize - x - 1; 
     5476                    break; 
     5477                default: 
     5478                    outx = x; 
     5479                    break; 
     5480            } 
     5481 
     5482            // top / bottom 
     5483            switch (index) 
     5484            { 
     5485                case NeighbourIndex.North: 
     5486                case NeighbourIndex.NorthEast: 
     5487                case NeighbourIndex.NorthWest: 
     5488                case NeighbourIndex.South: 
     5489                case NeighbourIndex.SouthWest: 
     5490                case NeighbourIndex.SouthEast: 
     5491                    outy = mSize - y - 1; 
     5492                    break; 
     5493                default: 
     5494                    outy = y; 
     5495                    break; 
     5496            } 
     5497        } 
     5498        /// <summary> 
     5499        ///  
     5500        /// </summary> 
     5501        /// <param name="x"></param> 
     5502        /// <param name="y"></param> 
     5503        /// <param name="outIndex"></param> 
     5504        /// <param name="outX"></param> 
     5505        /// <param name="outY"></param> 
     5506        public void GetNeighbourPointOverflow(long x, long y, out NeighbourIndex outindex, out long outx, out long outy) 
     5507        { 
     5508            outindex = NeighbourIndex.Count; 
     5509            if (x < 0) 
     5510            { 
     5511                outx = x + mSize - 1; 
     5512                if (y < 0) 
     5513                    outindex = NeighbourIndex.SouthWest; 
     5514                else if (y >= mSize) 
     5515                    outindex = NeighbourIndex.NorthWest; 
     5516                else 
     5517                    outindex = NeighbourIndex.West; 
     5518            } 
     5519            else if (x >= mSize) 
     5520            { 
     5521                outx = x - mSize + 1; 
     5522                if (y < 0) 
     5523                    outindex = NeighbourIndex.SouthEast; 
     5524                else if (y >= mSize) 
     5525                    outindex = NeighbourIndex.NorthEast; 
     5526                else 
     5527                    outindex = NeighbourIndex.East; 
     5528            } 
     5529            else 
     5530                outx = x; 
     5531 
     5532            if (y < 0) 
     5533            { 
     5534                outy = y + mSize - 1; 
     5535                if (x >= 0 && x < mSize) 
     5536                    outindex = NeighbourIndex.South; 
     5537            } 
     5538            else if (y >= mSize) 
     5539            { 
     5540                outy = y - mSize + 1; 
     5541                if (x >= 0 && x < mSize) 
     5542                    outindex = NeighbourIndex.North; 
     5543            } 
     5544            else 
     5545                outy = y; 
     5546 
     5547            System.Diagnostics.Debug.Assert(outindex != NeighbourIndex.Count); 
     5548        } 
     5549        /// <summary> 
     5550        /// checks if the given value is power of two. 
     5551        /// </summary> 
     5552        /// <param name="x">the value to check</param> 
     5553        /// <returns>true if the given value is power of two</returns> 
     5554        protected bool IsPowerOfTwo(ulong x) 
     5555        { 
     5556            return (x & (x - 1)) == 0; 
     5557        } 
     5558        #endregion 
     5559    } 
     5560 
     5561        #region - constants - 
     5562        public static uint TERRAIN_CHUNK_ID = StreamSerializer.MakeIdentifier("TERR"); 
     5563        public static ushort TERRAIN_CHUNK_VERSION = 1; 
     5564        public static uint TERRAINLAYERDECLARATION_CHUNK_ID = StreamSerializer.MakeIdentifier("TDCL"); 
     5565        public static ushort TERRAINLAYERDECLARATION_CHUNK_VERSION = 1; 
     5566        public static uint TERRAINLAYERSAMPLER_CHUNK_ID = StreamSerializer.MakeIdentifier("TSAM"); 
     5567        public static ushort TERRAINLAYERSAMPLER_CHUNK_VERSION = 1; 
     5568        public static uint TERRAINLAYERSAMPLERELEMENT_CHUNK_ID = StreamSerializer.MakeIdentifier("TSEL"); 
     5569        public static ushort TERRAINLAYERSAMPLERELEMENT_CHUNK_VERSION = 1; 
     5570        public static uint TERRAINLAYERINSTANCE_CHUNK_ID = StreamSerializer.MakeIdentifier("TLIN"); 
     5571        public static ushort TERRAINLAYERINSTANCE_CHUNK_VERSION = 1; 
     5572        public static uint TERRAINDERIVEDDATA_CHUNK_ID = StreamSerializer.MakeIdentifier("TDDA"); 
     5573        public static ushort TERRAINDERIVEDDATA_CHUNK_VERSION = 1; 
     5574        // since 129^2 is the greatest power we can address in 16-bit index 
     5575        public static ushort TERRAIN_MAX_BATCH_SIZE = 129; 
     5576        //static ushort WORKQUEUE_CHANNEL = Root::MAX_USER_WORKQUEUE_CHANNEL + 10; 
     5577        public static ushort WORKQUEUE_DERIVED_DATA_REQUEST = 1; 
     5578        public static int LOD_MORPH_CUSTOM_PARAM = 1001; 
     5579        public static byte DERIVED_DATA_DELTAS = 1; 
     5580        public static byte DERIVED_DATA_NORMALS = 2; 
     5581        public static byte DERIVED_DATA_LIGHTMAP = 4; 
     5582        // This MUST match the bitwise OR of all the types above with no extra bits! 
     5583        public static byte DERIVED_DATA_ALL = 7; 
     5584        public static ushort WORKQUEUE_CHANNEL; 
     5585         
     5586        #endregion 
     5587 
     5588        #region - fields - 
     5589        /// <summary> 
     5590        ///  
     5591        /// </summary> 
     5592        protected SceneManager mSceneMgr; 
     5593        /// <summary> 
     5594        ///  
     5595        /// </summary> 
     5596        protected SceneNode mRootNode; 
     5597        /// <summary> 
     5598        /// /// The height data (world coords relative to mPos) 
     5599        /// </summary> 
     5600        protected float[] mHeightData; 
     5601        /// <summary> 
     5602        /// /// The delta information defining how a vertex moves before it is removed at a lower LOD 
     5603        /// </summary> 
     5604        protected float[] mDeltaData; 
     5605        /// <summary> 
     5606        ///  
     5607        /// </summary> 
     5608        protected Alignment mAlign; 
     5609        /// <summary> 
     5610        ///  
     5611        /// </summary> 
     5612        protected float mWorldSize; 
     5613        /// <summary> 
     5614        ///  
     5615        /// </summary> 
     5616        protected ushort mSize; 
     5617        /// <summary> 
     5618        ///  
     5619        /// </summary> 
     5620        protected ushort mMaxBatchSize; 
     5621        /// <summary> 
     5622        ///  
     5623        /// </summary> 
     5624        protected ushort mMinBatchSize; 
     5625        /// <summary> 
     5626        ///  
     5627        /// </summary> 
     5628        protected Vector3 mPos; 
     5629        /// <summary> 
     5630        ///  
     5631        /// </summary> 
     5632        protected TerrainQuadTreeNode mQuadTree; 
     5633        /// <summary> 
     5634        ///  
     5635        /// </summary> 
     5636        protected ushort mNumLodLevels; 
     5637        /// <summary> 
     5638        ///  
     5639        /// </summary> 
     5640        protected ushort mNumLodLevelsPerLeafNode; 
     5641        /// <summary> 
     5642        ///  
     5643        /// </summary> 
     5644        protected ushort mTreeDepth; 
     5645        /// <summary> 
     5646        /// Base position in world space, relative to mPos 
     5647        /// </summary> 
     5648        protected float mBase; 
     5649        /// <summary> 
     5650        /// Relationship between one point on the terrain and world size 
     5651        /// </summary> 
     5652        protected float mScale; 
     5653        /// <summary> 
     5654        ///  
     5655        /// </summary> 
     5656        protected TerrainLayerDeclaration mLayerDecl; 
     5657        /// <summary> 
     5658        ///  
     5659        /// </summary> 
     5660        protected List<LayerInstance> mLayers = new List<LayerInstance>(); 
     5661        /// <summary> 
     5662        ///  
     5663        /// </summary> 
     5664        protected FloatList mLayerUVMultiplier = new FloatList(); 
     5665        /// <summary> 
     5666        ///  
     5667        /// </summary> 
     5668        protected float mSkirtSize; 
     5669        /// <summary> 
     5670        ///  
     5671        /// </summary> 
     5672        protected RenderQueueGroupID mRenderQueueGroup; 
     5673        /// <summary> 
     5674        ///  
     5675        /// </summary> 
     5676        protected Rectangle mDirtyGeometryRect; 
     5677        /// <summary> 
     5678        ///  
     5679        /// </summary> 
     5680        protected Rectangle mDirtyDerivedDataRect; 
     5681        /// <summary> 
     5682        ///  
     5683        /// </summary> 
     5684        protected bool mDerivedDataUpdateInProgress; 
     5685        /// <summary> 
     5686        /// if another update is requested while one is already running 
     5687        /// </summary> 
     5688        protected byte mDerivedUpdatePendingMask; 
     5689        /// <summary> 
     5690        ///  
     5691        /// </summary> 
     5692        protected string mMaterialName; 
     5693        /// <summary> 
     5694        ///  
     5695        /// </summary> 
     5696        protected Material mMaterial; 
     5697        /// <summary> 
     5698        ///  
     5699        /// </summary> 
     5700        protected TerrainMaterialGenerator mMaterialGenerator; 
     5701        /// <summary> 
     5702        ///  
     5703        /// </summary> 
     5704        protected long mMaterialGenerationCount; 
     5705        /// <summary> 
     5706        ///  
     5707        /// </summary> 
     5708        protected bool mMaterialDirty; 
     5709        /// <summary> 
     5710        ///  
     5711        /// </summary> 
     5712        protected bool mMaterialParamsDirty; 
     5713        /// <summary> 
     5714        ///  
     5715        /// </summary> 
     5716        protected ushort mLayerBlendMapSize; 
     5717        /// <summary> 
     5718        ///  
     5719        /// </summary> 
     5720        protected ushort mLayerBlendSizeActual; 
     5721        /// <summary> 
     5722        ///  
     5723        /// </summary> 
     5724        protected List<byte> mCpuBlendMapStorage = new List<byte>(); 
     5725        /// <summary> 
     5726        ///  
     5727        /// </summary> 
     5728        protected List<Texture> mBlendTextureList = new List<Texture>(); 
     5729        /// <summary> 
     5730        ///  
     5731        /// </summary> 
     5732        protected List<TerrainLayerBlendMap> mLayerBlendMapList = new List<TerrainLayerBlendMap>(); 
     5733        /// <summary> 
     5734        ///  
     5735        /// </summary> 
     5736        protected ushort mGlobalColorMapSize; 
     5737        /// <summary> 
     5738        ///  
     5739        /// </summary> 
     5740        protected bool mGlobalColorMapEnabled; 
     5741        /// <summary> 
     5742        ///  
     5743        /// </summary> 
     5744        protected Texture mColorMap; 
     5745        /// <summary> 
     5746        ///  
     5747        /// </summary> 
     5748        protected byte[] mCpuColorMapStorage; 
     5749        /// <summary> 
     5750        ///  
     5751        /// </summary> 
     5752        protected ushort mLightmapSize; 
     5753        /// <summary> 
     5754        ///  
     5755        /// </summary> 
     5756        protected ushort mLightmapSizeActual; 
     5757        /// <summary> 
     5758        ///  
     5759        /// </summary> 
     5760        protected Texture mLightMap; 
     5761        /// <summary> 
     5762        ///  
     5763        /// </summary> 
     5764        protected byte[] mCpuLightmapStorage; 
     5765        /// <summary> 
     5766        ///  
     5767        /// </summary> 
     5768        protected ushort mCompositeMapSize; 
     5769        /// <summary> 
     5770        ///  
     5771        /// </summary> 
     5772        protected ushort mCompositeMapSizeActual; 
     5773        /// <summary> 
     5774        ///  
     5775        /// </summary> 
     5776        protected Texture mCompositeMap; 
     5777        /// <summary> 
     5778        ///  
     5779        /// </summary> 
     5780        protected byte[] mCpuCompositeMapStorage; 
     5781        /// <summary> 
     5782        ///  
     5783        /// </summary> 
     5784        protected Rectangle mCompositeMapDirtyRect; 
     5785        /// <summary> 
     5786        ///  
     5787        /// </summary> 
     5788        protected long mCompositeMapUpdateCountdown; 
     5789        /// <summary> 
     5790        ///  
     5791        /// </summary> 
     5792        protected long mLastMillis; 
     5793        /// <summary> 
     5794        /// true if the updates included lightmap changes (widen) 
     5795        /// </summary> 
     5796        protected bool mCompositeMapDirtyRectLightmapUpdate; 
     5797        /// <summary> 
     5798        ///  
     5799        /// </summary> 
     5800        protected Material mCompositeMapMaterial; 
     5801        /// <summary> 
     5802        ///  
     5803        /// </summary> 
     5804        protected static NameGenerator<Texture> msBlendTextureGenerator; 
     5805        /// <summary> 
     5806        ///  
     5807        /// </summary> 
     5808        protected static NameGenerator<Texture> msNormalMapNameGenerator; 
     5809        /// <summary> 
     5810        ///  
     5811        /// </summary> 
     5812        protected static NameGenerator<Texture> msLightmapNameGenerator; 
     5813        /// <summary> 
     5814        ///  
     5815        /// </summary> 
     5816        protected static NameGenerator<Texture> msCompositeMapNameGenerator; 
     5817        /// <summary> 
     5818        ///  
     5819        /// </summary> 
     5820        protected bool mLodMorphRequired; 
     5821        /// <summary> 
     5822        ///  
     5823        /// </summary> 
     5824        protected bool mNormalMapRequired; 
     5825        /// <summary> 
     5826        ///  
     5827        /// </summary> 
     5828        protected bool mLightMapRequired; 
     5829        /// <summary> 
     5830        ///  
     5831        /// </summary> 
     5832        protected bool mLightMapShadowsOnly; 
     5833        /// <summary> 
     5834        ///  
     5835        /// </summary> 
     5836        protected bool mCompositeMapRequired; 
     5837        /// <summary> 
     5838        /// texture storing normals for the whole terrain 
     5839        /// </summary> 
     5840        protected Texture mTerrainNormalMap; 
     5841        /// <summary> 
     5842        /// pending data 
     5843        /// </summary> 
     5844        protected PixelBox mCpuTerrainNormalMap; 
     5845        /// <summary> 
     5846        ///  
     5847        /// </summary> 
     5848        protected Camera mLastLODCamera; 
     5849        /// <summary> 
     5850        ///  
     5851        /// </summary> 
     5852        protected ulong mLastLODFrame; 
     5853 
     5854       IntPtr mHeightDataPtr; 
     5855        IntPtr mDeltaDataPtr; 
     5856 
     5857        #endregion 
     5858 
     5859        #region - properties - 
     5860        /// <summary> 
     5861        /// Get's the scenemanager of the terrain 
     5862        /// </summary> 
     5863        public SceneManager SceneManager 
     5864        { 
     5865            get { return mSceneMgr; } 
     5866        } 
     5867        /// <summary> 
     5868        /// Get a pointer to all the delta data for this terrain. 
     5869        /// </summary> 
     5870        /// <remarks> 
     5871        /// The delta data is a measure at a given vertex of by how much vertically 
     5872        ///     a vertex will have to move to reach the point at which it will be 
     5873        ///     removed in the next lower LOD. 
     5874        /// </remarks> 
     5875        public float[] DeltaData 
     5876        { 
     5877            get { throw new NotImplementedException(); } 
     5878        } 
     5879        /// <summary> 
     5880        /// Get the requested size of the blend maps used to blend between layers 
     5881        ///     for this terrain.  
     5882        ///     Note that where hardware limits this, the actual blend maps may be lower 
     5883        ///     resolution. This option is derived from TerrainGlobalOptions when the 
     5884        ///     terrain is created. 
     5885        /// </summary> 
     5886        public ushort LayerBlendMapSize 
     5887        { 
     5888            get { return mLayerBlendMapSize; } 
     5889        } 
     5890        /// <summary> 
     5891        /// Get'S the AABB (local coords) of the entire terrain 
     5892        /// </summary> 
     5893        public AxisAlignedBox AABB 
     5894        { 
     5895            get 
     5896            { 
     5897                if (mQuadTree == null) 
     5898                    return null; 
     5899                else 
     5900                    return mQuadTree.AABB; 
     5901            } 
     5902        } 
     5903        /// <summary> 
     5904        ///  
     5905        /// </summary> 
     5906        public ushort Size 
     5907        { 
     5908            get { return mSize; } 
     5909        } 
     5910        /// <summary> 
     5911        /// Get the root scene node for the terrain (internal use only) 
     5912        /// </summary> 
     5913        public SceneNode RootSceneNode 
     5914        { 
     5915            get { return mRootNode; } 
     5916        } 
     5917        /// <summary> 
     5918        ///  
     5919        /// </summary> 
     5920        public Alignment Alignment 
     5921        { 
     5922            get { return mAlign; } 
     5923        } 
     5924        /// <summary> 
     5925        ///  
     5926        /// </summary> 
     5927        public ushort MinBatchSize 
     5928        { 
     5929            get { return mMinBatchSize; } 
     5930        } 
     5931        /// <summary> 
     5932        ///  
     5933        /// </summary> 
     5934        public ushort MaxBatchSize 
     5935        { 
     5936            get { return mMaxBatchSize; } 
     5937        } 
     5938        /// <summary> 
     5939        ///  
     5940        /// </summary> 
     5941        public float WorldSize 
     5942        { 
     5943            get { return mWorldSize; } 
     5944        } 
     5945        /// <summary> 
     5946        /// The default size of 'skirts' used to hide terrain cracks 
     5947        ///     (default 10, set for new Terrain using TerrainGlobalOptions) 
     5948        /// </summary> 
     5949        public float SkirtSize 
     5950        { 
     5951            get { return mSkirtSize; } 
     5952        } 
     5953        /// <summary> 
     5954        /// Get's the minimum height of the terrain 
     5955        /// </summary> 
     5956        public float MinHeight 
     5957        { 
     5958            get 
     5959            { 
     5960                if (mQuadTree == null) 
     5961                    return 0; 
     5962                else 
     5963                    return mQuadTree.MinHeight; 
     5964            } 
     5965        } 
     5966        /// <summary> 
     5967        /// Get's the maximum height of the terrain. 
     5968        /// </summary> 
     5969        public float MaxHeight 
     5970        { 
     5971            get 
     5972            { 
     5973                if (mQuadTree == null) 
     5974                    return 0; 
     5975                else 
     5976                    return mQuadTree.MaxHeight; 
     5977            } 
     5978        } 
     5979        /// <summary> 
     5980        /// Get's the bounding radius of the entire terrain 
     5981        /// </summary> 
     5982        public float BoundingRadius 
     5983        { 
     5984            get 
     5985            { 
     5986                if (mQuadTree == null) 
     5987                    return 0; 
     5988                else 
     5989                    return mQuadTree.BoundingRadius; 
     5990            } 
     5991        } 
     5992 
     5993        /// <summary> 
     5994        /// Get's the material being used for the terrain 
     5995        /// </summary> 
     5996        public Material Material 
     5997        { 
     5998            get 
     5999            { 
     6000                if (mMaterial == null || 
     6001                    mMaterialGenerator.ChangeCount != mMaterialGenerationCount || 
     6002                    mMaterialDirty) 
     6003                { 
     6004                    mMaterial = mMaterialGenerator.Generate(this); 
     6005                    mMaterial.Load(); 
     6006                    if (mCompositeMapRequired) 
     6007                    { 
     6008                        mCompositeMapMaterial = mMaterialGenerator.GenerateForCompositeMap(this); 
     6009                        mCompositeMapMaterial.Load(); 
     6010                    } 
     6011                    mMaterialGenerationCount = mMaterialGenerator.ChangeCount; 
     6012                    mMaterialDirty = false; 
     6013                } 
     6014                if (mMaterialParamsDirty) 
     6015                { 
     6016                    mMaterialGenerator.UpdateParams(mMaterial, this); 
     6017                    if (mCompositeMapRequired) 
     6018                        mMaterialGenerator.UpdateParamsForCompositeMap(mCompositeMapMaterial, this); 
     6019                } 
     6020 
     6021                return mMaterial; 
     6022            } 
     6023        } 
     6024        public Material _Material 
     6025        { 
     6026            get 
     6027            { 
     6028                return mMaterial; 
     6029            } 
     6030        } 
     6031        public Material _CompositeMapMaterial 
     6032        { 
     6033            get { return mCompositeMapMaterial; } 
     6034        } 
     6035        /// <summary> 
     6036        /// Get's the material being used for the terrain composite map 
     6037        /// </summary> 
     6038        public Material CompositeMapMaterial 
     6039        { 
     6040            get 
     6041            { 
     6042                // both materials updated together since they change at the same time 
     6043                string matNam = Material.Name; 
     6044                return mCompositeMapMaterial; 
     6045            } 
     6046        } 
     6047        /// <summary> 
     6048        /// Get's the name of the material being used for the terrain 
     6049        /// </summary> 
     6050        public string MaterialName 
     6051        { 
     6052            get { return mMaterialName; } 
     6053        } 
     6054        /// <summary> 
     6055        /// Get a pointer to all the height data for this terrain. 
     6056        /// </summary> 
     6057        /// <remarks> 
     6058        /// The height data is in world coordinates, relative to the position  
     6059        ///     of the terrain. 
     6060        /// </remarks> 
     6061        /// <returns></returns> 
     6062        public float[] HeightData 
     6063        { 
     6064            get { return mHeightData; } 
     6065        } 
     6066        /// <summary> 
     6067        /// Request internal implementation options for the terrain material to use,  
     6068        ///     in this case vertex morphing information.  
     6069        /// The TerrainMaterialGenerator should call this method to specify the  
     6070        /// options it would like to use when creating a material. Not all the data 
     6071        /// is guaranteed to be up to date on return from this method - for example som 
     6072        /// maps may be generated in the background. However, on return from this method 
     6073        /// all the features that are requested will be referenceable by materials, the 
     6074        /// data may just take a few frames to be fully populated. 
     6075        /// </summary> 
     6076        public bool IsMorphRequired 
     6077        { 
     6078            get { return mLodMorphRequired; } 
     6079            set { mLodMorphRequired = value; } 
     6080        } 
     6081        /// <summary> 
     6082        /// Request internal implementation options for the terrain material to use,  
     6083        /// in this case a terrain-wide normal map.  
     6084        /// The TerrainMaterialGenerator should call this method to specify the  
     6085        /// options it would like to use when creating a material. Not all the data 
     6086        /// is guaranteed to be up to date on return from this method - for example some 
     6087        /// maps may be generated in the background. However, on return from this method 
     6088        /// all the features that are requested will be referenceable by materials, the 
     6089        /// data may just take a few frames to be fully populated. 
     6090        /// </summary> 
     6091        public bool NormalMapRequired 
     6092        { 
     6093            set 
     6094            { 
     6095                if (mNormalMapRequired != value) 
     6096                { 
     6097                    mNormalMapRequired = value; 
     6098                    // Check NPOT textures supported. We have to use NPOT textures to map 
     6099                    // texels to vertices directly! 
     6100                    if (!mNormalMapRequired && Root.Instance.RenderSystem 
     6101                        .HardwareCapabilities.HasCapability(Capabilities.NonPowerOf2Textures)) 
     6102                    { 
     6103                        mNormalMapRequired = false; 
     6104                        LogManager.Instance.Write(LogMessageLevel.Critical, false, 
     6105                            "Terrain: Ignoring request for normal map generation since " + 
     6106                            "non-power-of-two texture support is required.", null); 
     6107                    } 
     6108 
     6109                    CreateOrDestroyGPUNormalMap(); 
     6110 
     6111                    // if we enabled, generate normal maps 
     6112                    if (mNormalMapRequired) 
     6113                    { 
     6114                        // update derived data for whole terrain, but just normals 
     6115                        mDirtyDerivedDataRect = new Rectangle(); 
     6116                        mDirtyDerivedDataRect.Left = mDirtyDerivedDataRect.Top = 0; 
     6117                        mDirtyDerivedDataRect.Right = mDirtyDerivedDataRect.Bottom = mSize; 
     6118                        UpdateDerivedData(false, DERIVED_DATA_NORMALS); 
     6119                    } 
     6120                } 
     6121            } 
     6122        } 
     6123 
     6124        /// <summary> 
     6125        /// Get's or set's the world position of the terrain centre 
     6126        /// </summary> 
     6127        public Vector3 Position 
     6128        { 
     6129            get { return mPos; } 
     6130            set 
     6131            { 
     6132                mPos = value; 
     6133                mRootNode.Position = mPos; 
     6134                UpdateBaseScale(); 
     6135            } 
     6136        } 
     6137        /// <summary> 
     6138        /// Request internal implementation options for the terrain material to use,  
     6139        /// in this case a terrain-wide composite map.  
     6140        /// The TerrainMaterialGenerator should call this method to specify the  
     6141        /// options it would like to use when creating a material. Not all the data 
     6142        /// is guaranteed to be up to date on return from this method - for example some 
     6143        /// maps may be generated in the background. However, on return from this method 
     6144        /// all the features that are requested will be referenceable by materials, the 
     6145        /// data may just take a few frames to be fully populated. 
     6146        /// ------------------------------------------------------ 
     6147        /// compositeMap Whether a terrain-wide composite map is needed. A composite 
     6148        /// map is a texture with all of the blending and lighting baked in, such that 
     6149        /// at distance this texture can be used as an approximation of the multi-layer 
     6150        /// blended material. It is actually up to the material generator to render this 
     6151        /// composite map, because obviously precisely what it looks like depends on what 
     6152        /// the main material looks like. For this reason, the composite map is one piece 
     6153        /// of derived terrain data that is always calculated in the render thread, and 
     6154        /// usually on the GPU. It is expected that if this option is requested,  
     6155        /// the material generator will use it to construct distant LOD techniques. 
     6156        /// </summary> 
     6157        public bool CompositeMapRequired 
     6158        { 
     6159            get { throw new NotImplementedException(); } 
     6160            set 
     6161            { 
     6162                if (mCompositeMapRequired != value) 
     6163                { 
     6164                    mCompositeMapRequired = value; 
     6165                    CreateOrDestroyGPUCompositeMap(); 
     6166 
     6167                    // if we enabled, generate normal maps 
     6168                    if (mCompositeMapRequired) 
     6169                    { 
     6170                        mCompositeMapDirtyRect.Left = mCompositeMapDirtyRect.Top = 0; 
     6171                        mCompositeMapDirtyRect.Right = mCompositeMapDirtyRect.Bottom = mSize; 
     6172                        UpdateCompositeMap(); 
     6173                    } 
     6174                } 
     6175            } 
     6176        } 
     6177        /// <summary> 
     6178        /// Get's whether a global color map is enabled on this terrain 
     6179        /// </summary> 
     6180        public bool GlobalColorMapEnabled 
     6181        { 
     6182            get { return mGlobalColorMapEnabled; } 
     6183        } 
     6184        /// <summary> 
     6185        /// Get access to the lightmap, if enabled (as requested by the material generator) 
     6186        /// </summary> 
     6187        public Texture LightMap 
     6188        { 
     6189            get { return mLightMap; } 
     6190        } 
     6191        /// <summary> 
     6192        /// Get the requested size of lightmap for this terrain.  
     6193        /// Note that where hardware limits this, the actual lightmap may be lower 
     6194        /// resolution. This option is derived from TerrainGlobalOptions when the 
     6195        /// terrain is created. 
     6196        /// </summary> 
     6197        public ushort LightMapSize 
     6198        { 
     6199            get { return mLightmapSize; } 
     6200        } 
     6201        /// <summary> 
     6202        /// Get's access to the global colour map, if enabled 
     6203        /// </summary> 
     6204        public Texture GlobalColorMap 
     6205        { 
     6206            get { return mColorMap; } 
     6207        } 
     6208        /// <summary> 
     6209        ///  Get's the size of the global colour map (if used) 
     6210        /// </summary> 
     6211        public ushort GlobalColorMapSize 
     6212        { 
     6213            get { return mGlobalColorMapSize; } 
     6214        } 
     6215        /// <summary> 
     6216        /// Get's the declaration which describes the layers in this terrain. 
     6217        /// </summary> 
     6218        public TerrainLayerDeclaration LayerDeclaration 
     6219        { 
     6220            get { return mLayerDecl; } 
     6221        } 
     6222        /// <summary> 
     6223        /// Get's the (global) normal map texture 
     6224        /// </summary> 
     6225        public Texture TerrainNormalMap 
     6226        { 
     6227            get { return mTerrainNormalMap; } 
     6228        } 
     6229        /// <summary> 
     6230        /// Get access to the composite map, if enabled (as requested by the material generator) 
     6231        /// </summary> 
     6232        public Texture CompositeMap 
     6233        { 
     6234            get { return mCompositeMap; } 
     6235        } 
     6236        /// <summary> 
     6237        /// Get's the top level of the quad tree which is used to divide up the terrain 
     6238        /// </summary> 
     6239        public TerrainQuadTreeNode QuadTree 
     6240        { 
     6241            get { return mQuadTree; } 
     6242        } 
     6243        /// <summary> 
     6244        /// Get the requested size of composite map for this terrain.  
     6245        /// Note that where hardware limits this, the actual texture may be lower 
     6246        /// resolution. This option is derived from TerrainGlobalOptions when the 
     6247        /// terrain is created. 
     6248        /// </summary> 
     6249        public ushort CompositeMapSize 
     6250        { 
     6251            get { return mCompositeMapSize; } 
     6252        } 
     6253        /// <summary> 
     6254        /// Get's the number of layers in this terrain. 
     6255        /// </summary> 
     6256        public byte LayerCount 
     6257        { 
     6258            get { return (byte)mLayers.Count; } 
     6259        } 
     6260        /// <summary> 
     6261        /// Get the total number of LOD levels in the terrain 
     6262        /// </summary> 
     6263        public ushort NumLodLevels 
     6264        { 
     6265            get { return mNumLodLevels; } 
     6266        } 
     6267        /// <summary> 
     6268        /// Get the number of LOD levels in a leaf of the terrain quadtree 
     6269        /// </summary> 
     6270        public ushort LodLevelsPerLeafCount 
     6271        { 
     6272            get { return mNumLodLevelsPerLeafNode; } 
     6273        } 
     6274        /// <summary> 
     6275        /// Get's or set's the render queue group that this terrain will be rendered into 
     6276        /// </summary> 
     6277        /// <remarks>The default is specified in TerrainGlobalOptions</remarks> 
     6278        public RenderQueueGroupID RenderQueueGroupID 
     6279        { 
     6280            get { return mRenderQueueGroup; } 
     6281            set { mRenderQueueGroup = value; } 
     6282        } 
     6283 
     6284        /// <summary> 
     6285        /// Get the maximum number of layers supported with the current options.  
     6286        /// </summary> 
     6287        /// <note>When you change the options requested, this value can change. </note> 
     6288        public byte MaxLayers 
     6289        { 
     6290            get { return mMaterialGenerator.GetMaxLayers(this); } 
     6291        } 
     6292        #endregion 
     6293 
     6294        /// <summary> 
     6295        ///  
     6296        /// </summary> 
     6297        /// <param name="sm"></param> 
     6298        public Terrain(SceneManager sm) 
     6299        { 
     6300             
     6301            TerrainGlobalOptions.SkirtSize = 10; 
     6302            Vector3 normalized = new Vector3(1, -1, 0); 
     6303            normalized.Normalize(); 
     6304            //TerrainGlobalOptions.LightMapDirection = normalized; 
     6305            TerrainGlobalOptions.CastsDynamicShadows = false; 
     6306            TerrainGlobalOptions.MaxPixelError = 8.0f; 
     6307            TerrainGlobalOptions.RenderQueueGroupID = RenderQueueGroupID.Main; 
     6308            TerrainGlobalOptions.IsUseRayBoxDistanceCalculation = false; 
     6309            TerrainGlobalOptions.DefaultMaterialGenerator = new TerrainMaterialGeneratorA(); 
     6310            TerrainGlobalOptions.LayerBlendMapSize = 1024; 
     6311            TerrainGlobalOptions.DefaultLayerTextureWorldSize = 10; 
     6312            TerrainGlobalOptions.DefaultGlobalColorMapSize = 1024; 
     6313            TerrainGlobalOptions.LightMapSize = 1024; 
     6314            TerrainGlobalOptions.CompositeMapSize = 1024; 
     6315            TerrainGlobalOptions.CompositeMapAmbient = sm.AmbientLight; 
     6316            TerrainGlobalOptions.CompositeMapDiffuse = ColorEx.White; 
     6317            TerrainGlobalOptions.CompositeMapDistance = 3000; 
     6318            mLightMapShadowsOnly = true; 
     6319            msBlendTextureGenerator = new NameGenerator<Texture>("TerrBlend"); 
     6320            TerrainGlobalOptions.DefaultMaterialGenerator.DebugLevel = 0; 
     6321            mSceneMgr = sm; 
     6322            mPos = Vector3.Zero; 
     6323 
     6324            mRootNode = sm.RootSceneNode.CreateChildSceneNode(); 
     6325             
     6326           // mSceneMgr.PreFindVisibleObjects += new FindVisibleObject(PreFindVisibleObjects); 
     6327            mSceneMgr.PreFindVisibleObjects += new FindVisibleObjectsEvent(PreFindVisibleObjects); 
     6328            mSceneMgr.PostFindVisibleObjects += new FindVisibleObjectsEvent(mSceneMgr_PostFindVisibleObjects); 
     6329#warning add SceneManager.AddListerner - or simmilar event approach 
     6330#warning implement workerqueue here 
     6331#if false 
     6332            WorkQueue* wq = Root::getSingleton().getWorkQueue(); 
     6333                    wq->addRequestHandler(WORKQUEUE_CHANNEL, this); 
     6334                    wq->addResponseHandler(WORKQUEUE_CHANNEL, this); 
     6335#endif 
     6336            // generate a material name, it's important for the terrain material 
     6337            // name to be consistent & unique no matter what generator is being used 
     6338            // so use our own pointer as identifier, use FashHash rather than just casting 
     6339            // the pointer to a long so we support 64-bit pointers 
     6340            mMaterialName = "AxiomTerrain/" + this.GetHashCode(); 
     6341        } 
     6342 
     6343        void mSceneMgr_PostFindVisibleObjects(SceneManager manager, IlluminationRenderStage stage, Viewport view) 
     6344        { 
     6345 
     6346        } 
     6347        public void Dispose() 
     6348        { 
     6349            mDerivedDataUpdateInProgress = false; 
     6350            WaitForDerivedProcesses(); 
     6351#warning delete workerqueue 
     6352#if false 
     6353WorkQueue* wq = Root::getSingleton().getWorkQueue(); 
     6354                wq->removeRequestHandler(WORKQUEUE_CHANNEL, this); 
     6355                wq->removeResponseHandler(WORKQUEUE_CHANNEL, this);      
     6356#endif 
     6357            FreeTemporaryResources(); 
     6358            FreeGPUResources(); 
     6359            FreeCPUResources(); 
     6360            if (mSceneMgr != null) 
     6361            { 
     6362                mSceneMgr.DestroySceneNode(mRootNode.Name); 
     6363#warning implement scenemanager.removelistener - or simmilar approach 
     6364            } 
     6365        } 
     6366        #region - public functions - 
     6367        /// <summary> 
     6368        /// Convert a position from one space to another with respect to this terrain. 
     6369        /// </summary> 
     6370        /// <param name="inSpace">The space that inPos is expressed as</param> 
     6371        /// <param name="inPos">The incoming position</param> 
     6372        /// <param name="outSpace">The space which outPos should be expressed as</param> 
     6373        /// <param name="outPos"> The output position to be populated</param> 
     6374        public void ConvertPosition(Space inSpace, Vector3 inPos, Space outSpace, ref Vector3 outPos) 
     6375        { 
     6376            ConvertSpace(inSpace, inPos, outSpace, ref outPos, true); 
     6377        } 
     6378        /// <summary> 
     6379        /// Convert a position from one space to another with respect to this terrain. 
     6380        /// </summary> 
     6381        /// <param name="inSpace"> The space that inPos is expressed as</param> 
     6382        /// <param name="inPos">The incoming position</param> 
     6383        /// <param name="outSpace">The space which outPos should be expressed as</param> 
     6384        public Vector3 ConvertPosition(Space inSpace, Vector3 inPos, Space outSpace) 
     6385        { 
     6386            Vector3 ret = Vector3.Zero; 
     6387            ConvertPosition(inSpace, inPos, outSpace, ref ret); 
     6388            return ret; 
     6389        } 
     6390        /// <summary> 
     6391        /// Convert a direction from one space to another with respect to this terrain. 
     6392        /// </summary> 
     6393        /// <param name="inSpace">The space that inDir is expressed as</param> 
     6394        /// <param name="inDir">The incoming direction</param> 
     6395        /// <param name="outSpace">The space which outDir should be expressed as</param> 
     6396        /// <param name="outDir">The output direction to be populated</param> 
     6397        public void ConvertDirection(Space inSpace, Vector3 inDir, Space outSpace, ref Vector3 outDir) 
     6398        { 
     6399            ConvertSpace(inSpace, inDir, outSpace, ref outDir, false); 
     6400        } 
     6401        /// <summary> 
     6402        /// Convert a direction from one space to another with respect to this terrain. 
     6403        /// </summary> 
     6404        /// <param name="inSpace">The space that inDir is expressed as</param> 
     6405        /// <param name="inDir">The incoming direction</param> 
     6406        /// <param name="outSpace">The space which outDir should be expressed as</param> 
     6407        /// <returns>The output direction </returns> 
     6408        public Vector3 ConvertDirection(Space inSpace, Vector3 inDir, Space outSpace) 
     6409        { 
     6410            Vector3 ret = Vector3.Zero; 
     6411            ConvertDirection(inSpace, inDir, outSpace, ref ret); 
     6412            return ret; 
     6413        } 
     6414        /// <summary> 
     6415        /// Save terrain data in native form to a standalone file 
     6416        /// </summary> 
     6417        /// <param name="fileName"></param> 
     6418        /// <note> 
     6419        /// This is a fairly basic way of saving the terrain, to save to a 
     6420        ///     file in the resource system, or to insert the terrain data into a 
     6421        ///     shared file, use the StreamSerialiser form. 
     6422        /// </note> 
     6423        public void Save(string filename) 
     6424        { 
     6425            FileStream fs = null; 
     6426            try 
     6427            { 
     6428                fs = new FileStream(filename, FileMode.OpenOrCreate, FileAccess.ReadWrite); 
     6429            } 
     6430            catch (FileNotFoundException f) 
     6431            { 
     6432                throw new FileNotFoundException(string.Format("Can't open {0} for writing. Terrain.Save()", filename)); 
     6433            } 
     6434            finally 
     6435            { 
     6436                if (fs != null) 
     6437                { 
     6438                    StreamSerializer sr = new StreamSerializer(fs); 
     6439                    Save(sr); 
     6440                } 
     6441            } 
     6442        } 
     6443        /// <summary> 
     6444        /// Save terrain data in native form to a serializing stream 
     6445        /// </summary> 
     6446        /// <param name="stream"></param> 
     6447        public void Save(StreamSerializer stream) 
     6448        { 
     6449            WaitForDerivedProcesses(); 
     6450 
     6451            stream.WriteChunkBegin(TERRAIN_CHUNK_ID, TERRAIN_CHUNK_VERSION); 
     6452 
     6453            byte align = (byte)mAlign; 
     6454            stream.Write(align); 
     6455 
     6456            stream.Write(mSize); 
     6457            stream.Write(mWorldSize); 
     6458            stream.Write(mMaxBatchSize); 
     6459            stream.Write(mMinBatchSize); 
     6460            stream.Write(mPos); 
     6461            for (int i = 0; i < mHeightData.Length; i++) 
     6462            stream.Write(mHeightData[i]); 
     6463 
     6464            //layer declatation 
     6465            stream.WriteChunkBegin(TERRAINLAYERDECLARATION_CHUNK_ID, TERRAINLAYERDECLARATION_CHUNK_VERSION); 
     6466            //samplers 
     6467            byte numSamplers = (byte)mLayerDecl.Samplers.Count; 
     6468            stream.Write(numSamplers); 
     6469            foreach (TerrainLayerSampler sampler in mLayerDecl.Samplers) 
     6470            { 
     6471                stream.WriteChunkBegin(TERRAINLAYERSAMPLER_CHUNK_ID, TERRAINLAYERSAMPLER_CHUNK_VERSION); 
     6472                stream.Write(sampler.Alias); 
     6473                byte pixFmt = (byte)sampler.Format; 
     6474                stream.Write(pixFmt); 
     6475                stream.WriteChunkEnd(TERRAINLAYERSAMPLER_CHUNK_ID); 
     6476            } 
     6477            //elements 
     6478            byte numElems = (byte)mLayerDecl.Elements.Count; 
     6479            stream.Write(numElems); 
     6480            foreach (TerrainLayerSamplerElement elem in mLayerDecl.Elements) 
     6481            { 
     6482                stream.WriteChunkBegin(TERRAINLAYERSAMPLERELEMENT_CHUNK_ID, TERRAINLAYERSAMPLERELEMENT_CHUNK_VERSION); 
     6483                stream.Write(elem.Source); 
     6484                byte sem = (byte)elem.Semantic; 
     6485                stream.Write(sem); 
     6486                stream.Write(elem.ElementStart); 
     6487                stream.Write(elem.ElementCount); 
     6488                stream.WriteChunkEnd(TERRAINLAYERSAMPLERELEMENT_CHUNK_ID); 
     6489            } 
     6490            stream.WriteChunkEnd(TERRAINLAYERDECLARATION_CHUNK_ID); 
     6491            //layers 
     6492            CheckLayers(false); 
     6493            byte numLayers = (byte)mLayers.Count; 
     6494            stream.Write(numLayers); 
     6495            foreach (LayerInstance inst in mLayers) 
     6496            { 
     6497                stream.WriteChunkBegin(TERRAINLAYERINSTANCE_CHUNK_ID, TERRAINLAYERINSTANCE_CHUNK_VERSION); 
     6498                stream.Write(inst.WorldSize); 
     6499                foreach (string t in inst.TextureNames) 
     6500                    stream.Write(t); 
     6501                stream.WriteChunkEnd(TERRAINLAYERINSTANCE_CHUNK_ID); 
     6502            } 
     6503 
     6504            //packed layer blend data 
     6505            if (mCpuBlendMapStorage.Count > 0) 
     6506            { 
     6507                // save from CPU data if it's there, it means GPU data was never created 
     6508                stream.Write(mLayerBlendMapSize); 
     6509 
     6510                // load packed cpu data 
     6511                int numBlendTex = (byte)GetBlendTextureCount(numLayers); 
     6512                for (int i = 0; i < numBlendTex; ++i) 
     6513                { 
     6514                    PixelFormat fmt = GetBlendTextureFormat((byte)i, numLayers); 
     6515                    int channels = PixelUtil.GetNumElemBytes(fmt); 
     6516                    int dataSz = channels * mLayerBlendMapSize * mLayerBlendMapSize; 
     6517                    byte pData = mCpuBlendMapStorage[i]; 
     6518                    stream.Write(pData); 
     6519                    stream.Write(dataSz); 
     6520                } 
     6521            } 
     6522            else 
     6523            { 
     6524                if (mLayerBlendMapSize != mLayerBlendSizeActual) 
     6525                { 
     6526                    LogManager.Instance.Write("WARNING: blend maps were requested at a size larger than was supported " + 
     6527                                        "on this hardware, which means the quality has been degraded"); 
     6528                } 
     6529                stream.Write(mLayerBlendSizeActual); 
     6530                unsafe 
     6531                { 
     6532                    byte[] tmpData = new byte[mLayerBlendSizeActual * mLayerBlendSizeActual * 4]; 
     6533                    fixed (byte* pTmpDataF = tmpData) 
     6534                    { 
     6535                        foreach (Texture tex in mBlendTextureList) 
     6536                        { 
     6537                            PixelBox dst = new PixelBox(mLayerBlendSizeActual, mLayerBlendSizeActual, 1, tex.Format, (IntPtr)pTmpDataF); 
     6538                            tex.GetBuffer().BlitToMemory(dst); 
     6539                            int dataSz = PixelUtil.GetNumElemBytes(tex.Format) 
     6540                            * mLayerBlendSizeActual * mLayerBlendSizeActual; 
     6541                            stream.Write(tmpData); 
     6542                            stream.Write(dataSz); 
     6543                        } 
     6544                    } 
     6545                } 
     6546            } 
     6547 
     6548            //other data 
     6549            //normals 
     6550            stream.ReadChunkBegin(TERRAINDERIVEDDATA_CHUNK_ID, TERRAINDERIVEDDATA_CHUNK_VERSION); 
     6551            stream.Write("normalmap"); 
     6552            stream.Write(mSize); 
     6553            if (mCpuTerrainNormalMap != null) 
     6554            { 
     6555                byte[] aData = new byte[mSize * mSize * 3]; 
     6556                IntPtrToArray(mCpuTerrainNormalMap.Data, ref aData); 
     6557                // save from CPU data if it's there, it means GPU data was never created 
     6558                stream.Write(aData); 
     6559 
     6560            } 
     6561            stream.ReadChunkEnd(TERRAINDERIVEDDATA_CHUNK_ID); 
     6562 
     6563            //color map 
     6564            if (mGlobalColorMapEnabled) 
     6565            { 
     6566                stream.WriteChunkBegin(TERRAINDERIVEDDATA_CHUNK_ID, TERRAINDERIVEDDATA_CHUNK_VERSION); 
     6567                stream.Write("colormap"); 
     6568                stream.Write(mSize); 
     6569                if (mCpuBlendMapStorage != null) 
     6570                { 
     6571                    // save from CPU data if it's there, it means GPU data was never created 
     6572                    stream.Write(mCpuColorMapStorage); 
     6573                } 
     6574                else 
     6575                { 
     6576                    unsafe 
     6577                    { 
     6578                        byte[] aData = new byte[mGlobalColorMapSize * mGlobalColorMapSize * 3]; 
     6579                        fixed (byte* pDataF = aData) 
     6580                        { 
     6581                            PixelBox dst = new PixelBox(mGlobalColorMapSize, mGlobalColorMapSize, 1, PixelFormat.BYTE_RGB, (IntPtr)pDataF); 
     6582                            mColorMap.GetBuffer().BlitToMemory(dst); 
     6583                            stream.Write(aData); 
     6584                        } 
     6585                    } 
     6586                } 
     6587                stream.WriteChunkEnd(TERRAINDERIVEDDATA_CHUNK_ID); 
     6588            } 
     6589 
     6590            //ligthmap 
     6591            if (mLightMapRequired) 
     6592            { 
     6593                stream.WriteChunkBegin(TERRAINDERIVEDDATA_CHUNK_ID, TERRAINDERIVEDDATA_CHUNK_VERSION); 
     6594                stream.Write("lightmap"); 
     6595                stream.Write(mLightmapSize); 
     6596                if (mCpuLightmapStorage != null) 
     6597                { 
     6598                    // save from CPU data if it's there, it means GPU data was never created 
     6599                    stream.Write(mCpuLightmapStorage); 
     6600                } 
     6601                else 
     6602                { 
     6603                    unsafe 
     6604                    { 
     6605                        byte[] aData = new byte[mLightmapSize * mLightmapSize]; 
     6606                        fixed (byte* pDataF = aData) 
     6607                        { 
     6608                            PixelBox dst = new PixelBox(mLightmapSize, mLightmapSize, 1, PixelFormat.L8, (IntPtr)pDataF); 
     6609                            mLightMap.GetBuffer().BlitToMemory(dst); 
     6610                            stream.Write(aData); 
     6611                        } 
     6612                    } 
     6613                } 
     6614                stream.WriteChunkEnd(TERRAIN_CHUNK_ID); 
     6615            } 
     6616 
     6617            // composite map 
     6618            if (mCompositeMapRequired) 
     6619            { 
     6620                stream.WriteChunkBegin(TERRAINDERIVEDDATA_CHUNK_ID, TERRAINDERIVEDDATA_CHUNK_VERSION); 
     6621                stream.Write("compositemap"); 
     6622                stream.Write(mCompositeMapSize); 
     6623                if (mCpuCompositeMapStorage != null) 
     6624                { 
     6625                    // save from CPU data if it's there, it means GPU data was never created 
     6626                    stream.Write(mCpuCompositeMapStorage); 
     6627                } 
     6628                else 
     6629                { 
     6630                    unsafe 
     6631                    { 
     6632                        // composite map is 4 channel, 3x diffuse, 1x specular mask 
     6633                        byte[] aData = new byte[mCompositeMapSize * mCompositeMapSize * 4]; 
     6634                        fixed (byte* pDataF = aData) 
     6635                        { 
     6636                            PixelBox dst = new PixelBox(mCompositeMapSize, mCompositeMapSize, 1, PixelFormat.BYTE_RGB, (IntPtr)pDataF); 
     6637                            mCompositeMap.GetBuffer().BlitToMemory(dst); 
     6638                            stream.Write(aData); 
     6639                        } 
     6640                    } 
     6641                } 
     6642                stream.WriteChunkEnd(TERRAINDERIVEDDATA_CHUNK_ID); 
     6643            } 
     6644 
     6645            //TODO - write deltas 
     6646 
     6647            stream.WriteChunkEnd(TERRAIN_CHUNK_ID); 
     6648        } 
     6649        /// <summary> 
     6650        /// Prepare the terrain from a standalone file. 
     6651        /// </summary> 
     6652        /// <param name="fileName"></param> 
     6653        /// <note> 
     6654        /// This is safe to do in a background thread as it creates no GPU resources. 
     6655        /// It reads data from a native terrain data chunk. For more advanced uses,  
     6656        /// such as loading from a shared file, use the StreamSerialiser form. 
     6657        /// </note> 
     6658        public bool Prepare(string fileName) 
     6659        { 
     6660            FileStream stream = null; 
     6661            if (ResourceGroupManager.Instance.ResourceExists( 
     6662                ResourceGroupManager.DefaultResourceGroupName, fileName)) 
     6663            { 
     6664#warning check me! 
     6665                stream = (FileStream)ResourceGroupManager.Instance.OpenResource( 
     6666                    fileName, ResourceGroupManager.DefaultResourceGroupName); 
     6667            } 
     6668            else 
     6669            { 
     6670                // try direct 
     6671                if (File.Exists(fileName)) 
     6672                { 
     6673                    stream = File.Open(fileName, FileMode.Open); 
     6674                } 
     6675                else 
     6676                { 
     6677                    throw new FileNotFoundException(string.Format("'{0}' not found!", fileName)); 
     6678                } </