/// <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 }