Beispiel #1
0
        /// <summary>Puts a copy of 2D pixel data in a BytePixels object, specifying a source rectangle and a destination X,Y point.</summary>
        /// <param name="rect">The section of the pixel data to copy. <paramref name="null"/> indicates the data will be copied from the entire object.</param>
        /// <param name="dest">The destination BytePixels object.</param>
        /// <param name="xy">The top-left corner of the destination.</param>
        public void PutData(RectI?rect, BytePixels dest, PointInt32 xy)
        {
            RectI r;

            if (rect != null)
            {
                r = (RectI)rect;
            }
            else
            {
                r = new RectI(new PointInt32(), this.Size);
            }

            var sOfs = (r.Y * this.Size.W) + r.X;

            sOfs *= Bpp;

            var dOfs = (xy.Y * dest.Size.W) + xy.X;

            dOfs *= Bpp;  // note: we're not factoring for Bpp mismatches here...

            var dataLeft = r.Size.Total * Bpp;

            for (int y = 0; y < r.Height; y++)
            {
                Array.Copy(_data, sOfs, dest.Data, dOfs, r.Width * Bpp);
                sOfs += this.Size.W * Bpp;
                dOfs += dest.Size.W * Bpp;
            }
        }
Beispiel #2
0
        public bool Rebound(RectI bound, bool shiftTop = false, bool shiftLeft = false, bool shiftBottom = false, bool shiftRight = false)    // shiftXXX = shift W/H or just truncate
        {
            bool changed = false;

            if (Top < bound.Top)
            {
                if (shiftTop)
                {
                    Height += bound.Top - Top;
                }
                Top     = bound.Top;
                changed = true;
            }
            if (Left < bound.Left)
            {
                if (shiftLeft)
                {
                    Width += bound.Left - Left;
                }
                Left    = bound.Left;
                changed = true;
            }
            if (Bottom > bound.Bottom)
            {
                if (shiftBottom)
                {
                    Top -= Bottom - bound.Bottom;
                }
                Bottom  = bound.Bottom;
                changed = true;
            }
            if (Right > bound.Right)
            {
                if (shiftRight)
                {
                    Left -= Right - bound.Right;
                }
                Right   = bound.Right;
                changed = true;
            }

            // forced truncations
            if (Width > bound.Width)
            {
                Left    = bound.Left;
                Right   = bound.Right;
                changed = true;
            }
            if (Height > bound.Height)
            {
                Top     = bound.Top;
                Bottom  = bound.Bottom;
                changed = true;
            }

            return(changed);
        }
Beispiel #3
0
        public void FillRectangle(RectI area, ref TilePicker tile)
        {
            // validate area
            int w = _world.Header.WorldBounds.W;
            area.Rebound(_world.Header.WorldBounds);

            for (int x = area.Left; x <= area.Right; x++) {
                for (int y = area.Top; y <= area.Bottom; y++) {
                    UpdateTile(ref tile, ref x, ref y, ref w);
                }
            }
        }
Beispiel #4
0
        public void DrawRectangle(RectI area, ref TilePicker tile)
        {
            // Use refs for faster access (really important!) speeds up a lot!
            int w = _world.Header.WorldBounds.W;
            int h = _world.Header.WorldBounds.H;

            // Check boundaries
            area.Rebound(_world.Header.WorldBounds);

            // (needed for refs)
            int x1 = area.Left;
            int x2 = area.Right;
            int y1 = area.Top;
            int y2 = area.Bottom;

            // top and bottom horizontal scanlines
            for (int x = area.Left; x <= area.Right; x++) {
                UpdateTile(ref tile, ref x, ref y1, ref w);
                UpdateTile(ref tile, ref x, ref y2, ref w);
            }

            for (int y = area.Top; y <= area.Bottom; y++) {
                UpdateTile(ref tile, ref x1, ref y, ref w);
                UpdateTile(ref tile, ref x2, ref y, ref w);
            }
        }
 public void SetData(RectI? rect, byte[] src, int width, int height, PointInt32 xy)
 {
     var bp = new BytePixels(width, height, src);
     bp.PutData(rect, this, xy);
 }
        // using FP = FramePlacement;
        private bool ValidatePlacement(PointInt32 location, PointShort size, FramePlacement frame)
        {
            // TODO: Support for attachesTo with placement

            // quick short-circuits
            if (frame.Is(FP.None))   return false;   // hey, if it can't attach to anything, it's invalid
            if (frame.Is(FP.Any))    return true;
            if (frame.Has(FP.Float)) return true;  // ...for now; this behavior may change if we actually get a "float only" object

            /// Look at surrounding area for objects ///
            FramePlacement area   = FP.Float;
            RectI areaRect = new RectI(location - 1, location + size);
            // (only used for x/y loop)
            RectI areaRectBnd = new RectI(areaRect);

            // skip tests that don't apply
            // (frame = multiples)
            if (frame.HasNo(FP.Ceiling))      areaRectBnd.Top++;
            if (frame.HasNo(FP.FloorSurface)) areaRectBnd.Bottom--;
            if (frame.HasNo(FP.Wall)) {
                areaRectBnd.Left++;
                areaRectBnd.Right--;
            }

            // (shorter cuts for singular terms; using HasNoneOf to factor in MustHaveAll)
            if (frame.HasNoneOf(FP.WallCeiling))      areaRectBnd.Top    = areaRect.Bottom;  // Floor/Surface/both
            if (frame.HasNoneOf(FP.WallFloorSurface)) areaRectBnd.Bottom = areaRect.Top;     // Ceiling
                                                                                             // Wall already covered in multiples checks

            // boundary checks
            if ( areaRectBnd.Left  < 0)                  areaRectBnd.Left   = 0;
            if ( areaRectBnd.Top   < 0)                  areaRectBnd.Top    = 0;
            if (areaRectBnd.Right  > Header.WorldBounds.Right)  areaRectBnd.Right  = Header.WorldBounds.Right;
            if (areaRectBnd.Bottom > Header.WorldBounds.Bottom) areaRectBnd.Bottom = Header.WorldBounds.Bottom;

            for (int y = areaRectBnd.Top; y <= areaRectBnd.Bottom; y++)
            {
                for (int x = areaRectBnd.Left; x <= areaRectBnd.Right; x++)
                {
                    // skip dead zone (the item itself) & corners (wow, xor use...)
                    bool valid = (x == areaRect.Left || x == areaRect.Right) ^ (y == areaRect.Top || y == areaRect.Bottom);
                    if (!valid) continue;

                    var t = Tiles[x, y];
                    var w = WorldSettings.Tiles[t.Type];

                    // skip non-solid objects
                    if (! (t.IsActive && w.IsSolid || w.IsSolidTop)) continue;

                    // FIXME: Assuming that a single tile will hold the object //
                    // (Maybe this is true in Terraria as well....)

                    // at this point, only one of these will hit
                    if      (y ==  areaRect.Top) {
                        area = area.Add(FP.Ceiling);
                        break;  // done with this Y-axis
                    }
                    else if (x ==  areaRect.Left || x == areaRect.Right) {
                        area = area.Add(FP.Wall);
                        y = areaRect.Bottom - 1;  // -1 = for loop will re-adjust, or kick out if LRB was truncated
                        break;  // done with all except bottom
                    }
                    else if (y == areaRect.Bottom) {  // special case for floor/surface
                        if (w.IsSolidTop) area = area.Add(FP.Surface);
                        else              area = area.Add(FP.Floor);
                        if (area.HasAllOf(FP.FloorSurface)) break;  // done with everything else
                    }
                }
            }

            // Now let's compare the object in question
            if (frame.Has(FP.MustHaveAll)) {
                area = area.Add(FP.MustHaveAll);  // add bit for bitwise math to work
                if (area.Filter(frame) != frame) return false;
            }
            else {
                if (frame.HasNoneOf(area))       return false;
            }

            return true;
        }
 public void SetData(RectI? rect, BytePixels src)
 {
     src.PutData(rect, this, new PointInt32());
 }
Beispiel #8
0
 public RectI(RectI rect)
 {
     _topLeft     = new PointInt32(rect.TopLeft);
     _bottomRight = new PointInt32(rect.BottomRight);
 }
 public void PutData(RectI? rect, BytePixels dest)
 {
     PutData(rect, dest, new PointInt32());
 }
Beispiel #10
0
        public override bool MoveTool(TileMouseEventArgs e)
        {
            WriteableBitmap bmp;

            if (_startPoint != null) _endPoint = e.Tile;
            CheckDirectionandDraw(e);
            ToolAnchorMode mode = ToolAnchorMode.Center;

            // Line draw preview
            if (_isRightDown && _startPoint != null && _endPoint != null) {
                var sp = (PointInt32)_startPoint;
                var ep = (PointInt32)_endPoint;
                var delta = ep - sp;
                var rect = new RectI(new PointInt32(), new SizeInt32(Math.Abs(delta.X) + 1, Math.Abs(delta.Y) + 1));

                // figure out exactly which PreviewMode
                mode = 0;
                if      (delta.X <  0) mode += (int)ToolAnchorModeParts.Left;
                else if (delta.X == 0) mode += (int)ToolAnchorModeParts.Center;
                else if (delta.X >  0) mode += (int)ToolAnchorModeParts.Right;

                if      (delta.Y <  0) mode += (int)ToolAnchorModeParts.Top;
                else if (delta.Y == 0) mode += (int)ToolAnchorModeParts.Middle;
                else if (delta.Y >  0) mode += (int)ToolAnchorModeParts.Bottom;

                // which direction to draw the line
                var linePnts = new PointInt32[2];
                switch (mode) {
                    case ToolAnchorMode.TopLeft:     linePnts = new[] { rect.BottomRight, rect.TopLeft }; break;
                    case ToolAnchorMode.TopRight:    linePnts = new[] { rect.BottomLeft, rect.TopRight }; break;
                    case ToolAnchorMode.BottomLeft:  linePnts = new[] { rect.TopRight, rect.BottomLeft }; break;
                    case ToolAnchorMode.BottomRight: linePnts = new[] { rect.TopLeft, rect.BottomRight }; break;
                    default:  // has middle or center, order doesn't matter
                        linePnts = new[] { rect.TopLeft, rect.BottomRight };
                        break;
                }

                bmp = new WriteableBitmap(
                    rect.W,
                    rect.H,
                    96,
                    96,
                    System.Windows.Media.PixelFormats.Bgra32,
                    null);

                bmp.Clear();
                foreach (PointInt32 p in WorldRenderer.DrawLine(linePnts[0], linePnts[1])) {
                    if (_selection.IsValid(p)) bmp.SetPixel(p.X, p.Y, previewColor);
                }
            }
            // Single dot
            else {
                bmp = new WriteableBitmap(
                    1,
                    1,
                    96,
                    96,
                    System.Windows.Media.PixelFormats.Bgra32,
                    null);

                bmp.Clear();
                bmp.SetPixel(0, 0, previewColor);
            }

            _properties.Image = bmp;
            _properties.PreviewMode = mode;

            return false;
        }
Beispiel #11
0
 private static bool MatchFields(RectI a, RectI m)
 {
     return (a.TopLeft == m.TopLeft && a.BottomRight == m.BottomRight);
 }
Beispiel #12
0
        public bool Rebound(RectI bound, bool shiftTop = false, bool shiftLeft = false, bool shiftBottom = false, bool shiftRight = false)
        {
            // shiftXXX = shift W/H or just truncate
            bool changed = false;

            if (Top    < bound.Top) {
                if (shiftTop)    Height += bound.Top - Top;
                Top    = bound.Top;
                changed = true;
            }
            if (Left   < bound.Left) {
                if (shiftLeft)   Width += bound.Left - Left;
                Left   = bound.Left;
                changed = true;
            }
            if (Bottom > bound.Bottom) {
                if (shiftBottom) Top  -= Bottom - bound.Bottom;
                Bottom = bound.Bottom;
                changed = true;
            }
            if (Right  > bound.Right) {
                if (shiftRight)  Left -= Right  - bound.Right;
                Right  = bound.Right;
                changed = true;
            }

            // forced truncations
            if (Width > bound.Width) {
                Left  = bound.Left;
                Right = bound.Right;
                changed = true;
            }
            if (Height > bound.Height) {
                Top    = bound.Top;
                Bottom = bound.Bottom;
                changed = true;
            }

            return changed;
        }
Beispiel #13
0
 public bool Equals(RectI p)
 {
     return MatchFields(this, p);
 }
Beispiel #14
0
 public RectI(RectI rect)
 {
     _topLeft = new PointInt32(rect.TopLeft);
     _bottomRight = new PointInt32(rect.BottomRight);
 }
        private BytePixels GetTextureLayer(string layerType, int y, Tile tile)
        {
            var size   = 8;
            var sizeI  = new SizeInt32(size, size);
            var pixels = new BytePixels(sizeI, 4);
            var rect00 = new RectI(0, 0, sizeI);
            string key = String.Empty;

            switch (layerType)
            {
                case "TilePixel":
                    Color c = GetTileColor(y, tile);

                    var b = new byte[4];
                    b[0] = c.B;
                    b[1] = c.G;
                    b[2] = c.R;
                    b[3] = c.A;
                    pixels = new BytePixels(1, 1, b);
                    break;

                case "Wall":
                    key = GetTileKey(y, tile, 'W');
                    if (textureCache.Contains(key)) return (BytePixels)textureCache.Get(key);

                    // FIXME: A complete wall is actually 16x16 big, with 3x3 variations, depending how many tiles exist //
                    if (tile.Wall > 0)
                        pixels = WorldSettings.Walls[tile.Wall].Texture.GetData(new RectI(166, 58, sizeI));  // tile with most coverage (will be eventually replaced per FIXME)
                    else {
                        // FIXME: These are actually pretty large bitmaps //
                        // Might need to go on a WallsBack layer... //

                        if (y >= _world.Header.WorldBounds.Bottom - 192)
                            pixels = WorldSettings.GlobalColors["Hell"].Texture.GetData(rect00);
                        else if (y > _world.Header.WorldRockLayer)
                            pixels = WorldSettings.GlobalColors["Rock"].Texture.GetData(rect00);
                        else if (y > _world.Header.WorldSurface)
                            pixels = WorldSettings.GlobalColors["Earth"].Texture.GetData(rect00);
                        else
                            pixels = WorldSettings.GlobalColors["Sky"].Texture.GetData(rect00);
                    }
                    break;

                case "TileBack":
                    key = GetTileKey(y, tile, 'T');
                    if (textureCache.Contains(key)) return (BytePixels)textureCache.Get(key);

                    // FIXME: Need XML property for larger than 8x8 sizes
                    if (tile.IsActive && !WorldSettings.Tiles[tile.Type].IsSolid) {
                        var rect = (WorldSettings.Tiles[tile.Type].IsFramed) ?
                            new RectI(tile.Frame.X / 2, tile.Frame.Y / 2, sizeI) :
                            rect00;
                        pixels = WorldSettings.Tiles[tile.Type].Texture.GetData(rect);
                    }
                    break;

                // FIXME: NPC layer would go here... //

                case "TileFront":
                    key = GetTileKey(y, tile, 'T');
                    if (textureCache.Contains(key)) return (BytePixels)textureCache.Get(key);

                    // FIXME: Need XML property for larger than 8x8 sizes
                    if (tile.IsActive && WorldSettings.Tiles[tile.Type].IsSolid) {
                        var rect = (WorldSettings.Tiles[tile.Type].IsFramed) ?
                            new RectI(tile.Frame.X / 2, tile.Frame.Y / 2, sizeI) :
                            rect00;
                        pixels = WorldSettings.Tiles[tile.Type].Texture.GetData(rect);
                    }
                    break;

                case "Liquid":
                    key = GetTileKey(y, tile, 'L');
                    if (textureCache.Contains(key)) return (BytePixels)textureCache.Get(key);

                    if (tile.Liquid > 0) {
                        // Should use Liquid levels to determine final height //
                        // Actually, bottom 4x4 should be for 255, and top 4x4 for anything else //
                        if (tile.IsLava)
                            pixels = WorldSettings.GlobalColors["Lava"].Texture.GetData(rect00);
                        else
                            pixels = WorldSettings.GlobalColors["Water"].Texture.GetData(rect00);
                    }
                    break;
            }

            // Cache policy for new cache items
            var cachePolicy = new CacheItemPolicy();
            cachePolicy.SlidingExpiration = new TimeSpan(0, 5, 0);  // 5 minute duration if not used
            if (shortKeyRegEx.IsMatch(key)) cachePolicy.Priority = CacheItemPriority.NotRemovable;  // single unframed tiles and walls get perma-cached

            textureCache.Add(key, pixels, cachePolicy);
            return pixels;
        }
        public void RenderTextures(RectI rect, System.Windows.Controls.ScrollViewer partView, System.Windows.Controls.Image img)
        {
            // Cancel any old render tasks
            if (_lastRenderTaskCancel != null) _lastRenderTaskCancel.Cancel();
            _lastRenderTaskCancel = new CancellationTokenSource();

            // Re-render
            Task.Factory.StartNew(() => {
                var wbmap = new WriteableBitmap(
                    rect.Size.W * 8,
                    rect.Size.H * 8,
                    96,
                    96,
                    System.Windows.Media.PixelFormats.Bgr32,
                    null);

                _renderer.UpdateWorldImage(rect, true, null, wbmap);
                wbmap.Freeze();
                return wbmap;
            })
            .ContinueWith(t => {
                // Re-draw
                WorldImage.Rendered = t.Result;

                // Re-position
                System.Windows.Controls.Canvas.SetLeft(img, rect.X);
                System.Windows.Controls.Canvas.SetTop (img, rect.Y);
                img.Width  = rect.Size.W * 8;
                img.Height = rect.Size.H * 8;

                img.UpdateLayout();
                CommandManager.InvalidateRequerySuggested();
            }, _lastRenderTaskCancel.Token, TaskContinuationOptions.LongRunning, _uiScheduler);

            // Re-time
            _lastRender = DateTime.Now;
        }
Beispiel #17
0
        /// <summary>Puts a copy of 2D pixel data in a BytePixels object, specifying a source rectangle and a destination X,Y point.</summary>
        /// <param name="rect">The section of the pixel data to copy. <paramref name="null"/> indicates the data will be copied from the entire object.</param>
        /// <param name="dest">The destination BytePixels object.</param>
        /// <param name="xy">The top-left corner of the destination.</param>
        public void PutData(RectI? rect, BytePixels dest, PointInt32 xy)
        {
            RectI r;
            if (rect != null) r = (RectI)rect;
            else              r = new RectI(new PointInt32(), this.Size);

            var sOfs = (r.Y * this.Size.W) + r.X;
            sOfs *= Bpp;

            var dOfs = (xy.Y * dest.Size.W) + xy.X;
            dOfs *= Bpp;  // note: we're not factoring for Bpp mismatches here...

            var dataLeft = r.Size.Total * Bpp;
            for (int y = 0; y < r.Height; y++)
            {
                Array.Copy(_data, sOfs, dest.Data, dOfs, r.Width * Bpp);
                sOfs += this.Size.W * Bpp;
                dOfs += dest.Size.W * Bpp;
            }
        }
Beispiel #18
0
 public bool Equals(RectI p)
 {
     return(MatchFields(this, p));
 }
Beispiel #19
0
 private static bool MatchFields(RectI a, RectI m)
 {
     return(a.TopLeft == m.TopLeft && a.BottomRight == m.BottomRight);
 }
Beispiel #20
0
 public void SetData(RectI? rect, BytePixels src, PointInt32 xy)
 {
     src.PutData(rect, this, xy);
 }
        public void UpdateWorldImage(RectI area, bool isRenderedLayer = false, string renderMsg = "Render Update Complete.", WriteableBitmap img = null)
        {
            // validate area
            area.Rebound(_world.Header.WorldBounds);

            int width = area.Width;
            int height = area.Height;
            int rts = isRenderedLayer ? 8 : 1;
            string renderProgressMsg = isRenderedLayer ? "Rendering Textured World..." : "Rendering Pixel World...";

            if (img == null) img = isRenderedLayer ? _worldImage.Rendered : _worldImage.Image;
            var pixels = new BytePixels(area.Size * rts, 4);
            var stride = img.PixelWidth * img.Format.BitsPerPixel / 8;

            for (int x = area.X; x <= area.Right; x++)
            {
                int dx = x - area.X;
                if (renderMsg != null) OnProgressChanged(this, dx, width, renderProgressMsg);

                for (int y = area.Y; y <= area.Bottom; y++)
                {
                    int dy = y - area.Y;
                    Tile tile = _world.Tiles[x, y];
                    if (tile != null)
                    {
                        var xy = (new PointInt32(x, y) - area.TopLeft) * rts;
                        var bp = isRenderedLayer ? GetTexture(y, tile) : GetTextureLayer("TilePixel", y, tile);
                        bp.PutData(pixels, xy);
                    }
                }
            }

            SizeInt32 ts = new SizeInt32(rts, rts);
            var realArea = isRenderedLayer ? new RectI(new PointInt32(), area.Size * ts) : area; // Rendered layer starts at 0,0

            img.Lock();
            img.WritePixels(realArea, pixels.GetData(), stride, 0);
            if (!isRenderedLayer) img.AddDirtyRect(realArea);
            img.Unlock();

            if (renderMsg != null) OnProgressChanged(this, 100, 100, renderMsg);
        }