Advertisement
Guest User

Untitled

a guest
Mar 27th, 2017
57
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.01 KB | None | 0 0
  1. fun unpack(spriteSheet: Path): List<Image> {
  2. Preconditions.checkArgument(Files.exists(spriteSheet),
  3. "The file ${spriteSheet.getFileName()} does not exist")
  4.  
  5. logger.debug("Loading sprite sheet.")
  6. // TODO: Convert to png so we have an alpha layer to work with
  7. val spriteSheetImage = readImage(spriteSheet).toBufferedImage()
  8.  
  9. logger.debug("Determining most probable background color.")
  10. val backgroundColor = determineProbableBackgroundColor(spriteSheetImage)
  11. logger.debug("The most probable background color is $backgroundColor")
  12.  
  13. return findSprites(spriteSheetImage, backgroundColor) map(::copySubImage.bindFirst(spriteSheetImage))
  14. }
  15.  
  16. private fun findSprites(image: BufferedImage,
  17. backgroundColor: Color): List<Rectangle> {
  18. val workingImage = copy(image)
  19.  
  20. val spriteRectangles = ArrayList<Rectangle>()
  21. for (pixel in workingImage) {
  22. val (point, color) = pixel
  23.  
  24. if (color != backgroundColor) {
  25. logger.debug("Found a sprite starting at (${point.x}, ${point.y})")
  26. val spritePlot = findContiguous(workingImage, point) { it != backgroundColor }
  27. val spriteRectangle = Rectangle(spritePlot, image)
  28.  
  29. logger.debug("The identified sprite has an area of ${spriteRectangle.width}x${spriteRectangle.height}")
  30.  
  31. spriteRectangles.add(spriteRectangle)
  32. eraseSprite(workingImage, backgroundColor, spritePlot)
  33. }
  34. }
  35.  
  36. logger.info("Found ${spriteRectangles.size()} sprites.")
  37. return spriteRectangles
  38. }
  39.  
  40. private fun findContiguous(image: BufferedImage, point: Point, predicate: (Color) -> Boolean): List<Point> {
  41. val unvisited = LinkedList<Point>()
  42. val visited = HashSet<Point>()
  43.  
  44. unvisited.addAll(neighbors(point, image) filter { predicate(Color(image.getRGB(it.x, it.y))) })
  45.  
  46. while (unvisited.isNotEmpty()) {
  47. val currentPoint = unvisited.pop()
  48. val currentColor = Color(image.getRGB(currentPoint.x, currentPoint.y))
  49.  
  50. if (predicate(currentColor)) {
  51. unvisited.addAll(neighbors(currentPoint, image) filter {
  52. !visited.contains(it) && !unvisited.contains(it) &&
  53. predicate(Color(image.getRGB(it.x, it.y)))
  54. })
  55.  
  56. visited.add(currentPoint)
  57. }
  58. }
  59.  
  60. return visited.toList()
  61. }
  62.  
  63. private fun neighbors(point: Point, image: Image): List<Point> {
  64. val points = ArrayList<Point>()
  65.  
  66. if (point.x > 0)
  67. points.add(Point(point.x - 1, point.y))
  68. if (point.x < image.getWidth(null) - 1)
  69. points.add(Point(point.x + 1, point.y))
  70.  
  71. if (point.y > 0)
  72. points.add(Point(point.x, point.y - 1))
  73. if (point.y < image.getHeight(null) - 1)
  74. points.add(Point(point.x, point.y + 1))
  75.  
  76. return points
  77. }
  78.  
  79. Public Function IntersectsWith(rectb As strRect, expand As Integer) As Boolean
  80. If isEmpty Or rectb.isEmpty Then Return False
  81.  
  82. If Not (m_top - expand <= rectb.m_bottom + expand) Then Return False
  83.  
  84. If Not (m_bottom + expand >= rectb.m_top - expand) Then Return False
  85.  
  86. If Not (m_left - expand <= rectb.m_right + expand) Then Return False
  87.  
  88. If Not (m_right + expand >= rectb.m_left - expand) Then Return False
  89.  
  90. Return True
  91. End Function
  92.  
  93. m_bmp = DirectCast(p_bmp.Clone(), Bitmap)
  94.  
  95. Dim lock As BitmapData = BMPLock(m_bmp)
  96.  
  97. Dim dword_bgcolor As Integer = bgcolor.ToArgb
  98.  
  99. ' first smash the copied bitmap into either BG or non bg so can search exact
  100.  
  101. For i As Integer = 0 To lock.Width * lock.Height - 1
  102. If BMPColorsAreSimilar(BMPGetPixelFastDWORD(lock, i), dword_bgcolor, tol) > 0 Then ' bg
  103. BMPSetPixelFast(lock, i, 0)
  104. Else
  105. BMPSetPixelFast(lock, i, 1)
  106. End If
  107. Next
  108.  
  109. Dim rect As strRect
  110. Dim temp_stack As New Stack ' fill algo uses this... passing it means not allocated every call
  111.  
  112. For y As Integer = 0 To lock.Height - 1
  113. For x As Integer = 0 To lock.Width - 1
  114. If BMPGetPixelFastDWORD(lock, x, y) = 1 Then ' hit a sprite so erase it with flood fill to get the bounds
  115. BMPFloodFill(lock, temp_stack, filldiag, x, y, 0)
  116. rect.SetBounds(BMPFloodFillLastMinX(), BMPFloodFillLastMaxX(), BMPFloodFillLastMinY, BMPFloodFillLastMaxY)
  117. m_bounds.Add(rect) ' add to our list of rectangles
  118. End If
  119. Next
  120. Next
  121.  
  122. int fill_dx[] = { 0, -1, 0, 1, -1, -1, 1, 1 };
  123. int fill_dy[] = { -1, 0, 1, 0, -1, 1, -1, 1 };
  124.  
  125. int fill_minx;
  126. int fill_miny;
  127. int fill_maxx;
  128. int fill_maxy;
  129.  
  130. BYTE *fill_track = 0;
  131. DWORD fill_track_size = 0;
  132.  
  133. Int32 MCUMakerSupport::MCUBitmap::BMPFloodFill(BitmapData ^%bmp_lock, Stack ^%mCods, Int32 diag, Int32 x, Int32 y, Int32 col)
  134. {
  135. diag = diag ? 8 : 4;
  136.  
  137. if (!bmp_lock)
  138. {
  139. return 0;
  140. }
  141.  
  142. int w = bmp_lock->Width;
  143. int h = bmp_lock->Height;
  144.  
  145. if (x < 0 || x >= w || y < 0 || y >= h) return 0;
  146.  
  147. refill:
  148.  
  149. if (!fill_track)
  150. {
  151. fill_track = (BYTE *)malloc(w * h);
  152. fill_track_size = w * h;
  153. }
  154. else
  155. {
  156. if (fill_track_size < w * h)
  157. {
  158. free(fill_track);
  159. fill_track = 0;
  160. fill_track_size = 0;
  161. goto refill;
  162. }
  163.  
  164. }
  165.  
  166. if (!fill_track)
  167. {
  168. fill_track_size = 0;
  169. return 0;
  170. }
  171.  
  172. memset(fill_track, 0, w * h);
  173.  
  174. //BitmapData ^bmp_lock = bmp->LockBits(Rectangle(0, 0, w, h), ImageLockMode::ReadWrite, bmp->PixelFormat);
  175.  
  176.  
  177. DWORD *fill_addr = (DWORD *)bmp_lock->Scan0.ToPointer();
  178.  
  179. DWORD fill_color = col;
  180. DWORD target_color = fill_addr[y * w + x];
  181.  
  182. //Stack ^mCods = gcnew Stack();
  183.  
  184. Point pt;
  185.  
  186. pt.X = x;
  187. pt.Y = y;
  188.  
  189. mCods->Clear();
  190.  
  191. int filled = 1;
  192.  
  193. fill_minx = fill_maxx = x;
  194. fill_miny = fill_maxy = y;
  195.  
  196. fill_addr[pt.Y * w + pt.X] = fill_color;
  197. fill_track[pt.Y * w + pt.X] = 255;
  198. mCods->Push(pt);
  199.  
  200. while (mCods->Count > 0)
  201. {
  202. recheck:
  203.  
  204. for (int i = 0; i < diag; i++)
  205. {
  206. int cx = pt.X + fill_dx[i];
  207.  
  208. if (cx < 0 || cx >= w) continue;
  209.  
  210. int cy = pt.Y + fill_dy[i];
  211.  
  212. if (cy < 0 || cy >= h) continue;
  213.  
  214. bool res = false;
  215.  
  216. if (!fill_track[cy * w + cx])
  217. {
  218. fill_track[cy * w + cx]++;
  219.  
  220. DWORD c = fill_addr[cy * w + cx];
  221.  
  222. if (c == target_color)
  223. {
  224. res = true;
  225. fill_addr[cx + cy * w] = fill_color;
  226.  
  227. if (cx < fill_minx) { fill_minx = cx; }
  228. if (cy < fill_miny) { fill_miny = cy; }
  229.  
  230. if (cx > fill_maxx) { fill_maxx = cx; }
  231. if (cy > fill_maxy) { fill_maxy = cy; }
  232. }
  233. }
  234.  
  235. if (res) // fill?
  236. {
  237. mCods->Push(pt);
  238. filled++;
  239. pt.Y = cy;
  240. pt.X = cx;
  241. goto recheck;
  242. }
  243. }
  244.  
  245. pt.X = ((Point ^)mCods->Peek())->X;
  246. pt.Y = ((Point ^)mCods->Peek())->Y;
  247. mCods->Pop();
  248. }
  249.  
  250. mCods->Clear();
  251.  
  252. return filled; // number of pixels filled
  253. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement