OSDN Git Service

Fixing author and email.
authorPaul Siegel <psiegelnospam@binkystick.com>
Sun, 30 Sep 2012 18:19:36 +0000 (14:19 -0400)
committerPaul Siegel <psiegelnospam@binkystick.com>
Sun, 30 Sep 2012 18:19:36 +0000 (14:19 -0400)
extensions/gdx-tools/src/com/badlogic/gdx/tools/imagepacker/ImageProcessor.java
extensions/gdx-tools/src/com/badlogic/gdx/tools/imagepacker/TexturePacker2.java
gdx/src/com/badlogic/gdx/graphics/g2d/NinePatch.java
gdx/src/com/badlogic/gdx/graphics/g2d/TextureAtlas.java
gdx/src/com/badlogic/gdx/scenes/scene2d/ui/Skin.java
gdx/src/com/badlogic/gdx/scenes/scene2d/utils/NinePatchDrawable.java
tests/gdx-tests-android/assets-raw/skin/default-round.9.png
tests/gdx-tests-android/assets/data/uiskin.atlas [changed mode: 0644->0755]
tests/gdx-tests-android/assets/data/uiskin.png [changed mode: 0644->0755]

index 4bdb428..d28062e 100644 (file)
@@ -8,6 +8,7 @@ import java.io.IOException;
 import java.math.BigInteger;\r
 import java.security.MessageDigest;\r
 import java.security.NoSuchAlgorithmException;\r
+import java.util.Arrays;\r
 import java.util.HashMap;\r
 import java.util.regex.Matcher;\r
 import java.util.regex.Pattern;\r
@@ -56,9 +57,11 @@ public class ImageProcessor {
 \r
                // Strip ".9" from file name, read ninepatch split pixels, and strip ninepatch split pixels.\r
                int[] splits = null;\r
+               int[] pads = null;\r
                if (name.endsWith(".9")) {\r
                        name = name.substring(0, name.length() - 2);\r
                        splits = getSplits(image, name);\r
+                       pads = getPads(image, name, splits);\r
                        // Strip split pixels.\r
                        BufferedImage newImage = new BufferedImage(image.getWidth() - 2, image.getHeight() - 2, BufferedImage.TYPE_4BYTE_ABGR);\r
                        newImage.getGraphics().drawImage(image, 0, 0, newImage.getWidth(), newImage.getHeight(), 1, 1, image.getWidth() - 1,\r
@@ -67,6 +70,7 @@ public class ImageProcessor {
                        // Ninepatches won't be rotated or whitespace stripped.\r
                        rect = new Rect(image, 0, 0, image.getWidth(), image.getHeight());\r
                        rect.splits = splits;\r
+                       rect.pads = pads;\r
                        rect.canRotate = false;\r
                }\r
 \r
@@ -181,51 +185,123 @@ public class ImageProcessor {
         * has left, right, top, bottom. */\r
        private int[] getSplits (BufferedImage image, String name) {\r
                WritableRaster raster = image.getRaster();\r
-               int[] rgba = new int[4];\r
+               \r
+               int startX = getSplitPoint(raster, name, 1, 0, true, true);\r
+               int endX = getSplitPoint(raster, name, startX, 0, false, true);\r
+               int startY = getSplitPoint(raster, name, 0, 1, true, false);\r
+               int endY = getSplitPoint(raster, name, 0, startY, false, false);\r
 \r
-               int startX = 1;\r
-               for (int x = 1; x < raster.getWidth() - 1; x++) {\r
-                       raster.getPixel(x, 0, rgba);\r
-                       if (rgba[3] == 0) continue;\r
-                       if (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0 || rgba[3] != 255) splitError(x, 0, rgba, name);\r
-                       startX = x;\r
-                       break;\r
-               }\r
-               int endX;\r
-               for (endX = startX; endX < raster.getWidth() - 1; endX++) {\r
-                       raster.getPixel(endX, 0, rgba);\r
-                       if (rgba[3] == 0) break;\r
-                       if (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0 || rgba[3] != 255) splitError(endX, 0, rgba, name);\r
+               // Ensure pixels after the end are not invalid.\r
+               getSplitPoint(raster, name, endX+1, 0, true, true);\r
+               getSplitPoint(raster, name, 0, endY+1, true, false);\r
+               \r
+               // No splits, or all splits.\r
+               if (startX == 0 && endX == 0 && startY == 0 && endY == 0) \r
+                       return null;\r
+\r
+               // Subtraction here is because the coordinates were computed before the 1px border was stripped.\r
+               if (startX != 0) {\r
+                       startX--;\r
+                       endX = raster.getWidth() - 2 - (endX - 1);\r
+               } else {\r
+                       // If no start point was ever found, we assume full stretch.\r
+                       endX = raster.getWidth() - 2;\r
                }\r
-               for (int x = endX + 1; x < raster.getWidth() - 1; x++) {\r
-                       raster.getPixel(x, 0, rgba);\r
-                       if (rgba[3] != 0) splitError(x, 0, rgba, name);\r
+               if (startY != 0) {\r
+                       startY--;\r
+                       endY = raster.getHeight() - 2 - (endY - 1);\r
+               } else {\r
+                       // If no start point was ever found, we assume full stretch.\r
+                       endY = raster.getHeight() - 2;\r
                }\r
+               \r
+               return new int[] {startX, endX, startY, endY};\r
+       }\r
+       \r
+       /** Returns the pads, or null if the image had no pads or the pads match the splits. Pads are an int[4] that\r
+        * has left, right, top, bottom. */\r
+       private int[] getPads (BufferedImage image, String name, int[] splits) {\r
+               WritableRaster raster = image.getRaster();\r
+               \r
+               int bottom = raster.getHeight() - 1;\r
+               int right = raster.getWidth() - 1;\r
+               \r
+               int startX = getSplitPoint(raster, name, 1, bottom, true, true);\r
+               int startY = getSplitPoint(raster, name, right, 1, true, false);\r
+               \r
+               // No need to hunt for the end if a start was never found.\r
+               int endX = 0;\r
+               int endY = 0;\r
+               if (startX != 0)\r
+                       endX = getSplitPoint(raster, name, startX+1, bottom, false, true);\r
+               if (startY != 0)\r
+                       endY = getSplitPoint(raster, name, right, startY+1, false, false);\r
+               \r
+               // Ensure pixels after the end are not invalid.\r
+               getSplitPoint(raster, name, endX+1, bottom, true, true);\r
+               getSplitPoint(raster, name, right, endY+1, true, false);\r
+               \r
+               // No pads.\r
+               if (startX == 0 && endX == 0 && startY == 0 && endY == 0) {\r
+                       return null;\r
+               }               \r
 \r
-               int startY = 1;\r
-               for (int y = 1; y < raster.getHeight() - 1; y++) {\r
-                       raster.getPixel(0, y, rgba);\r
-                       if (rgba[3] == 0) continue;\r
-                       if (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0 || rgba[3] != 255) splitError(0, y, rgba, name);\r
-                       startY = y;\r
-                       break;\r
+               // Subtraction here is because the coordinates were computed before the 1px border was stripped.\r
+               if (startX > 0) {\r
+                       startX--;\r
+                       endX = raster.getWidth() - 2 - (endX - 1);\r
+               } else {\r
+                       // If no start point was ever found, we assume full stretch.\r
+                       endX = raster.getWidth() - 2;\r
                }\r
-               int endY;\r
-               for (endY = startY; endY < raster.getHeight() - 1; endY++) {\r
-                       raster.getPixel(0, endY, rgba);\r
-                       if (rgba[3] == 0) break;\r
-                       if (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0 || rgba[3] != 255) splitError(0, endY, rgba, name);\r
+               if (startY > 0) {\r
+                       startY--;\r
+                       endY = raster.getHeight() - 2 - (endY - 1);\r
+               } else {\r
+                       // If no start point was ever found, we assume full stretch.\r
+                       endY = raster.getHeight() - 2;\r
                }\r
-               for (int y = endY + 1; y < raster.getHeight() - 1; y++) {\r
-                       raster.getPixel(0, y, rgba);\r
-                       if (rgba[3] != 0) splitError(0, y, rgba, name);\r
+               \r
+               int[] pads = new int[] {startX, endX, startY, endY};\r
+               \r
+               if ((splits != null) && Arrays.equals(pads, splits)) {\r
+                       return null;\r
                }\r
+               \r
+               return pads;\r
+       }\r
+       \r
+       /** Hunts for the start or end of a sequence of split pixels.  Begins searching at (startX, startY) then follows\r
+        * along the x or y axis (depending on value of xAxis) for the first non-transparent pixel if startPoint is true,\r
+        * or the first transparent pixel if startPoint is false.  Returns 0 if none found, as 0 is considered an invalid\r
+        * split point being in the outer border which will be stripped. */\r
+       private int getSplitPoint(WritableRaster raster, String name, int startX, int startY, boolean startPoint, boolean xAxis) \r
+       {\r
+               int[] rgba = new int[4];\r
 \r
-               // No splits, or all splits.\r
-               if (startX == 1 && endX == 1 && startY == 1 && endY == 1) return null;\r
-\r
-               // Subtraction here is because the coordinates were computed before the 1px border was stripped.\r
-               return new int[] {startX - 1, raster.getWidth() - 2 - (endX - 1), startY - 1, raster.getHeight() - 2 - (endY - 1)};\r
+               int next = xAxis ? startX : startY;\r
+               int end = xAxis ? raster.getWidth() : raster.getHeight();\r
+               int breakA = startPoint ? 255 : 0;\r
+               \r
+               int x = startX;\r
+               int y = startY;\r
+               while (next != end) {\r
+                       if (xAxis)\r
+                               x = next;\r
+                       else\r
+                               y = next;\r
+                       \r
+                       raster.getPixel(x, y, rgba);\r
+                       if (rgba[3] == breakA)\r
+                               return next;\r
+                       \r
+                       if (!startPoint && (rgba[0] != 0 || rgba[1] != 0 || rgba[2] != 0 || rgba[3] != 255))\r
+                               splitError(x, y, rgba, name);\r
+                       \r
+                       next++;\r
+               }\r
+               \r
+               return 0;\r
        }\r
 \r
        static private String hash (BufferedImage image) {\r
index 6751120..a70b840 100644 (file)
@@ -193,6 +193,9 @@ public class TexturePacker2 {
                if (rect.splits != null) {\r
                        writer\r
                                .write("  split: " + rect.splits[0] + ", " + rect.splits[1] + ", " + rect.splits[2] + ", " + rect.splits[3] + "\n");\r
+                       if (rect.pads != null) {\r
+                               writer.write("  pads: " + rect.pads[0] + ", " + rect.pads[1] + ", " + rect.pads[2] + ", " + rect.pads[3] + "\n");\r
+                       }\r
                }\r
                writer.write("  orig: " + rect.originalWidth + ", " + rect.originalHeight + "\n");\r
                writer.write("  offset: " + rect.offsetX + ", " + (rect.originalHeight - rect.image.getHeight() - rect.offsetY) + "\n");\r
@@ -239,6 +242,7 @@ public class TexturePacker2 {
                public boolean rotated;\r
                public ArrayList<Rect> aliases = new ArrayList();\r
                public int[] splits;\r
+               public int[] pads;\r
                public boolean canRotate = true;\r
 \r
                int score1, score2;\r
@@ -283,6 +287,7 @@ public class TexturePacker2 {
                        rotated = rect.rotated;\r
                        aliases = rect.aliases;\r
                        splits = rect.splits;\r
+                       pads = rect.pads;\r
                        canRotate = rect.canRotate;\r
                        score1 = rect.score1;\r
                        score2 = rect.score2;\r
index ad31555..008c27d 100644 (file)
@@ -41,7 +41,13 @@ public class NinePatch {
        private float[] vertices = new float[9 * 4 * 5];\r
        private int idx;\r
        private final Color color = new Color(Color.WHITE);\r
-\r
+       \r
+       /** Padding overrides are stored by NinePatch for use by elements such as tables that use\r
+        *  a NinePatch for their background.   If these values are not set, the width/height of \r
+        *  border patches are used (eg. leftWidth, rightWidth, topHeight, and bottomHeight).\r
+        */\r
+       private int padLeft = -1, padRight = -1, padTop = -1, padBottom = -1;\r
+       \r
        public NinePatch (Texture texture, int left, int right, int top, int bottom) {\r
                this(new TextureRegion(texture), left, right, top, bottom);\r
        }\r
@@ -367,4 +373,51 @@ public class NinePatch {
        public float getTotalHeight () {\r
                return topHeight + middleHeight + bottomHeight;\r
        }\r
+       \r
+       public void setPadding(int left, int right, int top, int bottom) {\r
+               this.padLeft = left;\r
+               this.padRight = right;\r
+               this.padTop = top;\r
+               this.padBottom = bottom;\r
+       }\r
+       \r
+       public void setPadLeft(int left) {\r
+               this.padLeft = left;\r
+       }\r
+       \r
+       public void setPadRight(int right) {\r
+               this.padRight = right;\r
+       }\r
+       \r
+       public void setPadTop(int top) {\r
+               this.padTop = top;\r
+       }\r
+       \r
+       public void setPadBottom(int bottom) {\r
+               this.padBottom = bottom;\r
+       }\r
+       \r
+       public float getPadLeft() {\r
+               if (this.padLeft == -1)\r
+                       return this.getLeftWidth();\r
+               return this.padLeft;\r
+       }\r
+       \r
+       public float getPadRight() {\r
+               if (this.padRight == -1)\r
+                       return this.getRightWidth();\r
+               return this.padRight;\r
+       }\r
+       \r
+       public float getPadTop() {\r
+               if (this.padTop == -1)\r
+                       return this.getTopHeight();\r
+               return this.padTop;\r
+       }\r
+       \r
+       public float getPadBottom() {\r
+               if (this.padBottom == -1)\r
+                       return this.getBottomHeight();\r
+               return this.padBottom;\r
+       }       \r
 }\r
index b84e2c3..a549af7 100644 (file)
@@ -88,6 +88,7 @@ public class TextureAtlas implements Disposable {
                        public int height;\r
                        public boolean flip;\r
                        public int[] splits;\r
+                       public int[] pads;\r
                }\r
 \r
                final Array<Page> pages = new Array<Page>();\r
@@ -148,7 +149,13 @@ public class TextureAtlas implements Disposable {
                                                if (readTuple(reader) == 4) { // split is optional\r
                                                        region.splits = new int[] {Integer.parseInt(tuple[0]), Integer.parseInt(tuple[1]),\r
                                                                Integer.parseInt(tuple[2]), Integer.parseInt(tuple[3])};\r
-                                                       readTuple(reader);\r
+                                                       \r
+                                                       if (readTuple(reader) == 4) { // pads are optional, but only present with splits\r
+                                                               region.pads = new int[] {Integer.parseInt(tuple[0]), Integer.parseInt(tuple[1]),\r
+                                                                       Integer.parseInt(tuple[2]), Integer.parseInt(tuple[3])};\r
+                                                               \r
+                                                               readTuple(reader);\r
+                                                       }\r
                                                }\r
 \r
                                                region.originalWidth = Integer.parseInt(tuple[0]);\r
@@ -250,6 +257,7 @@ public class TextureAtlas implements Disposable {
                        atlasRegion.originalWidth = region.originalWidth;\r
                        atlasRegion.rotate = region.rotate;\r
                        atlasRegion.splits = region.splits;\r
+                       atlasRegion.pads = region.pads;\r
                        if (region.flip) atlasRegion.flip(false, true);\r
                        regions.add(atlasRegion);\r
                }\r
@@ -381,7 +389,11 @@ public class TextureAtlas implements Disposable {
                        if (region.name.equals(name)) {\r
                                int[] splits = region.splits;\r
                                if (splits == null) throw new IllegalArgumentException("Region does not have ninepatch splits: " + name);\r
-                               return new NinePatch(region, splits[0], splits[1], splits[2], splits[3]);\r
+                               NinePatch retVal = new NinePatch(region, splits[0], splits[1], splits[2], splits[3]);\r
+                               if (region.pads != null) {\r
+                                       retVal.setPadding(region.pads[0], region.pads[1], region.pads[2], region.pads[3]);\r
+                               }\r
+                               return retVal;\r
                        }\r
                }\r
                return null;\r
@@ -473,6 +485,10 @@ public class TextureAtlas implements Disposable {
 \r
                /** The ninepatch splits, or null if not a ninepatch. Has 4 elements: left, right, top, bottom. */\r
                public int[] splits;\r
+               \r
+               /** The ninepatch pads, or null if not a ninepatch or ninepatch does not override padding.\r
+                *  Has 4 elements: left, right, top, bottom. */\r
+               public int[] pads;\r
 \r
                public AtlasRegion (Texture texture, int x, int y, int width, int height) {\r
                        super(texture, x, y, width, height);\r
index 75a82a1..47ddaa3 100644 (file)
@@ -211,7 +211,13 @@ public class Skin implements Disposable {
                        TextureRegion region = getRegion(name);\r
                        if (region instanceof AtlasRegion) {\r
                                int[] splits = ((AtlasRegion)region).splits;\r
-                               if (splits != null) patch = new NinePatch(region, splits[0], splits[1], splits[2], splits[3]);\r
+                               if (splits != null) {\r
+                                       patch = new NinePatch(region, splits[0], splits[1], splits[2], splits[3]);\r
+                                       int[] pads = ((AtlasRegion)region).pads;\r
+                                       if (pads != null) {\r
+                                               patch.setPadding(pads[0], pads[1], pads[2], pads[3]);\r
+                                       }\r
+                               }\r
                        }\r
                        if (patch == null) patch = new NinePatch(region);\r
                        add(name, patch, NinePatch.class);\r
index 5126db9..7e7bfc4 100644 (file)
@@ -52,10 +52,10 @@ public class NinePatchDrawable extends BaseDrawable {
                this.patch = patch;\r
                setMinWidth(patch.getTotalWidth());\r
                setMinHeight(patch.getTotalHeight());\r
-               setTopHeight(patch.getTopHeight());\r
-               setRightWidth(patch.getRightWidth());\r
-               setBottomHeight(patch.getBottomHeight());\r
-               setLeftWidth(patch.getLeftWidth());\r
+               setTopHeight(patch.getPadTop());\r
+               setRightWidth(patch.getPadRight());\r
+               setBottomHeight(patch.getPadBottom());\r
+               setLeftWidth(patch.getPadLeft());\r
        }\r
 \r
        public NinePatch getPatch () {\r
index 55cf73f..adf9568 100644 (file)
Binary files a/tests/gdx-tests-android/assets-raw/skin/default-round.9.png and b/tests/gdx-tests-android/assets-raw/skin/default-round.9.png differ
old mode 100644 (file)
new mode 100755 (executable)
index 2aa740d..b230e82
@@ -54,6 +54,7 @@ default-round
   xy: 91, 29
   size: 12, 20
   split: 5, 5, 5, 4
+  pads: 4, 4, 1, 1
   orig: 12, 20
   offset: 0, 0
   index: -1
old mode 100644 (file)
new mode 100755 (executable)