private bool HandleMouseMove(int pxX, int pxY, Toolbox.ToolType tool) { if (m_sprite == null || pxX < 0 || pxY < 0) { return(false); } // Convert screen pixel (x,y) to sprite pixel index (x,y). int pxSpriteX = pxX / BigBitmapPixelSize; int pxSpriteY = pxY / BigBitmapPixelSize; // Ignore if pixel is outside bounds of current sprite. if (pxSpriteX >= m_sprite.PixelWidth || pxSpriteY >= m_sprite.PixelHeight) { return(false); } if (tool == Toolbox.ToolType.FloodFill) { return(m_sprite.FloodFillClick(pxSpriteX, pxSpriteY)); } // Convert sprite pixel coords (x,y) into tile index (x,y) and tile pixel coords (x,y). int tileX = pxSpriteX / Tile.TileSize; int pxTileX = pxSpriteX % Tile.TileSize; int tileY = pxSpriteY / Tile.TileSize; int pxTileY = pxSpriteY % Tile.TileSize; int nTileIndex = (tileY * m_sprite.TileWidth) + tileX; Palette p = m_parent.ActivePalette(); if (tool == Toolbox.ToolType.Eyedropper) { int nCurrColor = m_sprite.GetPixel(pxSpriteX, pxSpriteY); if (nCurrColor == p.CurrentColor()) { return(false); } p.SetCurrentColor(nCurrColor); return(true); } Tile t = m_sprite.GetTile(nTileIndex); int nColor = (tool == Toolbox.ToolType.Eraser ? 0 : p.CurrentColor()); // Same color - no need to update. if (t.GetPixel(pxTileX, pxTileY) == nColor) { return(false); } // Set the new color. t.SetPixel(pxTileX, pxTileY, nColor); return(true); }
public void Test_AddSprite_draw_redo() { Sprite s = m_ss.AddSprite(1, 1, "sample", 0, "", 0, m_mgr); Assert.IsNotNull(s); Assert.AreEqual(1, m_mgr.Count); Assert.AreEqual(0, m_mgr.Current); Assert.IsTrue(m_mgr.CanUndo()); Assert.IsFalse(m_mgr.CanRedo()); // Draw a pixel. int x1 = 3, y1 = 4; int color1 = 1; s.SetPixel(x1, y1, color1); Assert.AreEqual(color1, s.GetPixel(x1, y1)); s.RecordUndoAction("pencil1", m_mgr); Assert.AreEqual(2, m_mgr.Count); Assert.AreEqual(1, m_mgr.Current); UndoAction_SpriteEdit u1 = m_mgr.GetCurrent() as UndoAction_SpriteEdit; Assert.AreEqual(0, u1.Before.tiles[0].pixels[x1, y1]); Assert.AreEqual(color1, u1.After.tiles[0].pixels[x1, y1]); Assert.IsTrue(m_mgr.CanUndo()); Assert.IsFalse(m_mgr.CanRedo()); // Undo the pixel draw. m_mgr.ApplyUndo(); Assert.AreEqual(2, m_mgr.Count); Assert.AreEqual(0, m_mgr.Current); // Pencil mark reverted. Assert.AreEqual(0, s.GetPixel(x1, y1)); Assert.IsTrue(m_mgr.CanUndo()); Assert.IsTrue(m_mgr.CanRedo()); // Redo the pixel draw. m_mgr.ApplyRedo(); Assert.AreEqual(2, m_mgr.Count); Assert.AreEqual(1, m_mgr.Current); Assert.AreEqual(color1, s.GetPixel(x1, y1)); Assert.IsTrue(m_mgr.CanUndo()); Assert.IsFalse(m_mgr.CanRedo()); }
private int[] CalcMask(Sprite s, out int width, out int height) { width = 0; height = 0; if (s == null) { return(null); } // Calc # of int32s required. int xsize = ((s.PixelWidth + MaskWordWidth - 1) / MaskWordWidth); int ysize = s.PixelHeight; int size = xsize * ysize; int[] mask = new int[size]; for (int y = 0; y < ysize; y++) { for (int x = 0; x < xsize; x++) { int index = y * xsize + x; mask[index] = 0; for (int i = 0; i < MaskWordWidth; i++) { mask[index] <<= 1; if (x * MaskWordWidth + i < s.PixelWidth) { if (s.GetPixel(x * MaskWordWidth + i, y) != 0) { mask[index] |= 1; } } } } } width = xsize; height = ysize; return(mask); }
// +----------+ - // |A | | y offset // | +---------+ - // | |B | // | | | // +-----| | // | | // +---------+ // // |-----| // x offset private bool CollisionCheck() { if (s2 == null) { return(false); } StringBuilder sb = new StringBuilder(); if (xOffset >= s1.PixelWidth || yOffset >= s1.PixelHeight || -xOffset >= s2.PixelWidth || -yOffset >= s2.PixelHeight) { tbInfo.Text = "BBoxes don't overlap"; return(false); } // Calculate the intersection rect in the local coord system // of each sprite. int s1x = xOffset >= 0 ? xOffset : 0; int s1y = yOffset >= 0 ? yOffset : 0; int s2x = xOffset < 0 ? -xOffset : 0; int s2y = yOffset < 0 ? -yOffset : 0; sb.Append(String.Format("offset: {0},{1}\r\n", xOffset, yOffset)); int w, h; if (xOffset >= 0) { w = min(s2.PixelWidth, s1.PixelWidth - s1x); } else { w = min(s1.PixelWidth, s2.PixelWidth - s2x); } if (yOffset >= 0) { h = min(s2.PixelHeight, s1.PixelHeight - s1y); } else { h = min(s1.PixelHeight, s2.PixelHeight - s2y); } sb.Append(String.Format("s1 size: {0},{1}\r\n", s1.PixelWidth, s1.PixelHeight)); sb.Append(String.Format("s2 size: {0},{1}\r\n", s2.PixelWidth, s2.PixelHeight)); sb.Append(String.Format("overlap: {0},{1}\r\n", w, h)); // Slow but sure method to use for verification. int verify_count = 0; bool fFirst = true; for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { if (s1.GetPixel(s1x + x, s1y + y) != 0 && s2.GetPixel(s2x + x, s2y + y) != 0) { if (fFirst) { sb.Append(String.Format("Hit at {0},{1}\r\n", x, y)); } fFirst = false; verify_count++; tbInfo.Text = sb.ToString(); } } } sb.Append(String.Format("count: {0}\r\n", verify_count)); // Run bitmask based collision check. // Assumes bitmasks are padded out with 0's to a MaskWidth boundary // General approach is to: // calculate the bitmask overlap area // for each line: // for each bitmask: // shift bits in A so that they align with B // if shited-A & B != 0: // we have a collision // // Shifting the masks to align is the only tricky part. int[] a_mask, b_mask; int a_maskw, a_maskh; int b_maskw, b_maskh; int x_offset, y_offset; if (xOffset >= 0) { a_mask = mask1; a_maskw = mask1w; a_maskh = mask1h; b_mask = mask2; b_maskw = mask2w; b_maskh = mask2h; x_offset = xOffset; y_offset = yOffset; } else { a_mask = mask2; a_maskw = mask2w; a_maskh = mask2h; b_mask = mask1; b_maskw = mask1w; b_maskh = mask1h; x_offset = -xOffset; y_offset = -yOffset; } int a_lshift = x_offset % MaskWordWidth; int a_maskword_offset = x_offset / MaskWordWidth; int maskword_count = (w + MaskWordWidth - 1) / MaskWordWidth; int a_x0, b_x0; int a_xN; if (y_offset >= 0) { a_x0 = (y_offset * a_maskw) + a_maskword_offset; a_xN = a_maskw - (y_offset * a_maskw); b_x0 = 0; } else { a_x0 = a_maskword_offset; a_xN = a_maskw; b_x0 = (-y_offset * b_maskw); } bool fFirstMessage = true; int count = 0; if (a_lshift == 0) { sb.Append("PP checking mask aligned\r\n"); // offset is aligned to maskwidth boundary - no bit shifting needed for (int x = 0; x < maskword_count; x++) { for (int y = 0; y < h; y++) { if ((a_mask[a_x0 + x] & b_mask[b_x0 + x]) != 0) { if (fFirstMessage) { sb.Append("PP found collision\r\n"); } fFirstMessage = false; count = 1; } a_x0 += a_maskw; b_x0 += b_maskw; } } } else { sb.Append("PP checking mask shifted\r\n"); int a_rshift = MaskWordWidth - a_lshift; for (int x = 0; x < maskword_count; x++) { for (int y = 0; y < h; y++) { int a = a_mask[a_x0 + x] << a_lshift; if (x + 1 < a_xN) { a |= a_mask[a_x0 + x + 1] >> a_rshift; } if ((a & b_mask[b_x0 + x]) != 0) { if (fFirstMessage) { sb.Append("PP found collision\r\n"); } fFirstMessage = false; count = 1; } a_x0 += a_maskw; b_x0 += b_maskw; } } } bool fCollision = verify_count != 0; lResult.Text = fCollision ? "Collision" : "No collision"; tbInfo.Text = sb.ToString(); if (!((count == 0 && verify_count == 0) || (count != 0 && verify_count != 0))) { lResult.Text = "ERROR! no match"; } return(fCollision); }
private int[] CalcMask(Sprite s, out int width, out int height) { width = 0; height = 0; if (s == null) return null; // Calc # of int32s required. int xsize = ((s.PixelWidth + MaskWordWidth-1) / MaskWordWidth); int ysize = s.PixelHeight; int size = xsize * ysize; int[] mask = new int[size]; for (int y = 0; y < ysize; y++) { for (int x = 0; x < xsize; x++) { int index = y * xsize + x; mask[index] = 0; for (int i = 0; i < MaskWordWidth; i++) { mask[index] <<= 1; if (x * MaskWordWidth + i < s.PixelWidth) { if (s.GetPixel(x * MaskWordWidth + i, y) != 0) mask[index] |= 1; } } } } width = xsize; height = ysize; return mask; }
public void Test_AddSprite_draw_undo() { Sprite s = m_ss.AddSprite(1, 1, "sample", 0, "", 0, m_mgr); Assert.IsNotNull(s); Assert.AreEqual(1, m_mgr.Count); Assert.AreEqual(0, m_mgr.Current); Assert.IsTrue(m_mgr.CanUndo()); Assert.IsFalse(m_mgr.CanRedo()); // Draw a pixel. int x1 = 3, y1 = 4; int color1 = 1; s.SetPixel(x1, y1, color1); Assert.AreEqual(color1, s.GetPixel(x1, y1)); s.RecordUndoAction("pencil1", m_mgr); Assert.AreEqual(2, m_mgr.Count); Assert.AreEqual(1, m_mgr.Current); UndoAction_SpriteEdit u1 = m_mgr.GetCurrent() as UndoAction_SpriteEdit; Assert.AreEqual(0, u1.Before.tiles[0].pixels[x1, y1]); Assert.AreEqual(color1, u1.After.tiles[0].pixels[x1, y1]); Assert.IsTrue(m_mgr.CanUndo()); Assert.IsFalse(m_mgr.CanRedo()); // Draw another pixel. int x2 = 4, y2 = 5; int color2 = 2; s.SetPixel(x2, y2, color2); Assert.AreEqual(color2, s.GetPixel(x2, y2)); s.RecordUndoAction("pencil2", m_mgr); Assert.AreEqual(3, m_mgr.Count); Assert.AreEqual(2, m_mgr.Current); UndoAction_SpriteEdit u2 = m_mgr.GetCurrent() as UndoAction_SpriteEdit; Assert.AreEqual(0, u2.Before.tiles[0].pixels[x2, y2]); Assert.AreEqual(color2, u2.After.tiles[0].pixels[x2, y2]); Assert.IsTrue(m_mgr.CanUndo()); Assert.IsFalse(m_mgr.CanRedo()); // Undo the last pixel draw. m_mgr.ApplyUndo(); Assert.AreEqual(3, m_mgr.Count); Assert.AreEqual(1, m_mgr.Current); // Last pencil reverted. Assert.AreEqual(0, s.GetPixel(x2, y2)); // First pencil still present. Assert.AreEqual(color1, s.GetPixel(x1, y1)); Assert.IsTrue(m_mgr.CanUndo()); Assert.IsTrue(m_mgr.CanRedo()); // Undo the first pixel draw. m_mgr.ApplyUndo(); Assert.AreEqual(3, m_mgr.Count); Assert.AreEqual(0, m_mgr.Current); // Both pencil marks reverted. Assert.AreEqual(0, s.GetPixel(x1, y1)); Assert.AreEqual(0, s.GetPixel(x2, y2)); Assert.IsTrue(m_mgr.CanUndo()); Assert.IsTrue(m_mgr.CanRedo()); // Undo the sprite add. m_mgr.ApplyUndo(); Assert.AreEqual(3, m_mgr.Count); Assert.AreEqual(-1, m_mgr.Current); Assert.IsFalse(m_mgr.CanUndo()); Assert.IsTrue(m_mgr.CanRedo()); }