From 8b70966ece0ef3d9810d9c88ad7c059f8fcd9092 Mon Sep 17 00:00:00 2001 From: codistmonk Date: Sat, 24 Apr 2010 11:12:31 +0000 Subject: [PATCH] Added brushes (some work left to be done on the UI); changed default particle size. git-svn-id: https://desert.svn.sourceforge.net/svnroot/desert@79 cbff3641-ea5c-438d-a1bd-c9f42921e016 --- src/org/sourceforge/desert/Particle.java | 2 +- src/org/sourceforge/desert/Utilities.java | 41 +++++++ .../desert/resources/images/brush_dot_1x1.png | Bin 0 -> 68 bytes .../desert/resources/images/brush_round_5x5.png | Bin 0 -> 82 bytes .../desert/resources/images/brush_square_2x2.png | Bin 0 -> 71 bytes src/org/sourceforge/desert/ui/DrawingBoard.java | 135 ++++++++++++++++++--- 6 files changed, 161 insertions(+), 17 deletions(-) create mode 100644 src/org/sourceforge/desert/resources/images/brush_dot_1x1.png create mode 100644 src/org/sourceforge/desert/resources/images/brush_round_5x5.png create mode 100644 src/org/sourceforge/desert/resources/images/brush_square_2x2.png diff --git a/src/org/sourceforge/desert/Particle.java b/src/org/sourceforge/desert/Particle.java index d053bf4..e5b48e8 100644 --- a/src/org/sourceforge/desert/Particle.java +++ b/src/org/sourceforge/desert/Particle.java @@ -142,7 +142,7 @@ public interface Particle { } - public static final float DEFAULT_RADIUS = 0.5F; + public static final float DEFAULT_RADIUS = 0.4F; public static final float IMMOBILE_MASS = Float.POSITIVE_INFINITY; diff --git a/src/org/sourceforge/desert/Utilities.java b/src/org/sourceforge/desert/Utilities.java index 3ce5296..6cf6c10 100644 --- a/src/org/sourceforge/desert/Utilities.java +++ b/src/org/sourceforge/desert/Utilities.java @@ -25,6 +25,10 @@ */ package org.sourceforge.desert; +import java.awt.image.BufferedImage; +import java.io.IOException; +import javax.imageio.ImageIO; + /** * * @author codistmonk (creation 2010-04-17) @@ -32,6 +36,43 @@ package org.sourceforge.desert; public class Utilities { /** + * Default private constructor to ensure that the class isn't instantiated. + */ + private Utilities() { + // Nothing + } + + /** + * A brush resource is an image where non-black pixels represent a particle generation point. + * @param resourcePath + *
Should not be null + *
Eg: "org/sourceforge/desert/resources/images/brush_dot_1x1.png" + * @return a boolean representation of the pixels of the resource image, + * where true indicate non-black pixels + *
A non-null value + *
A new value + * @throws RuntimeException if the resource couldn't be read + */ + public static final boolean[][] getBrush(final String resourcePath) { + try { + final BufferedImage brush = ImageIO.read(Utilities.class.getClassLoader().getResourceAsStream(resourcePath)); + + final boolean[][] result = new boolean[brush.getHeight()][brush.getWidth()]; + + for (int y = 0; y < brush.getHeight(); ++y) { + for (int x = 0; x < brush.getWidth(); ++x) { + // A non-black pixels means "put a particle here" + result[y][x] = (brush.getRGB(x, y) & 0x00FFFFFF) != 0; + } + } + + return result; + } catch (final IOException exception) { + throw new RuntimeException(exception); + } + } + + /** * Concatenates the source location of the call and the string representations * of the parameters separated by spaces.
* This is method helps to perform console debugging using System.out or System.err. diff --git a/src/org/sourceforge/desert/resources/images/brush_dot_1x1.png b/src/org/sourceforge/desert/resources/images/brush_dot_1x1.png new file mode 100644 index 0000000000000000000000000000000000000000..6e438b2f308d0b5d81c0126cc09697b52629cb45 GIT binary patch literal 68 zcwXxa@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k8}blZci7-kcwN$KloV~IDa$$&G;pA Q1}Mzn>FVdQ&MBb@0Hd7`oB#j- literal 0 HcwPel00001 diff --git a/src/org/sourceforge/desert/resources/images/brush_round_5x5.png b/src/org/sourceforge/desert/resources/images/brush_round_5x5.png new file mode 100644 index 0000000000000000000000000000000000000000..ed3abebb9b4214c36295fbb921ff0ae56702bd56 GIT binary patch literal 82 zcwXxa@N?(olHy`uVBq!ia0vp^tRT$61|)m))t&+=NlzEYkcwN$2?+^5`gt5`LIh{9 fd~CXLhK1p4QuxXn=N~=-Dq`?-^>bP0l+XkK2=^E( literal 0 HcwPel00001 diff --git a/src/org/sourceforge/desert/resources/images/brush_square_2x2.png b/src/org/sourceforge/desert/resources/images/brush_square_2x2.png new file mode 100644 index 0000000000000000000000000000000000000000..7222c8d9d577b294f08fa2a3595c4d6122590420 GIT binary patch literal 71 zcwXxa@N?(olHy`uVBq!ia0vp^Od!m`1|*BN@u~nRK2I0NkcwN$KloXB4A>a@oA^H} To|RAs$}o7k`njxgN@xNAu+$E$ literal 0 HcwPel00001 diff --git a/src/org/sourceforge/desert/ui/DrawingBoard.java b/src/org/sourceforge/desert/ui/DrawingBoard.java index f4f9119..d09a9ae 100644 --- a/src/org/sourceforge/desert/ui/DrawingBoard.java +++ b/src/org/sourceforge/desert/ui/DrawingBoard.java @@ -28,6 +28,7 @@ package org.sourceforge.desert.ui; import java.awt.Canvas; import java.awt.Dimension; import java.awt.Graphics; +import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; @@ -35,12 +36,16 @@ import java.awt.event.ComponentEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.image.BufferedImage; +import java.io.IOException; +import java.util.Arrays; +import javax.imageio.ImageIO; import org.sourceforge.desert.ImageFilter; import org.sourceforge.desert.ImageFilterClearImplementation; import org.sourceforge.desert.Particle; import org.sourceforge.desert.ParticleEngine; import org.sourceforge.desert.ParticleEngineCustomImplementation; import org.sourceforge.desert.ParticleRenderer; +import org.sourceforge.desert.Utilities; /** * The drawing board, extending the graphics Canvas. @@ -61,11 +66,20 @@ public class DrawingBoard extends Canvas implements ActionListener { private boolean paused; + /** + * This mask covers the board and is used to tell where particles can be added. + *
It should be updated at the same time as the drawing buffer. + */ + private boolean[][] particleMask; + + private boolean[][] brush; + public DrawingBoard() { this.particleRenderer = new ParticleRenderer(); this.particleEngine = new ParticleEngineCustomImplementation(); this.particleType = Particle.Type.values()[0]; this.imageFilter = new ImageFilterClearImplementation(); + this.brush = Utilities.getBrush("org/sourceforge/desert/resources/images/brush_square_2x2.png"); this.addComponentListener(this.new ResizeHandler()); @@ -99,6 +113,26 @@ public class DrawingBoard extends Canvas implements ActionListener { } /** + * + * @return + *
A non-null value + *
A reference + */ + public final boolean[][] getBrush() { + return brush; + } + + /** + * + * @param brush + *
Should not be null + *
A reference parameter + */ + public final void setBrush(final boolean[][] brush) { + this.brush = brush; + } + + /** * * @return */ @@ -207,6 +241,7 @@ public class DrawingBoard extends Canvas implements ActionListener { final void resizeBuffer() { if (this.getWidth() >0 && this.getHeight() > 0) { this.buffer = new BufferedImage(this.getWidth(), this.getHeight(), BufferedImage.TYPE_3BYTE_BGR); + this.particleMask = new boolean[this.getHeight()][this.getWidth()]; this.getParticleEngine().setBoardSize(this.getSize()); this.particleRenderer.setBuffer(this.buffer); } @@ -215,19 +250,52 @@ public class DrawingBoard extends Canvas implements ActionListener { } } + /** + * + * @param x + *
Range: [Integer.MIN_VALUE .. Integer.MAX_VALUE] + * @param y + *
Range: [Integer.MIN_VALUE .. Integer.MAX_VALUE] + * @return true if the specified location is outside the board or contain no particle + */ + final boolean canAddParticle(final int x, final int y) { + return !this.isInsideBoard(x, y) || !this.particleMask[y][x]; + } + private final void clearBuffer() { this.buffer = this.imageFilter.filter(this.buffer); + + for (int i = 0; i < this.particleMask.length; ++i) { + Arrays.fill(this.particleMask[i], false); + } + this.particleRenderer.setBuffer(this.buffer); } private final void drawParticlesToBuffer() { for (final Particle particle : this.getParticleEngine()) { this.particleRenderer.draw(particle); + + if (this.isInsideBoard((int) particle.getX(), (int) particle.getY())) { + this.particleMask[(int) particle.getY()][(int) particle.getX()] = true; + } } } /** * + * @param x + *
Range: [Integer.MIN_VALUE .. Integer.MAX_VALUE] + * @param y + *
Range: [Integer.MIN_VALUE .. Integer.MAX_VALUE] + * @return + */ + private final boolean isInsideBoard(final int x, final int y) { + return 0 <= x && x < this.getWidth() && 0 <= y && y < this.getHeight(); + } + + /** + * * @param graphics *
Should not be null */ @@ -256,44 +324,79 @@ public class DrawingBoard extends Canvas implements ActionListener { // TODO: Use triggers set off by classes called Desert*Element + private Point lastPoint; + @Override public final void mouseDragged(final MouseEvent event) { - this.addRandomParticles(event, NUMBER_OF_PARTICLES_CREATED_DURING_A_MOUSE_EVENT); + if (this.lastPoint != null) { + this.addParticleStreak(this.lastPoint, event.getPoint()); + } + else { + this.addParticle(event.getX(), event.getY()); + } + + this.lastPoint = event.getPoint(); } @Override public final void mousePressed(final MouseEvent event) { - this.addRandomParticles(event, NUMBER_OF_PARTICLES_CREATED_DURING_A_MOUSE_EVENT); + this.addParticle(event.getX(), event.getY()); + + this.lastPoint = null; } /** - * - * @param event + * + * @param origin + *
Should not be null + * @param destination *
Should not be null - * @param particleCount - *
Range: [0 .. Integer.MAX_VALUE] */ - private final void addRandomParticles(final MouseEvent event, final int particleCount) { - for (int i = 0; i < particleCount; ++i) { - this.addRandomParticle(event.getX(), DrawingBoard.this.getHeight() - event.getY() - 1F); + private final void addParticleStreak(final Point origin, final Point destination) { + float deltaX = destination.x - origin.x; + float deltaY = destination.y - origin.y; + final float pixelCount = Math.max(Math.abs(deltaX), Math.abs(deltaY)); + + if (pixelCount > 0) { + deltaX /= pixelCount; + deltaY /= pixelCount; + + float x = origin.x; + float y = origin.y; + + for (int i = 0; i < pixelCount; ++i) { + this.addParticle((int) x, (int) y); + + x += deltaX; + y += deltaY; + } } } /** - * + * There is no real limit on x and y because + * particles can be created outside the board and moved inside by the engines. * @param x - *
Range: ]Float.NEGATIVE_INFINITY .. Float.POSITIVE_INFINITY[ + *
Range: [Integer.MIN_VALUE .. Integer.MAX_VALUE]] * @param y - *
Range: ]Float.NEGATIVE_INFINITY .. Float.POSITIVE_INFINITY[ + *
Range: [Integer.MIN_VALUE .. Integer.MAX_VALUE]] */ - private final void addRandomParticle(final float x, final float y) { - DrawingBoard.this.addParticle(x, y, 0F, 0F); + private final void addParticle(final int x, final int y) { + final boolean[][] brush = DrawingBoard.this.getBrush(); + final int halfWidth = brush[0].length / 2; + final int halfHeight = brush.length / 2; + + for (int y2 = y - halfHeight; y2 < y + halfHeight; ++y2) { + for (int x2 = x - halfWidth; x2 < x + halfWidth; ++x2) { + if (DrawingBoard.this.canAddParticle(x2, DrawingBoard.this.getHeight() - y2)) { + DrawingBoard.this.addParticle(x2, DrawingBoard.this.getHeight() - y2, 0F, 0F); + } + } + } } } - private static final int NUMBER_OF_PARTICLES_CREATED_DURING_A_MOUSE_EVENT = 1; - public static final int PREFERRED_WIDTH = 400; public static final int PREFERRED_HEIGHT = 300; -- 2.11.4.GIT