Exemplo n.º 1
0
        /// <summary>
        /// Updates any neccesary clip levels to be centered on the specified position. If you're using split-screen
        /// or any complex post-processing effects use the Center property rather than directly calling this method.
        /// That will allow the clip map to recenter during UpdateAnimation rather than immediately update. Otherwise
        /// you risk corrupting your render targets on platforms such as XBox that don't support multiple render
        /// targets.
        /// </summary>
        /// <param name="position">The new clip center of the clip map.</param>
        public void Recenter(Vector2 position)
        {
            #if DEBUG
            Profiler.Instance.StartBlock("ClipMap.Recenter");
            #endif

            _center = position;
            _needsRecenter = false;

            // update our budget texel upload budget
            _maxTexelUploadPerRecenter = _clipMapSize * _clipMapSize;

            Assert.Fatal((int)TorqueUtil.GetLog2(_clipMapSize) % 1f == 0f, "ClipMap.Recenter - Requires a power of 2 clipmap size.");

            // do toroidal updates on each entry of the clipstack
            // calculate the new texel at most detailed level.
            Vector2 texelCenterF = position * (float)_clipMapSize * _clipLevels[0].ScaleFactor;
            Point texelCenter = new Point((int)Math.Floor(texelCenterF.X), (int)Math.Floor(texelCenterF.Y));

            // Note how many we were at so we can cut off at the right time.
            int lastTexelsUpdated = _texelsUpdated;

            // create a list to store desired data in
            List<RectangleI> desiredData;

            // For each texture...
            for (int i = _clipStackDepth - 2; i >= 0; i--)
            {
                ClipStackEntry stackEntry = _clipLevels[i];

                // calculate new center point for this texture
                texelCenterF = position * (float)_clipMapSize * stackEntry.ScaleFactor;

                int texelMin = _clipMapSize / 2;
                int texelMax = (int)((float)(_clipMapSize) * stackEntry.ScaleFactor) - texelMin;

                // get the top left corner
                Point texelTopLeft = new Point((int)MathHelper.Clamp((int)(Math.Floor(texelCenterF.X)), texelMin, texelMax) - texelMin,
                                                (int)MathHelper.Clamp((int)(Math.Floor(texelCenterF.Y)), texelMin, texelMax) - texelMin);

                // prevent very small updates - the RT changes are costly
                Point delta = new Point(stackEntry.ToroidalOffset.X - texelTopLeft.X, stackEntry.ToroidalOffset.Y - texelTopLeft.Y);
                if (Math.Abs(delta.X) <= _minUpdateDelta && Math.Abs(delta.Y) <= _minUpdateDelta)
                    continue;

                // this + current toroid offset tells us what regions have to be blasted
                RectangleI oldData = new RectangleI(stackEntry.ToroidalOffset, new Point(_clipMapSize, _clipMapSize));
                RectangleI newData = new RectangleI(texelTopLeft, new Point(_clipMapSize, _clipMapSize));

                // get the bounds of the new texture data we want to copy
                desiredData = _CalculateModuloDeltaBounds(oldData, newData);
                //Console.WriteLine("Level {0}: {1} rects", i, desiredData.Count);
                Assert.Fatal(desiredData.Count < 8, "ClipMap.Recenter - Got too many rects back from CalculateModuloDeltaBounds.");

                // update the clip stack entry's clip center and toroidal offset
                stackEntry.ClipCenter = position;
                stackEntry.ToroidalOffset = texelTopLeft;

                // update any regions we found
                if (desiredData.Count > 0)
                {
                    //jk 9-14 temp, causes crash when enter debug mode //jk
                    for (int t = 0, c = GFXDevice.Instance.Device.GraphicsDeviceCapabilities.MaxSimultaneousTextures; t < c; t++)
                        GFXDevice.Instance.Device.Textures[t] = null;
                    //jk

                    _imageCache.BeginRectUpdates(i, stackEntry);

                    // update regions
                    for (int j = 0; j < desiredData.Count; j++)
                    {
                        Assert.Fatal(desiredData[j].IsValid, "ClipMap.Recenter - got an invalid rect.");

                        // Note the rect, so we can then wrap and let the image cache do its thing.
                        RectangleI srcRegion = desiredData[j];
                        desiredData[j] = new RectangleI(new Point(srcRegion.Point.X % _clipMapSize, srcRegion.Point.Y % _clipMapSize), desiredData[j].Extent);

                        Assert.Fatal(newData.Contains(srcRegion), "ClipMap.Recenter - got update buffer outside of expected new data bounds.");

                        _totalUpdates++;
                        _texelsUpdated += srcRegion.Extent.X * srcRegion.Extent.Y;

                        _imageCache.DoRectUpdate(i, stackEntry, srcRegion, desiredData[j]);
                    }

                    _imageCache.FinishRectUpdates(i, stackEntry);
                }

                // check if we've overrun our budget.
                if ((_texelsUpdated - lastTexelsUpdated) > _maxTexelUploadPerRecenter)
                {
                    _needsRecenter = true;
                    break;
                }
            }

            #if DEBUG
            Profiler.Instance.EndBlock("ClipMap.Recenter");
            #endif
        }