Beispiel #1
0
        /// <summary>
        ///
        /// </summary>
        public void Update()
        {
            //If no camera has been set, then return without doing anything
            if (mSceneCam == null)
            {
                return;
            }
            //Calculate time since last update
            long deltaTime = 0, tmp = 0;

            tmp       = mTimer.Milliseconds;
            deltaTime = tmp - mLastTime;
            mLastTime = tmp;

            //Get camera position and speed
            Vector3 camPos   = ConvertToLocal(mSceneCam.DerivedPosition);
            Vector3 camSpeed = Vector3.Zero;

            if (deltaTime == 0)
            {
                camSpeed = new Vector3(0, 0, 0);
            }
            else
            {
                camSpeed = (camPos - mOldCamPos) / deltaTime;
            }

            mOldCamPos = camPos;

            if (mPageLoader != null)
            {
                //Update the PageLoader
                mPageLoader.FrameUpdate();
                //Update all the page managers
                bool enableCache            = true;
                GeometryPageManager prevMgr = null;
                foreach (GeometryPageManager it in mMangerList)
                {
                    GeometryPageManager mgr = it;
                    mgr.Update(deltaTime, camPos, camSpeed, enableCache, prevMgr);
                    prevMgr = mgr;
                }
            }

            //Update misc. subsystems
            StaticBillboardSet.UpdateAll(ConvertToLocal(Camera.DerivedDirection));
        }
Beispiel #2
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="mgr"></param>
        /// <param name="maxRange"></param>
        /// <param name="transitionLength"></param>
        protected void AddDetailLevel(GeometryPageManager mgr, float maxRange, float transitionLength)
        {
            //Calculate the near range
            float minRange = 0;

            if (mMangerList.Count > 0)
            {
                GeometryPageManager lastMgr = mMangerList[mMangerList.Count - 1];
                minRange = lastMgr.FarRange;
            }
            //Error check
            if (maxRange <= minRange)
            {
                throw new Exception("Closer detail levels must be added before farther ones");
            }

            //Setup the new manager
            mgr.NearRange  = minRange;
            mgr.FarRange   = maxRange;
            mgr.Transition = transitionLength;
            mMangerList.Add(mgr);
        }
Beispiel #3
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="maxRange"></param>
        /// <param name="transitionLength"></param>
        /// <returns></returns>
        public GeometryPageManager AddDetailLevel <T>(float maxRange, float transitionLength) where T : GeometryPage
        {
            //Create a new page manager
            GeometryPageManager mgr = new GeometryPageManager(this);

            //If vertex shaders aren't supported, don't use transitions
            Root  root        = Root.Singleton;
            float transLength = transitionLength;

            if (!root.RenderSystem.Capabilities.HasCapability(MogreLibGraphics.Capabilities.VertexPrograms))
            {
                transLength = 0;
            }

            //Add it to the list (also initializing maximum viewing distance)
            AddDetailLevel(mgr, maxRange, transLength);

            //And initialize the paged (dependent on maximum viewing distance)
            mgr.InitPages <T>(Bounds);

            return(mgr);
        }
        /// <summary>
        ///
        /// </summary>
        /// <param name="deltaTime"></param>
        /// <param name="campos"></param>
        /// <param name="camSpeed"></param>
        /// <param name="enableCache"></param>
        /// <param name="prevManager"></param>
        internal void Update(long deltaTime, Vector3 campos, Vector3 camSpeed, bool enableCache, GeometryPageManager prevManager)
        {
            //-- Cache new geometry pages --

            //Cache 1 page ahead of the view ranges
            float cacheDist   = mFarTransDist + mMainGeom.PageSize;
            float cacheDistSq = cacheDist * cacheDist;

            //First calculate the general area where the pages will be processed
            // 0,0 is the left top corner of the bounding box
            int x1 = (int)System.Math.Floor(
                ((campos.x - cacheDist) - mGridBounds.Left) / mMainGeom.PageSize);

            int x2 = (int)System.Math.Floor(
                ((campos.x + cacheDist) - mGridBounds.Left) / mMainGeom.PageSize);

            int z1 = (int)System.Math.Floor(
                ((campos.z - cacheDist) - mGridBounds.Top) / mMainGeom.PageSize);

            int z2 = (int)System.Math.Floor(
                ((campos.z + cacheDist) - mGridBounds.Top) / mMainGeom.PageSize);

            if (mScrollBuffer != null)
            {
                //Check if the page grid needs to be scrolled
                int shiftX = 0, shiftZ = 0;
                if (x1 < 0)
                {
                    shiftX = x1;
                }
                else if (x2 >= mGeomGridX - 1)
                {
                    shiftX = x2 - (mGeomGridX - 1);
                }
                if (z1 < 0)
                {
                    shiftZ = z1;
                }
                else if (z2 >= mGeomGridZ - 1)
                {
                    shiftZ = z2 - (mGeomGridZ - 1);
                }
                if (shiftX != 0 || shiftZ != 0)
                {
                    //Scroll grid
                    ScrollGridPages(shiftX, shiftZ);
                    //Update grid bounds and processing area
                    mGridBounds.Left   += shiftX * mMainGeom.PageSize;
                    mGridBounds.Right  += shiftX * mMainGeom.PageSize;
                    mGridBounds.Top    += shiftZ * mMainGeom.PageSize;
                    mGridBounds.Bottom += shiftZ * mMainGeom.PageSize;
                    x1 -= shiftX; x2 -= shiftX;
                    z1 -= shiftZ; z2 -= shiftZ;
                }
            }
            else
            {
                // make sure that values are inbounds
                if (x2 >= mGeomGridX)
                {
                    x2 = mGeomGridX - 1;
                }
                if (z2 >= mGeomGridZ)
                {
                    z2 = mGeomGridZ - 1;
                }

                if (x1 < 0)
                {
                    x1 = 0;
                }
                if (z1 < 0)
                {
                    z1 = 0;
                }
            }

            //Now, in that general area, find what pages are within the cacheDist radius
            //Pages within the cacheDist radius will be added to the pending block list
            //to be loaded later, and pages within farDist will be loaded immediately.
            for (int x = x1; x <= x2; ++x)
            {
                for (int z = z1; z <= z2; ++z)
                {
                    GeometryPage blk    = GetGridPage(x, z);
                    float        dx     = campos.x - blk.CenterPoint.x;
                    float        dz     = campos.z - blk.CenterPoint.z;
                    float        distSq = dx * dx + dz * dz;

                    //If the page is in the cache radius...
                    if (distSq <= cacheDistSq)
                    {
                        //If the block hasn't been loaded yet, it should be
                        if (!blk.IsLoaded)
                        {
                            //Test if the block's distance is between nearDist and farDist
                            if (distSq >= mNearDistSq && distSq < mFarTransDistSq)
                            {
                                //If so, load the geometry immediately
                                LoadPage(blk);
                                mLoadedList.Add(blk);
                                if (blk.IsPending)
                                {
                                    mPendingList.Remove(blk);
                                    blk.IsPending = false;
                                }
                            }
                            else
                            {
                                //Otherwise, add it to the pending geometry list (if not already)
                                //Pages in then pending list will be loaded later (see below)
                                if (!blk.IsPending)
                                {
                                    mPendingList.Add(blk);
                                    blk.IsPending = true;
                                }
                            }
                        }
                        else
                        {
                            //Set the inactive time to 0 (since the page is active). This
                            //must be done in order to keep it from expiring (and deleted).
                            //This way, blocks not in the cache radius won't have their
                            //inactivity clock reset, and they will expire in a few seconds.
                            blk.InactiveTime = 0;
                        }
                    }
                }
            }//end for

            //Calculate cache speeds based on camera speed. This is important to keep the cache
            //process running smooth, because if the cache can't keep up with the camera, the
            //immediately visible pages will be forced to load instantly, which can cause
            //noticeable and sudden stuttering. The cache system results in smoother performance
            //because it smooths the loading tasks out across multiple frames. For example,
            //instead of loading 10+ blocks every 2 seconds, the cache would load 1 block every
            //200 milliseconds.
            float speed         = MogreLibMath.Utility.Sqrt(camSpeed.x * camSpeed.x + camSpeed.z * camSpeed.z);
            long  cacheInterval = 0;

            if (speed == 0)
            {
                cacheInterval = mMaxCacheInterval;
            }
            else
            {
                cacheInterval = (long)((mMainGeom.PageSize * 0.8f) / (speed * mPendingList.Count));
                if (cacheInterval > mMaxCacheInterval)
                {
                    cacheInterval = mMaxCacheInterval;
                }
            }

            int geomPageBegin = 0;
            int geomPageEnd   = mPendingList.Count - 1;
            //GeometryPage i1 = null;
            GeometryPage i2 = null;

            //Now load a single geometry page periodically, based on the cacheInterval
            mCacheTimer += deltaTime;
            if (mCacheTimer >= cacheInterval && enableCache)
            {
                //Find a block to be loaded from the pending list
                //i1 = mPendingList[geomPageBegin];
                // i2 = mPendingList[geomPageEnd];
                //while (i1 != i2)
                GeometryPage[] pend = mPendingList.ToArray();
                foreach (GeometryPage i1 in pend)
                {
                    GeometryPage blk = i1;
                    //Remove it from the pending list
                    mPendingList.Remove(i1);
                    //if (geomPageBegin < mPendingList.Count)
                    //    i1 = mPendingList[geomPageBegin++];
                    blk.IsPending = false;
                    //If it's within the geometry cache radius, load it and break out of the loop
                    float dx     = campos.x - blk.CenterPoint.x;
                    float dz     = campos.z - blk.CenterPoint.z;
                    float distSq = dx * dx + dz * dz;
                    if (distSq <= cacheDistSq)
                    {
                        LoadPage(blk);
                        mLoadedList.Add(blk);
                        blk         = mLoadedList[mLoadedList.Count - 1];
                        enableCache = false;
                        break;
                    }
                    //Otherwise this will keep looping until an unloaded page is found
                }

                mCacheTimer = 0;
            }

            //-- Update existing geometry and impostors --

            //Loop through each loaded geometry block
            int loadPageBegin = 0;
            int loadPageEnd   = mLoadedList.Count - 1;

            //i1 = mLoadedList[loadPageBegin];
            // i2 = mLoadedList[loadPageEnd];

            float halfPageSize = mMainGeom.PageSize * 0.5f;

            //while (i1 != i2)
            GeometryPage[] load = mLoadedList.ToArray();
            foreach (GeometryPage i1 in load)
            {
                GeometryPage blk = i1;
                //If the geometry has expired...
                if (blk.InactiveTime >= mInactivePageLife)
                {
                    //Unload it
                    UnLoadPage(blk);
                    mLoadedList.Remove(i1);
                    //if (loadPageBegin < mLoadedList.Count)
                    //    i1 = mLoadedList[loadPageBegin];
                }
                else
                {//Update it's visibility/fade status based on it's distance from the camera
                    bool  visible = false;
                    float dx      = campos.x - blk.CenterPoint.x;
                    float dz      = campos.z - blk.CenterPoint.z;
                    float distSq  = dx * dx + dz * dz;

                    float overlap = 0, tmp = 0;
                    tmp = blk.BoundingBox.Maximum.x - halfPageSize;
                    if (tmp > overlap)
                    {
                        overlap = tmp;
                    }
                    tmp = blk.BoundingBox.Maximum.z - halfPageSize;
                    if (tmp > overlap)
                    {
                        overlap = tmp;
                    }
                    tmp = blk.BoundingBox.Minimum.x + halfPageSize;
                    if (tmp > overlap)
                    {
                        overlap = tmp;
                    }
                    tmp = blk.BoundingBox.Minimum.z + halfPageSize;
                    if (tmp > overlap)
                    {
                        overlap = tmp;
                    }

                    float pageLengthSq = MogreLibMath.Utility.Sqr((mMainGeom.PageSize + overlap) * 1.41421356f);
                    if (distSq + pageLengthSq >= mNearDistSq && distSq - pageLengthSq < mFarTransDistSq)
                    {
                        //Fade the page when transitioning
                        bool  enable   = false;
                        float fadeNear = 0;
                        float fadeFar  = 0;

                        if (mFadeEnabled && distSq + pageLengthSq >= mFarDistSq)
                        {
                            //Fade in
                            visible  = true;
                            enable   = true;
                            fadeNear = mFarDist;
                            fadeFar  = mFarTransDist;
                        }
                        else if (prevManager != null && prevManager.mFadeEnabled && (distSq - pageLengthSq < prevManager.mFarTransDistSq))
                        {
                            //Fade out
                            visible  = true;
                            enable   = true;
                            fadeNear = prevManager.mFarDist + (prevManager.mFarTransDist - prevManager.mFarDist) * 0.5f;//This causes geometry to fade out faster than it fades in, avoiding a state where a transition appears semitransparent
                            fadeFar  = prevManager.mFarDist;
                        }

                        //apply fade settings
                        if (enable != blk.IsFadeEnabled)
                        {
                            blk.SetFade(enable, fadeNear, fadeFar);
                            blk.IsFadeEnabled = enable;
                        }
                    }
                    //Non-fade visibility
                    if (distSq > mNearDistSq && distSq < mFarDistSq)
                    {
                        visible = true;
                    }
                    //Update visibility
                    if (visible)
                    {
                        //Show the page if it isn't visible
                        if (!blk.IsVisible)
                        {
                            blk.IsVisible = true;
                        }
                    }
                    else
                    {
                        //Hide the page if it's not already
                        if (blk.IsVisible)
                        {
                            blk.IsVisible = false;
                        }
                    }

                    //And update it
                    blk.Update();
                    //if (loadPageBegin < mLoadedList.Count)
                    //    i1 = mLoadedList[loadPageBegin++];
                }
                //Increment the inactivity timer for the geometry
                blk.InactiveTime += deltaTime;
            }
        }