public void DoRectUpdate(int mipLevel, ClipStackEntry stackEntry, RectangleI srcRegion, RectangleI dstRegion)
        {
            // get an array of texture data
            int elementCount = dstRegion.Width * dstRegion.Height;
            uint[] dstData = new uint[elementCount];
            uint[] srcData = _textureData[mipLevel];

            // make local copies of the rectangle components for quick access
            int srcExtentX = srcRegion.Extent.X;
            int srcExtentY = srcRegion.Extent.Y;
            int srcIndex = srcRegion.Point.X + (srcRegion.Point.Y * (int)stackEntry.ScaleFactor * stackEntry.Texture.Width);

            for (int y = 0; y < srcExtentY; y++)
            {
                Array.Copy(srcData, srcIndex, dstData, y * srcExtentX, srcExtentX);
                srcIndex += (int)stackEntry.ScaleFactor * stackEntry.Texture.Width;
            }

            // send the new data to the stack entry texture
            MSXNA.Rectangle dstTextureRect = new MSXNA.Rectangle(dstRegion.X, dstRegion.Y, dstRegion.Width, dstRegion.Height);

            // replace the specified rect of texture data on the texture
            #if XBOX
               stackEntry.Texture.SetData<uint>(0, dstTextureRect, dstData, 0, elementCount, SetDataOptions.None);
            #else
            stackEntry.Texture.SetData<uint>(0, dstTextureRect, dstData, 0, elementCount, SetDataOptions.Discard);
            #endif
        }
        public void DoRectUpdate(int mipLevel, ClipStackEntry stackEntry, RectangleI srcRegion, RectangleI dstRegion)
        {
            // toggle updateToggle
            _updateToggle = (_updateToggle + 1) % 3;

            // find the index to start at
            int index = (stackEntry.Texture.Width * dstRegion.Point.Y) + dstRegion.Point.X;

            // get an array of texture data
            int elementCount = dstRegion.Width * dstRegion.Height;
            uint[] dstData = new uint[elementCount];

            // make local copies of the rectangle components for quick access
            int srcPointX = srcRegion.Point.X;
            int srcPointY = srcRegion.Point.Y;
            int srcExtentX = srcRegion.Extent.X;
            int srcExtentY = srcRegion.Extent.Y;
            float scaleFactor = stackEntry.ScaleFactor;

            for (int y = 0; y < srcExtentY; y++)
            {
                for (int x = 0; x < srcExtentX; x++)
                {
                    uint color = 0xFF000000;

                    int realX = x + srcPointX;
                    int realY = y + srcPointY;

                    int xFlag = realX & 4;
                    int yFlag = realY & 4;

                    // checker pattern
                    if ((xFlag ^ yFlag) != 0)
                        color += 0xFF;

                    // gradient based on x position across master texture
                    color += (uint)((float)realX / (float)(512f * scaleFactor) * 255) << 8;

                    // toggle colors
                    switch (_updateToggle)
                    {
                        case 0:
                            color += 0xFF0000;
                            break;
                        case 1:
                            color += 0xA00000;
                            break;
                    }

                    //(uint)(_updateToggle ? 0xFF0000 : 0x00);
                    //color += 0xFF;

                    dstData[(srcExtentX * y) + x] = color;
                }
            }

            // send the new data to the stack entry texture
            Rectangle dstTextureRect = new Rectangle(dstRegion.X, dstRegion.Y, dstRegion.Width, dstRegion.Height);
            stackEntry.Texture.SetData<uint>(0, dstTextureRect, dstData, 0, elementCount, SetDataOptions.None);
        }
Ejemplo n.º 3
0
 /// <summary>
 /// Tests if this rectangle overlaps another rectangle.
 /// </summary>
 /// <param name="rect">The rectangle to test against.</param>
 /// <returns></returns>
 public bool Overlaps(RectangleI rect)
 {
     RectangleI test = new RectangleI(this);
     return test.Intersect(rect);
 }
Ejemplo n.º 4
0
 /// <summary>
 /// Returns whether or not this rectangle intersects with another rectangle.
 /// </summary>
 /// <param name="rect">The rectangle to test intersections with.</param>
 /// <returns>True if the rectangles intersect.</returns>
 public bool IntersectsWith(RectangleI rect)
 {
     if (_point.X + _extent.X < rect._point.X)
         return false;
     if (_point.Y + _extent.Y < rect._point.Y)
         return false;
     if (rect._point.X + rect._extent.X < _point.X)
         return false;
     if (rect._point.Y + rect._extent.Y < _point.Y)
         return false;
     return true;
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Set this rectangle to the intersection of it and another rectangle.
        /// </summary>
        /// <param name="clipRect">The rectangle to intersect with.</param>
        /// <returns>Whether or not the resulting rectangle is valid.</returns>
        public bool Intersect(RectangleI clipRect)
        {
            int bottomLX = (int)MathHelper.Min(_point.X + _extent.X, clipRect.X + clipRect.Width);
            int bottomLY = (int)MathHelper.Min(_point.Y + _extent.Y, clipRect.Y + clipRect.Height);

            _point.X = (int)MathHelper.Max(_point.X, clipRect.X);
            _point.Y = (int)MathHelper.Max(_point.Y, clipRect.Y);

            _extent.X = bottomLX - _point.X;
            _extent.Y = bottomLY - _point.Y;

            return IsValid;
        }
Ejemplo n.º 6
0
        /// <summary>
        /// Returns whether or not this rectangle entirely contains another rectangle.
        /// </summary>
        /// <param name="rect">The rectangle to test against.</param>
        /// <returns>True if the rectangle is entirely contained.</returns>
        public bool Contains(RectangleI rect)
        {
            if (_point.X <= rect.Point.X && _point.Y <= rect.Point.Y)
                if (rect.Point.X + rect.Extent.X <= _point.X + _extent.X)
                    if (rect.Point.Y + rect.Extent.Y <= _point.Y + _extent.Y)
                        return true;

            return false;
        }
Ejemplo n.º 7
0
 /// <summary>
 /// Creates a rectangle from another rectangle.
 /// </summary>
 /// <param name="rectangle"></param>
 public RectangleI(RectangleI rectangle)
 {
     _point = rectangle.Point;
     _extent = rectangle.Extent;
 }
        public void DoRectUpdate(int mipLevel, ClipStackEntry stackEntry, RectangleI srcRegion, RectangleI dstRegion)
        {
            // get a local reference to the GFXDevice's graphics device
            GraphicsDevice device = GFXDevice.Instance.Device;

            if (device.IsDisposed)
                return;

            // calculate the new destination texture coordinates
            // (custom viewports currently not fully supported on the XBox, so we use this method instead.
            // this is just as fast, so probably keep using this.)
            RectangleF dstCoords = new RectangleF(
                (float)dstRegion.X / (float)stackEntry.Texture.Width,
                (float)dstRegion.Y / (float)stackEntry.Texture.Height,
                (float)dstRegion.Width / (float)stackEntry.Texture.Width,
                (float)dstRegion.Height / (float)stackEntry.Texture.Height
                );

            // calculate the new texture coordinates
            RectangleF texCoords = new RectangleF(
                (float)srcRegion.X / ((float)stackEntry.Texture.Width * stackEntry.ScaleFactor),
                (float)srcRegion.Y / ((float)stackEntry.Texture.Height * stackEntry.ScaleFactor),
                (float)srcRegion.Width / ((float)stackEntry.Texture.Width * stackEntry.ScaleFactor),
                (float)srcRegion.Height / ((float)stackEntry.Texture.Height * stackEntry.ScaleFactor)
                );

            // custom viewports currently bugged on XBOX
            _UpdateRenderQuad(texCoords, dstCoords);

            // init the effect for this render
            _blender.SetupEffect(_toTexRenderState, null);

            // draw the quad
            while (_blender.SetupPass())
            {
                try
                {
                    device.DrawUserPrimitives<VertexPositionTexture>(PrimitiveType.TriangleStrip, _renderQuadVB, 0, 2);
                }
                catch (Exception x)
                {
                    break;
                }
            }
            // cleanup the effect after render
            _blender.CleanupEffect();
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Clips a given rectangle against a source texture and returns a list of rects that the rect will wrap to.
        /// </summary>
        /// <param name="gridSpacing">The grid over which to wrap the rectangle. Normally _clipMapSize.</param>
        /// <param name="rect">The rectangle to wrap around the grid.</param>
        /// <returns>The resultant list of rectangles from wrapping the texture to the grid.</returns>
        protected void _ClipAgainstGrid(int gridSpacing, RectangleI rect, ref List<RectangleI> rectList)
        {
            // check against X grids...
            int startX = rect.Point.X;
            int endX = rect.Point.X + rect.Extent.X;

            int gridMask = ~(gridSpacing - 1);
            int startGridX = startX & gridMask;
            int endGridX = endX & gridMask;

            _clipRectBuffer.Clear();

            // check X...
            if (startGridX != endGridX && endX - endGridX > 0)
            {
                // we have a clip: split against the grid multiple and store
                _clipRectBuffer.Add(new RectangleI(startX, rect.Point.Y, endGridX - startX, rect.Extent.Y));
                _clipRectBuffer.Add(new RectangleI(endGridX, rect.Point.Y, endX - endGridX, rect.Extent.Y));
            }
            else
            {
                // copy the original rect
                _clipRectBuffer.Add(rect);
            }

            // now, check Y for the one or two rects we have from above.
            for (int i = 0; i < _clipRectBuffer.Count; i++)
            {
                // Figure our extent and grid information.
                int startY = _clipRectBuffer[i].Point.Y;
                int endY = _clipRectBuffer[i].Point.Y + rect.Extent.Y;
                int startGridY = startY & gridMask;
                int endGridY = endY & gridMask;

                if (startGridY != endGridY && endY - endGridY > 0)
                {
                    // we have a clip: split against the grid multiple and store
                    rectList.Add(new RectangleI(_clipRectBuffer[i].Point.X, endGridY, _clipRectBuffer[i].Extent.X, endY - endGridY));
                    rectList.Add(new RectangleI(_clipRectBuffer[i].Point.X, startY, _clipRectBuffer[i].Extent.X, endGridY - startY));
                }
                else
                {
                    // copy the current rect
                    rectList.Add(_clipRectBuffer[i]);
                }
            }
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Calculate the list of rects that need to be updated when moving a clip level from one source area to another.
        /// </summary>
        /// <param name="oldData">The area the clip level is moving from.</param>
        /// <param name="newData">The area the clip level is moving to.</param>
        /// <returns>A list of rectangles that need to be updated.</returns>
        protected List<RectangleI> _CalculateModuloDeltaBounds(RectangleI oldData, RectangleI newData)
        {
            // sanity checking
            Assert.Fatal(oldData.Point.X >= 0 && oldData.Point.Y >= 0 && oldData.IsValid, "ClipMap.CalculateModuloDeltaBounds - Negative oldData origin or bad rect.");
            Assert.Fatal(newData.Point.X >= 0 && newData.Point.Y >= 0 && newData.IsValid, "ClipMap.CalculateModuloDeltaBounds - Negative newData origin or bad rect.");
            Assert.Fatal(newData.Extent == oldData.Extent, "ClipMap.CalculateModuloDeltaBounts - Mismatching extents, can only work with matching extents.");

            _updateRectList.Clear();

            // easiest case - if they're the same then do nothing
            if (oldData.Point == newData.Point)
                return _updateRectList;

            // easy case - if there's no overlap then it's all new
            if (!oldData.Overlaps(newData))
            {
                // clip out to return buffer, and we're done
                _ClipAgainstGrid(_clipMapSize, newData, ref _updateRectList);
                return _updateRectList;
            }

            // calculate some useful values for both X and Y. delta is used a lot
            // in determining bounds, and the boundary values are important for
            // determining where to start copying new data in.
            int xDelta = newData.Point.X - oldData.Point.X;
            int yDelta = newData.Point.Y - oldData.Point.Y;

            int xBoundary = (oldData.Point.X + oldData.Extent.X) % _clipMapSize;
            int yBoundary = (oldData.Point.Y + oldData.Extent.Y) % _clipMapSize;

            Assert.Fatal(xBoundary % _clipMapSize == oldData.Point.X % _clipMapSize, "ClipMap.CalculateModuleDeltaBounds - We assume that left and right of the dataset are identical (ie, it's periodical on size of clipmap!) (x)");
            Assert.Fatal(yBoundary % _clipMapSize == oldData.Point.Y % _clipMapSize, "ClipMap.CalculateModuleDeltaBounds - We assume that left and right of the dataset are identical (ie, it's periodical on size of clipmap!) (y)");

            // now, let's build up our rects. we have one rect if we are moving
            // on the X or Y axis, two if both. we dealt with the no-move case
            // previously.
            if (xDelta == 0)
            {
                // moving on Y! so generate and store clipped results.
                RectangleI yRect = new RectangleI();

                if (yDelta < 0)
                {
                    // we need to generate the box from right of old to right of new
                    yRect.Point = newData.Point;
                    yRect.Extent = new Point(_clipMapSize, -yDelta);
                }
                else
                {
                    // we need to generate the box from left of old to left of new
                    yRect.Point = new Point(newData.Point.X, (oldData.Point.Y + oldData.Extent.Y));
                    yRect.Extent = new Point(_clipMapSize, yDelta);
                }

                // clip out to return buffer, and we're done
                _ClipAgainstGrid(_clipMapSize, yRect, ref _updateRectList);

                return _updateRectList;
            }
            else if (yDelta == 0)
            {
                // moving on X! So generate and store clipped results.
                RectangleI xRect = new RectangleI();

                if (xDelta < 0)
                {
                    // We need to generate the box from right of old to right of new.
                    xRect.Point = newData.Point;
                    xRect.Extent = new Point(-xDelta, _clipMapSize);
                }
                else
                {
                    // we need to generate the box from left of old to left of new.
                    xRect.Point = new Point((oldData.Point.X + oldData.Extent.X), newData.Point.Y);
                    xRect.Extent = new Point(xDelta, _clipMapSize);
                }

                // clip out to return buffer, and we're done
                _ClipAgainstGrid(_clipMapSize, xRect, ref _updateRectList);

                return _updateRectList;
            }
            else
            {
                // Both! We have an L shape. So let's do the bulk of it in one rect,
                // and the remainder in the other. We'll choose X as the dominant axis.
                //
                // a-----b---------c   going from e to a.
                // |     |         |
                // |     |         |
                // d-----e---------f   So the dominant rect is abgh and the passive
                // |     |         |   rect is bcef. Obviously depending on delta we
                // |     |         |   have to switch things around a bit.
                // |     |         |          y+ ^
                // |     |         |             |
                // g-----h---------i   x+->      |

                RectangleI xRect = new RectangleI();
                RectangleI yRect = new RectangleI();

                if (xDelta < 0)
                {
                    // case in the diagram
                    xRect.Point = newData.Point;
                    xRect.Extent = new Point(-xDelta, _clipMapSize);

                    // set up what of yRect we know too
                    yRect.Point = new Point(xRect.Point.X + xRect.Extent.X, 0);
                    yRect.Extent = new Point(_clipMapSize + xDelta, 0);
                }
                else
                {
                    // opposite of case in diagram
                    xRect.Point = new Point(oldData.Point.X + oldData.Extent.X, newData.Point.Y);
                    xRect.Extent = new Point(xDelta, _clipMapSize);

                    // set up what of yRect we know too
                    yRect.Point = new Point((xRect.Point.X + xRect.Extent.X) - _clipMapSize, 0);
                    yRect.Extent = new Point(_clipMapSize - xRect.Extent.X, 0);
                }

                if (yDelta < 0)
                {
                    // case in the diagram.
                    yRect.Point = new Point(yRect.Point.X, newData.Point.Y);
                    yRect.Extent = new Point(yRect.Extent.X, -yDelta);
                }
                else
                {
                    // case in the diagram.
                    yRect.Point = new Point(yRect.Point.X, oldData.Point.Y + oldData.Extent.Y);
                    yRect.Extent = new Point(yRect.Extent.X, yDelta);
                }

                // make sure we don't overlap.
                Assert.Fatal(!yRect.Overlaps(xRect), "ClipMap.CalculateModuloDeltaBounds() - overlap in result rects - should not happen!");

                // now run them through the clipper and we're done
                _ClipAgainstGrid(_clipMapSize, xRect, ref _updateRectList);
                _ClipAgainstGrid(_clipMapSize, yRect, ref _updateRectList);

                return _updateRectList;
            }
        }
Ejemplo n.º 11
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
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Fills each clip stack entry with texture data. This should be called once the clip stack and image cache have been initialized.
        /// </summary>
        /// <returns>True if the operation completed successfully.</returns>
        public bool FillWithTextureData()
        {
            // get the interest center
            Vector2 texelCenterF;

            List<RectangleI> desiredData = new List<RectangleI>();

            // first generate our desired rects for each level
            for (int i = 0; i < _clipStackDepth; i++)
            {
                // get this stack entry
                ClipStackEntry stackEntry = _clipLevels[i];

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

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

                Point texelTopLeft = new Point((int)MathHelper.Clamp((int)(Math.Floor(texelCenterF.Y)), texelMin, texelMax) - texelMin,
                                                (int)MathHelper.Clamp((int)(Math.Floor(texelCenterF.X)), texelMin, texelMax) - texelMin);

                desiredData.Add(new RectangleI(texelTopLeft, new Point(_clipMapSize, _clipMapSize)));
            }

            // upload all the textures...
            for (int i = 0; i < _clipStackDepth; i++)
            {
                ClipStackEntry stackEntry = _clipLevels[i];

                _updateRectList.Clear();
                _ClipAgainstGrid(_clipMapSize, desiredData[i], ref _updateRectList);

                Assert.Fatal(_updateRectList.Count < 8, "ClipMap.FillWithTextureData - Got too many rects back!");

                if (_updateRectList.Count > 0)
                {
                    _imageCache.BeginRectUpdates(i, stackEntry);

                    for (int j = 0; j < _updateRectList.Count; j++)
                    {
                        RectangleI srcRegion = _updateRectList[j];
                        _updateRectList[j] = new RectangleI(new Point(srcRegion.Point.X % _clipMapSize, srcRegion.Point.Y % _clipMapSize), _updateRectList[j].Extent);

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

                    _imageCache.FinishRectUpdates(i, stackEntry);
                }

                stackEntry.ToroidalOffset = desiredData[i].Point;
            }

            // success!
            return true;
        }