/// <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; } }
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); }
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); } } }
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()); }
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()); }
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; }
private static bool MatchFields(RectI a, RectI m) { return (a.TopLeft == m.TopLeft && a.BottomRight == m.BottomRight); }
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; }
public bool Equals(RectI p) { return MatchFields(this, p); }
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; }
/// <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; } }
public bool Equals(RectI p) { return(MatchFields(this, p)); }
private static bool MatchFields(RectI a, RectI m) { return(a.TopLeft == m.TopLeft && a.BottomRight == m.BottomRight); }
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); }