From 7b813ad9c1676821ef0b737c2a16cac3f05f58f3 Mon Sep 17 00:00:00 2001 From: "nathan.sweet" Date: Sun, 21 Nov 2010 06:27:17 +0000 Subject: [PATCH] [fixed] SpriteSheet/SpriteSheetPacker bugs. [changed] ParticleEmitter to take Sprite rather than Texture. [added] Sprite copy constructor. [fixed] Sprite scale bug. --- .../gdx/imagepacker/SpriteSheetPacker.java | 122 +++++++++++---------- .../gdx/graphics/particles/EffectPanel.java | 2 +- .../gdx/graphics/particles/ImagePanel.java | 2 +- .../gdx/graphics/particles/ParticleEditor.java | 24 +++- gdx/src/com/badlogic/gdx/graphics/Sprite.java | 38 +++++-- gdx/src/com/badlogic/gdx/graphics/SpriteSheet.java | 35 +++--- .../gdx/graphics/particles/ParticleEffect.java | 35 ++++-- .../gdx/graphics/particles/ParticleEmitter.java | 73 ++++++------ 8 files changed, 203 insertions(+), 128 deletions(-) diff --git a/extensions/image-packer/src/com/badlogic/gdx/imagepacker/SpriteSheetPacker.java b/extensions/image-packer/src/com/badlogic/gdx/imagepacker/SpriteSheetPacker.java index 3bd59f158..a598e442d 100644 --- a/extensions/image-packer/src/com/badlogic/gdx/imagepacker/SpriteSheetPacker.java +++ b/extensions/image-packer/src/com/badlogic/gdx/imagepacker/SpriteSheetPacker.java @@ -43,13 +43,6 @@ public class SpriteSheetPacker { this.inputDir = inputDir; this.filter = filter; - minWidth = filter.width != -1 ? filter.width : settings.minWidth; - minHeight = filter.height != -1 ? filter.height : settings.minHeight; - maxWidth = filter.width != -1 ? filter.width : settings.maxWidth; - maxHeight = filter.height != -1 ? filter.height : settings.maxHeight; - xPadding = images.size() > 1 && filter.direction != Direction.x && filter.direction != Direction.xy ? settings.padding : 0; - yPadding = images.size() > 1 && filter.direction != Direction.y && filter.direction != Direction.xy ? settings.padding : 0; - // Collect and squeeze images. File[] files = inputDir.listFiles(filter); if (files == null) return; @@ -60,6 +53,13 @@ public class SpriteSheetPacker { } if (images.isEmpty()) return; + minWidth = filter.width != -1 ? filter.width : settings.minWidth; + minHeight = filter.height != -1 ? filter.height : settings.minHeight; + maxWidth = filter.width != -1 ? filter.width : settings.maxWidth; + maxHeight = filter.height != -1 ? filter.height : settings.maxHeight; + xPadding = images.size() > 1 && !filter.direction.isX() ? settings.padding : 0; + yPadding = images.size() > 1 && !filter.direction.isY() ? settings.padding : 0; + System.out.println(inputDir); if (filter.format != null) System.out.println("Format: " + filter.format); @@ -87,27 +87,6 @@ public class SpriteSheetPacker { } private void writePage (String prefix, File outputDir) throws IOException { - // Remove existing image pages in output dir. - int imageNumber = 1; - File outputFile = new File(outputDir, prefix + imageNumber + ".png"); - while (outputFile.exists()) - outputFile = new File(outputDir, prefix + ++imageNumber + ".png"); - - writer.write("\n" + prefix + imageNumber + ".png\n"); - Format format; - if (filter.format != null) { - writer.write("format: " + filter.format + "\n"); - format = filter.format; - } else { - writer.write("format: " + settings.defaultFormat + "\n"); - format = settings.defaultFormat; - } - if (filter.minFilter == null || filter.magFilter == null) - writer.write("filter: " + settings.defaultFilterMin + "," + settings.defaultFilterMag + "\n"); - else - writer.write("filter: " + filter.minFilter + "," + filter.magFilter + "\n"); - writer.write("repeat: " + filter.direction + "\n"); - // Try reasonably hard to pack images into the smallest POT size. Comparator bestComparator = null; Comparator secondBestComparator = imageComparators.get(0); @@ -118,7 +97,6 @@ public class SpriteSheetPacker { int grownPixels = 0, grownPixels2 = 0; int i = 0, ii = 0; while (true) { - if (width > maxWidth && height > maxHeight) break; for (Comparator comparator : imageComparators) { // Pack as many images as possible, sorting the images different ways. Collections.sort(images, comparator); @@ -138,19 +116,17 @@ public class SpriteSheetPacker { } } } + if (width == maxWidth && height == maxHeight) break; if (bestComparator != null) break; if (settings.pot) { - // 64,64 then 64,128 then 128,64 then 128,128 then 128,256 etc. - if (i % 3 == 0) { - width *= 2; - i++; - } else if (i % 3 == 1) { - width /= 2; + // 64,64 then 64,128 then 64,256 etc then 128,64 then 128,128 then 128,256 etc. + grownPixels += width; + width *= 2; + if (width > maxWidth) { + width -= grownPixels; + grownPixels = 0; height *= 2; - i++; - } else { width *= 2; - i++; } } else { // 64-127,64 then 64,64-127 then 128-255,128 then 128,128-255 etc. @@ -179,6 +155,8 @@ public class SpriteSheetPacker { i++; } } + width = Math.min(maxWidth, width); + height = Math.min(maxHeight, height); } if (bestComparator != null) { Collections.sort(images, bestComparator); @@ -195,7 +173,7 @@ public class SpriteSheetPacker { } int type; - switch (format) { + switch (filter.format != null ? filter.format : settings.defaultFormat) { case RGBA8888: case RGBA4444: type = BufferedImage.TYPE_INT_ARGB; @@ -209,6 +187,27 @@ public class SpriteSheetPacker { default: throw new RuntimeException(); } + + int imageNumber = 1; + File outputFile = new File(outputDir, prefix + imageNumber + ".png"); + while (outputFile.exists()) + outputFile = new File(outputDir, prefix + ++imageNumber + ".png"); + + writer.write("\n" + outputFile.getName() + "\n"); + Format format; + if (filter.format != null) { + writer.write("format: " + filter.format + "\n"); + format = filter.format; + } else { + writer.write("format: " + settings.defaultFormat + "\n"); + format = settings.defaultFormat; + } + if (filter.minFilter == null || filter.magFilter == null) + writer.write("filter: " + settings.defaultFilterMin + "," + settings.defaultFilterMag + "\n"); + else + writer.write("filter: " + filter.minFilter + "," + filter.magFilter + "\n"); + writer.write("repeat: " + filter.direction + "\n"); + BufferedImage canvas = new BufferedImage(width, height, type); insert(canvas, images, bestWidth, bestHeight); System.out.println("Writing " + canvas.getWidth() + "x" + canvas.getHeight() + ": " + outputFile); @@ -223,8 +222,8 @@ public class SpriteSheetPacker { g.drawRect(0, 0, width - 1, height - 1); } // Pretend image is larger so padding on right and bottom edges is ignored. - if (filter.direction != Direction.x && filter.direction != Direction.xy) width += xPadding; - if (filter.direction != Direction.y && filter.direction != Direction.xy) height += yPadding; + if (!filter.direction.isX()) width += xPadding; + if (!filter.direction.isY()) height += yPadding; Node root = new Node(0, 0, width, height); int usedPixels = 0; for (int i = images.size() - 1; i >= 0; i--) { @@ -276,7 +275,7 @@ public class SpriteSheetPacker { final byte[] a = new byte[1]; int top = 0; int bottom = source.getHeight(); - if (filter.direction != Direction.y && filter.direction != Direction.xy) { + if (!filter.direction.isY()) { outer: for (int y = 0; y < source.getHeight(); y++) { for (int x = 0; x < source.getWidth(); x++) { @@ -300,10 +299,10 @@ public class SpriteSheetPacker { } int left = 0; int right = source.getWidth(); - if (filter.direction != Direction.x && filter.direction != Direction.xy) { + if (!filter.direction.isX()) { outer: for (int x = 0; x < source.getWidth(); x++) { - for (int y = top; y <= bottom; y++) { + for (int y = top; y < bottom; y++) { alphaRaster.getDataElements(x, y, a); int alpha = a[0]; if (alpha < 0) alpha += 256; @@ -313,7 +312,7 @@ public class SpriteSheetPacker { } outer: for (int x = source.getWidth(); --x >= left;) { - for (int y = top; y <= bottom; y++) { + for (int y = top; y < bottom; y++) { alphaRaster.getDataElements(x, y, a); int alpha = a[0]; if (alpha < 0) alpha += 256; @@ -388,7 +387,7 @@ public class SpriteSheetPacker { if (imageName.startsWith("/") || imageName.startsWith("\\")) imageName = imageName.substring(1); int dotIndex = imageName.lastIndexOf('.'); if (dotIndex != -1) imageName = imageName.substring(0, dotIndex); - imageName = imageName.replace("_" + filter.format, ""); + imageName = imageName.replace("_" + formatToAbbrev.get(filter.format), ""); imageName = imageName.replace("_" + filter.direction, ""); imageName = imageName.replace("_" + filterToAbbrev.get(filter.minFilter) + "," + filterToAbbrev.get(filter.magFilter), ""); @@ -461,9 +460,7 @@ public class SpriteSheetPacker { int height = -1; Settings settings; - public Filter (Settings settings, Direction direction, Format format, int width, int height, TextureFilter minFilter, - TextureFilter magFilter) { - this.settings = settings; + public Filter (Direction direction, Format format, int width, int height, TextureFilter minFilter, TextureFilter magFilter) { this.direction = direction; this.format = format; this.width = width; @@ -523,7 +520,15 @@ public class SpriteSheetPacker { } static private enum Direction { - x, y, xy, none + x, y, xy, none; + + public boolean isX () { + return this == x || this == xy; + } + + public boolean isY () { + return this == y || this == xy; + } } static final HashMap filterToAbbrev = new HashMap(); @@ -561,6 +566,8 @@ public class SpriteSheetPacker { } static private void process (Settings settings, File inputDir, File outputDir, File packFile) throws Exception { + if (inputDir.getName().startsWith(".")) return; + // Clean existing page images. if (outputDir.exists()) { String prefix = inputDir.getName(); @@ -583,22 +590,22 @@ public class SpriteSheetPacker { TextureFilter mag = filters.get(iii); if ((min == null && mag != null) || (min != null && mag == null)) continue; - Filter filter = new Filter(settings, Direction.none, format, -1, -1, min, mag); + Filter filter = new Filter(Direction.none, format, -1, -1, min, mag); new SpriteSheetPacker(settings, inputDir, filter, outputDir, packFile); for (int width = settings.minWidth; width <= settings.maxWidth; width <<= 1) { - filter = new Filter(settings, Direction.x, format, width, -1, min, mag); + filter = new Filter(Direction.x, format, width, -1, min, mag); new SpriteSheetPacker(settings, inputDir, filter, outputDir, packFile); } for (int height = settings.minHeight; height <= settings.maxHeight; height <<= 1) { - filter = new Filter(settings, Direction.y, format, -1, height, min, mag); + filter = new Filter(Direction.y, format, -1, height, min, mag); new SpriteSheetPacker(settings, inputDir, filter, outputDir, packFile); } for (int width = settings.minWidth; width <= settings.maxWidth; width <<= 1) { for (int height = settings.minHeight; height <= settings.maxHeight; height <<= 1) { - filter = new Filter(settings, Direction.xy, format, width, height, min, mag); + filter = new Filter(Direction.xy, format, width, height, min, mag); new SpriteSheetPacker(settings, inputDir, filter, outputDir, packFile); } } @@ -610,7 +617,7 @@ public class SpriteSheetPacker { File[] files = inputDir.listFiles(); if (files == null) return; for (File file : files) - if (file.isDirectory()) process(settings, file, new File(outputDir, file.getName()), packFile); + if (file.isDirectory()) process(settings, file, outputDir, packFile); } static public void process (Settings settings, String input, String output) throws Exception { @@ -637,8 +644,7 @@ public class SpriteSheetPacker { } input = args[0]; output = args[1]; - // input = "c:/temp/pack-in"; - // output = "c:/temp/pack-out"; - process(new Settings(), input, output); + Settings settings = new Settings(); + process(settings, input, output); } } diff --git a/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/EffectPanel.java b/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/EffectPanel.java index 6189dfa58..a6b8051ea 100644 --- a/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/EffectPanel.java +++ b/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/EffectPanel.java @@ -108,7 +108,7 @@ class EffectPanel extends JPanel { lastDir = dir; ParticleEffect effect = new ParticleEffect(); try { - effect.loadEmitters(Gdx.files.getFileHandle(new File(dir, file).getAbsolutePath(), FileType.Absolute)); + effect.loadEmitters(Gdx.files.absolute(new File(dir, file).getAbsolutePath())); editor.effect = effect; emitterTableModel.getDataVector().removeAllElements(); editor.particleData.clear(); diff --git a/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/ImagePanel.java b/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/ImagePanel.java index c1e46c09f..3a9962c6a 100644 --- a/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/ImagePanel.java +++ b/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/ImagePanel.java @@ -44,7 +44,7 @@ class ImagePanel extends EditorPanel { heightLabel.setText("Height: " + icon.getIconHeight()); revalidate(); emitter.setImagePath(new File(dir, file).getAbsolutePath()); - emitter.setTexture(null); + emitter.setSprite(null); } catch (Exception ex) { ex.printStackTrace(); } diff --git a/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/ParticleEditor.java b/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/ParticleEditor.java index 364ba0315..16c13395a 100644 --- a/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/ParticleEditor.java +++ b/extensions/particle-editor/src/com/badlogic/gdx/graphics/particles/ParticleEditor.java @@ -33,6 +33,7 @@ import com.badlogic.gdx.Files.FileType; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.InputProcessor; import com.badlogic.gdx.backends.lwjgl.LwjglCanvas; +import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.graphics.BitmapFont; import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.GL10; @@ -150,6 +151,7 @@ public class ParticleEditor extends JFrame { ParticleData data = particleData.get(emitter); if (data == null) particleData.put(emitter, data = new ParticleData()); data.enabled = enabled; + emitter.reset(); } public boolean isEnabled (ParticleEmitter emitter) { @@ -265,15 +267,18 @@ public class ParticleEditor extends JFrame { } activeCount = 0; + boolean complete = true; for (ParticleEmitter emitter : effect.getEmitters()) { - if (emitter.getTexture() == null && emitter.getImagePath() != null) loadImage(emitter); + if (emitter.getSprite() == null && emitter.getImagePath() != null) loadImage(emitter); boolean enabled = isEnabled(emitter); if (enabled) { - if (emitter.getTexture() != null) emitter.draw(spriteBatch, delta); + if (emitter.getSprite() != null) emitter.draw(spriteBatch, delta); activeCount += emitter.getActiveCount(); + if (emitter.isContinuous()) complete = false; + if (!emitter.isComplete()) complete = false; } } - if (effect.isComplete()) effect.start(); + if (complete) effect.start(); maxActive = Math.max(maxActive, activeCount); maxActiveTimer += delta; @@ -296,15 +301,22 @@ public class ParticleEditor extends JFrame { spriteBatch.end(); // gl.drawLine((int)(viewWidth * getCurrentParticles().getPercentComplete()), viewHeight - 1, viewWidth, viewHeight - -// 1); + // 1); } private void loadImage (ParticleEmitter emitter) { final String imagePath = emitter.getImagePath(); + String imageName = new File(imagePath.replace('\\', '/')).getName(); try { - emitter.setTexture(Gdx.graphics.newTexture(Gdx.files.getFileHandle(imagePath, FileType.Absolute), - TextureFilter.Linear, TextureFilter.Linear, TextureWrap.ClampToEdge, TextureWrap.ClampToEdge)); + FileHandle file; + if (imagePath.equals("particle.png")) + file = Gdx.files.classpath(imagePath); + else + file = Gdx.files.absolute(imagePath); + emitter.setSprite(new Sprite(Gdx.graphics.newTexture(file, TextureFilter.Linear, TextureFilter.Linear, + TextureWrap.ClampToEdge, TextureWrap.ClampToEdge))); } catch (GdxRuntimeException ex) { + ex.printStackTrace(); EventQueue.invokeLater(new Runnable() { public void run () { JOptionPane.showMessageDialog(ParticleEditor.this, "Error loading image:\n" + imagePath); diff --git a/gdx/src/com/badlogic/gdx/graphics/Sprite.java b/gdx/src/com/badlogic/gdx/graphics/Sprite.java index 245658a4a..65493d896 100644 --- a/gdx/src/com/badlogic/gdx/graphics/Sprite.java +++ b/gdx/src/com/badlogic/gdx/graphics/Sprite.java @@ -21,14 +21,14 @@ public class Sprite { static final int VERTEX_SIZE = 2 + 1 + 2; static final int SPRITE_SIZE = 4 * VERTEX_SIZE; - Texture texture; - private float[] vertices = new float[20]; + private Texture texture; + private final float[] vertices = new float[20]; private float x, y; private float width, height; private float originX, originY; private float rotation; private float scaleX = 1, scaleY = 1; - private Color color = new Color(1, 1, 1, 1); + private final Color color = new Color(1, 1, 1, 1); private boolean dirty; /** @@ -101,6 +101,26 @@ public class Sprite { } /** + * Creates a sprite that is a copy in every way of the specified sprite. + */ + public Sprite (Sprite sprite) { + if (sprite == null) throw new IllegalArgumentException("sprite cannot be null."); + texture = sprite.texture; + System.arraycopy(sprite.vertices, 0, vertices, 0, 20); + x = sprite.x; + y = sprite.y; + width = sprite.width; + height = sprite.height; + originX = sprite.originX; + originY = sprite.originY; + rotation = sprite.rotation; + scaleX = sprite.scaleX; + scaleY = sprite.scaleY; + color.set(sprite.color); + dirty = sprite.dirty; + } + + /** * Sets the position and size of the sprite when drawn, before scaling and * rotation are applied. If origin, rotation, or scale are changed, it is * slightly more efficient to set the bounds after those operations. @@ -415,18 +435,18 @@ public class Sprite { dirty = false; float[] vertices = this.vertices; - float localX = -originX * scaleX; - float localY = -originY * scaleY; - float localX2 = (-originX + width) * scaleX; - float localY2 = (-originY + height) * scaleY; + float localX = -originX; + float localY = -originY; + float localX2 = localX + width; + float localY2 = localY + height; + float worldOriginX = this.x - localX; + float worldOriginY = this.y - localY; if (scaleX != 1 || scaleY != 1) { localX *= scaleX; localY *= scaleY; localX2 *= scaleX; localY2 *= scaleY; } - float worldOriginX = this.x + originX; - float worldOriginY = this.y + originY; if (rotation != 0) { float cos = MathUtils.cosDeg(rotation); float sin = MathUtils.sinDeg(rotation); diff --git a/gdx/src/com/badlogic/gdx/graphics/SpriteSheet.java b/gdx/src/com/badlogic/gdx/graphics/SpriteSheet.java index 5b2175fd7..f45ed3bd4 100644 --- a/gdx/src/com/badlogic/gdx/graphics/SpriteSheet.java +++ b/gdx/src/com/badlogic/gdx/graphics/SpriteSheet.java @@ -31,6 +31,10 @@ public class SpriteSheet { private final PackedSprite[] images; public SpriteSheet (FileHandle packFile, FileHandle imagesDir) { + this(packFile, imagesDir, false); + } + + public SpriteSheet (FileHandle packFile, FileHandle imagesDir, boolean flip) { PriorityQueue sortedSprites = new PriorityQueue(16, indexComparator); BufferedReader reader = new BufferedReader(new InputStreamReader(packFile.read()), 64); @@ -78,27 +82,28 @@ public class SpriteSheet { int width = Integer.parseInt(tuple[0]); int height = Integer.parseInt(tuple[1]); - PackedSprite image; + PackedSprite sprite; if (rotate) { - image = new PackedSprite(pageImage, left, top, height, width); - image.rotate90(true); + sprite = new PackedSprite(pageImage, left, top, height, width); + sprite.rotate90(true); } else - image = new PackedSprite(pageImage, left, top, width, height); - image.name = line; + sprite = new PackedSprite(pageImage, left, top, width, height); + sprite.name = line; readTuple(reader); - image.originalWidth = Integer.parseInt(tuple[0]); - image.originalHeight = Integer.parseInt(tuple[1]); + sprite.originalWidth = Integer.parseInt(tuple[0]); + sprite.originalHeight = Integer.parseInt(tuple[1]); readTuple(reader); - image.offsetX = Integer.parseInt(tuple[0]); - image.offsetY = Integer.parseInt(tuple[1]); - image.setPosition(image.offsetX, image.offsetY); + sprite.offsetX = Integer.parseInt(tuple[0]); + sprite.offsetY = Integer.parseInt(tuple[1]); + sprite.setPosition(sprite.offsetX, sprite.offsetY); - image.index = Integer.parseInt(readValue(reader)); - if (image.index == -1) image.index = Integer.MAX_VALUE; + sprite.index = Integer.parseInt(readValue(reader)); + if (sprite.index == -1) sprite.index = Integer.MAX_VALUE; - sortedSprites.add(image); + if (flip) sprite.flip(false, true); + sortedSprites.add(sprite); } } } catch (IOException ex) { @@ -195,6 +200,10 @@ public class SpriteSheet { super.setBounds(x + offsetX, y + offsetY, width, height); } + public void setOrigin (float originX, float originY) { + super.setOrigin(originX + offsetX, originY + offsetY); + } + /** * The name of the original image file, with any trailing numbers or special flags removed. */ diff --git a/gdx/src/com/badlogic/gdx/graphics/particles/ParticleEffect.java b/gdx/src/com/badlogic/gdx/graphics/particles/ParticleEffect.java index dc4bc181f..19532bbb8 100644 --- a/gdx/src/com/badlogic/gdx/graphics/particles/ParticleEffect.java +++ b/gdx/src/com/badlogic/gdx/graphics/particles/ParticleEffect.java @@ -10,10 +10,12 @@ import java.io.InputStreamReader; import java.io.Writer; import java.util.ArrayList; -import com.badlogic.gdx.Files.FileType; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.files.FileHandle; +import com.badlogic.gdx.graphics.Sprite; import com.badlogic.gdx.graphics.SpriteBatch; +import com.badlogic.gdx.graphics.SpriteSheet; +import com.badlogic.gdx.graphics.SpriteSheet.PackedSprite; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.Texture.TextureFilter; import com.badlogic.gdx.graphics.Texture.TextureWrap; @@ -94,8 +96,13 @@ public class ParticleEffect { loadEmitterImages(imagesDir); } - void loadEmitters (FileHandle file) { - InputStream input = file.read(); + public void load (FileHandle effectFile, SpriteSheet spriteSheet) { + loadEmitters(effectFile); + loadEmitterImages(spriteSheet); + } + + public void loadEmitters (FileHandle effectFile) { + InputStream input = effectFile.read(); emitters.clear(); BufferedReader reader = null; try { @@ -103,13 +110,13 @@ public class ParticleEffect { while (true) { ParticleEmitter emitter = new ParticleEmitter(reader); reader.readLine(); - emitter.setImagePath(ParticleEmitter.readString(reader, "Image Path")); + emitter.setImagePath(reader.readLine()); emitters.add(emitter); if (reader.readLine() == null) break; if (reader.readLine() == null) break; } } catch (IOException ex) { - throw new GdxRuntimeException("Error loading effect: " + file, ex); + throw new GdxRuntimeException("Error loading effect: " + effectFile, ex); } finally { try { if (reader != null) reader.close(); @@ -118,13 +125,27 @@ public class ParticleEffect { } } - private void loadEmitterImages (FileHandle imagesDir) { + public void loadEmitterImages (SpriteSheet spriteSheet) { + for (int i = 0, n = emitters.size(); i < n; i++) { + ParticleEmitter emitter = emitters.get(i); + String imagePath = emitter.getImagePath(); + if (imagePath == null) continue; + String imageName = new File(imagePath.replace('\\', '/')).getName(); + int lastDotIndex = imageName.lastIndexOf('.'); + if (lastDotIndex != -1) imageName = imageName.substring(0, lastDotIndex); + Sprite sprite = spriteSheet.get(imageName); + if (sprite == null) throw new IllegalArgumentException("SpriteSheet missing image: " + imageName); + emitter.setSprite(sprite); + } + } + + public void loadEmitterImages (FileHandle imagesDir) { for (int i = 0, n = emitters.size(); i < n; i++) { ParticleEmitter emitter = emitters.get(i); String imagePath = emitter.getImagePath(); if (imagePath == null) continue; String imageName = new File(imagePath.replace('\\', '/')).getName(); - emitter.setTexture(loadTexture(imagesDir.child(imageName))); + emitter.setSprite(new Sprite(loadTexture(imagesDir.child(imageName)))); } } diff --git a/gdx/src/com/badlogic/gdx/graphics/particles/ParticleEmitter.java b/gdx/src/com/badlogic/gdx/graphics/particles/ParticleEmitter.java index 97273b82e..893341be6 100644 --- a/gdx/src/com/badlogic/gdx/graphics/particles/ParticleEmitter.java +++ b/gdx/src/com/badlogic/gdx/graphics/particles/ParticleEmitter.java @@ -43,10 +43,9 @@ public class ParticleEmitter { private ScaledNumericValue spawnHeightValue = new ScaledNumericValue(); private SpawnShapeValue spawnShapeValue = new SpawnShapeValue(); - private Texture texture; + private Sprite sprite; private Particle[] particles; private int minParticleCount, maxParticleCount = 4; - private float imageAspectRatio; private int x, y; private String name; private String imagePath; @@ -80,8 +79,7 @@ public class ParticleEmitter { } public ParticleEmitter (ParticleEmitter emitter) { - texture = emitter.texture; - imageAspectRatio = emitter.imageAspectRatio; + sprite = emitter.sprite; setMaxParticleCount(emitter.maxParticleCount); minParticleCount = emitter.minParticleCount; delayValue.load(emitter.delayValue); @@ -210,6 +208,12 @@ public class ParticleEmitter { restart(); } + public void reset () { + emissionDelta = 0; + durationTimer = 0; + start(); + } + private void restart () { delay = delayValue.active ? delayValue.newLowValue() : 0; delayTimer = 0; @@ -242,15 +246,15 @@ public class ParticleEmitter { if (velocityValue.active && velocityValue.active) updateFlags |= UPDATE_VELOCITY; if (scaleValue.timeline.length > 1) updateFlags |= UPDATE_SCALE; if (rotationValue.active && rotationValue.timeline.length > 1) updateFlags |= UPDATE_ROTATION; - if (windValue.active && windValue.timeline.length > 1) updateFlags |= UPDATE_WIND; - if (gravityValue.active && gravityValue.timeline.length > 1) updateFlags |= UPDATE_GRAVITY; + if (windValue.active) updateFlags |= UPDATE_WIND; + if (gravityValue.active) updateFlags |= UPDATE_GRAVITY; if (tintValue.timeline.length > 1) updateFlags |= UPDATE_TINT; } private void activateParticle (int index) { Particle particle = particles[index]; if (particle == null) { - particles[index] = particle = new Particle(texture); + particles[index] = particle = new Particle(sprite); particle.flip(flipX, flipY); } @@ -269,15 +273,16 @@ public class ParticleEmitter { particle.angle = angleValue.newLowValue(); particle.angleDiff = angleValue.newHighValue(); if (!angleValue.isRelative()) particle.angleDiff -= particle.angle; + float angle = 0; if ((updateFlags & UPDATE_ANGLE) == 0) { - float angle = particle.angle + particle.angleDiff * angleValue.getScale(0); + angle = particle.angle + particle.angleDiff * angleValue.getScale(0); particle.angle = angle; particle.angleCos = MathUtils.cosDeg(angle); particle.angleSin = MathUtils.sinDeg(angle); } - particle.scale = scaleValue.newLowValue() / texture.getWidth(); - particle.scaleDiff = scaleValue.newHighValue() / texture.getWidth(); + particle.scale = scaleValue.newLowValue() / sprite.getWidth(); + particle.scaleDiff = scaleValue.newHighValue() / sprite.getWidth(); if (!scaleValue.isRelative()) particle.scaleDiff -= particle.scale; if ((updateFlags & UPDATE_SCALE) == 0) particle.setScale(particle.scale + particle.scaleDiff * scaleValue.getScale(0)); @@ -285,8 +290,11 @@ public class ParticleEmitter { particle.rotation = rotationValue.newLowValue(); particle.rotationDiff = rotationValue.newHighValue(); if (!rotationValue.isRelative()) particle.rotationDiff -= particle.rotation; - if ((updateFlags & UPDATE_ROTATION) == 0) - particle.setRotation(particle.rotation + particle.rotationDiff * rotationValue.getScale(0)); + if ((updateFlags & UPDATE_ROTATION) == 0) { + float rotation = particle.rotation + particle.rotationDiff * rotationValue.getScale(0); + if (aligned) rotation += angle; + particle.setRotation(rotation); + } } if (windValue.active) { @@ -334,20 +342,20 @@ public class ParticleEmitter { if (radiusX == 0 || radiusY == 0) break; float scaleY = radiusX / (float)radiusY; if (spawnShapeValue.edges) { - float angle; + float spawnAngle; switch (spawnShapeValue.side) { case top: - angle = -MathUtils.random(179f); + spawnAngle = -MathUtils.random(179f); break; case bottom: - angle = MathUtils.random(179f); + spawnAngle = MathUtils.random(179f); break; default: - angle = MathUtils.random(360f); + spawnAngle = MathUtils.random(360f); break; } - x += MathUtils.cosDeg(angle) * radiusX; - y += MathUtils.sinDeg(angle) * radiusX / scaleY; + x += MathUtils.cosDeg(spawnAngle) * radiusX; + y += MathUtils.sinDeg(spawnAngle) * radiusX / scaleY; } else { int radius2 = radiusX * radiusX; while (true) { @@ -374,9 +382,9 @@ public class ParticleEmitter { } } - int texWidth = texture.getWidth(); - int texHeight = texture.getHeight(); - particle.setBounds(x - texWidth / 2, y - texHeight / 2, texWidth, texHeight); + float spriteWidth = sprite.getWidth(); + float spriteHeight = sprite.getHeight(); + particle.setBounds(x - spriteWidth / 2, y - spriteHeight / 2, spriteWidth, spriteHeight); } private boolean updateParticle (int index, float delta, int deltaMillis) { @@ -407,7 +415,7 @@ public class ParticleEmitter { } else { velocityX = velocity * particle.angleCos; velocityY = velocity * particle.angleSin; - if ((updateFlags & UPDATE_ROTATION) != 0) { + if (aligned || (updateFlags & UPDATE_ROTATION) != 0) { float rotation = particle.rotation + particle.rotationDiff * rotationValue.getScale(percent); if (aligned) rotation += particle.angle; particle.setRotation(rotation); @@ -455,13 +463,12 @@ public class ParticleEmitter { this.y = y; } - // BOZO - Should be setSprite. - public void setTexture (Texture texture) { - this.texture = texture; - if (texture == null) return; - imageAspectRatio = texture.getHeight() / (float)texture.getWidth(); - float originX = texture.getWidth() / 2; - float originY = texture.getHeight() / 2; + public void setSprite (Sprite sprite) { + this.sprite = sprite; + if (sprite == null) return; + float originX = sprite.getOriginX(); + float originY = sprite.getOriginY(); + Texture texture = sprite.getTexture(); for (int i = 0, n = particles.length; i < n; i++) { Particle particle = particles[i]; if (particle == null) break; @@ -470,8 +477,8 @@ public class ParticleEmitter { } } - public Texture getTexture () { - return texture; + public Sprite getSprite () { + return sprite; } public String getName () { @@ -778,8 +785,8 @@ public class ParticleEmitter { float gravity, gravityDiff; float[] tint; - public Particle (Texture texture) { - super(texture); + public Particle (Sprite sprite) { + super(sprite); } } -- 2.11.0