Fix major bugs caused by rename and rip out the GC
[desert.git] / src / net / sourceforge / desert / Utilities.java
blobbba1c18ac5b34a23520214953ac80ab632cd84cd
1 /*
2 * Copyright (c) 2010 The Desert team
4 * Permission is hereby granted, free of charge, to any person
5 * obtaining a copy of this software and associated documentation
6 * files (the "Software"), to deal in the Software without
7 * restriction, including without limitation the rights to use,
8 * copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following
11 * conditions:
13 * The above copyright notice and this permission notice shall be
14 * included in all copies or substantial portions of the Software.
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23 * OTHER DEALINGS IN THE SOFTWARE.
26 package net.sourceforge.desert;
28 import java.awt.image.BufferedImage;
29 import java.io.File;
30 import java.io.IOException;
31 import java.net.JarURLConnection;
32 import java.net.URL;
33 import java.util.ArrayList;
34 import java.util.Collections;
35 import java.util.Enumeration;
36 import java.util.Iterator;
37 import java.util.LinkedList;
38 import java.util.List;
39 import java.util.jar.JarEntry;
40 import java.util.jar.JarFile;
41 import javax.imageio.ImageIO;
43 import static java.lang.Math.*;
45 /**
47 * @author codistmonk (creation 2010-04-17)
49 public class Utilities {
51 // TODO add automated tests
53 /**
54 * Private default constructor to ensure that the class isn't instantiated.
56 private Utilities() {
57 // Do nothing
60 public static final String RESOURCE_BASE = "net/sourceforge/desert/resources/";
62 /**
64 * @param iterator
65 * <br>Should no be null
66 * <br>Input-output parameter
67 * @return the next available element if there is one, or else null
68 * <br>A possibly null value
69 * <br>A reference
71 public static final <T> T next(final Iterator<T> iterator) {
72 return iterator.hasNext() ? iterator.next() : null;
75 /**
76 * TODO move this function into a ParticleUtilities class, or ParticleDefaultImplementation itself
77 * @param particle
78 * <br>Should not be null
79 * @param deltaX
80 * <br>Range: <code>]Float.NEGATIVE_INFINITY .. Float.POSITIVE_INFINITY[</code>
81 * @param deltaY
82 * <br>Range: <code>]Float.NEGATIVE_INFINITY .. Float.POSITIVE_INFINITY[</code>
84 public static final void move(final ParticleDefaultImplementation particle, final float deltaX, final float deltaY) {
85 particle.setX(particle.getX() + deltaX);
86 particle.setY(particle.getY() + deltaY);
89 /**
90 * TODO move this function into a ParticleUtilities class
91 * @param particle1
92 * <br>Should not be null
93 * @param particle2
94 * <br>Should not be null
95 * @return <code>distance(particle1, particle2) <= particle1.getRadius() + particle2.getRadius()</code>
96 * <br>A non-null value
98 public static final Boolean collision(final Particle particle1, final Particle particle2) {
99 return distance(particle1, particle2) <= particle1.getType().getRadius() + particle2.getType().getRadius();
103 * TODO move this function into a ParticleUtilities class
104 * @param particle1
105 * <br>Should not be null
106 * @param particle2
107 * <br>Should not be null
108 * @return <code>sqrt(square(particle1.getX() - particle2.getX()) + square(particle1.getY() - particle2.getY()))</code>
109 * <br>Range: <code>[0F .. Float.POSITIVE_INFINITY[</code>
111 public static final float distance(final Particle particle1, final Particle particle2) {
112 return length(particle1.getX() - particle2.getX(), particle1.getY() - particle2.getY());
117 * @param deltaX
118 * <br>Range: <code>]Float.NEGATIVE_INFINITY .. Float.OSITIVE_INFINITY[</code>
119 * @param deltaY
120 * <br>Range: <code>]Float.NEGATIVE_INFINITY .. Float.OSITIVE_INFINITY[</code>
121 * @return
122 * <br>Range: <code>[0F .. Float.POSITIVE_INFINITY[</code>
124 public static final float length(final float deltaX, final float deltaY) {
125 return LengthAlgorithm.EUCLIDIAN.length(deltaX, deltaY);
130 * @param value
131 * <br>Range: <code>]Float.NEGATIVE_INFINITY .. Float.POSITIVE_INFINITY[</code>
132 * @return
133 * <br>Range: <code>[0F .. Float.POSITIVE_INFINITY[</code>
135 public static final float square(final float value) {
136 return value * value;
141 * @param resourcePath
142 * <br>Should not be null
143 * <br>Eg: "org/sourceforge/desert/resources/images/"
144 * @return An unmodifiable list
145 * <br>A non-null value
146 * @throws IOException
148 public static final List<String> listSubresources(final String resourcePath) throws IOException {
149 final URL resourceURL = Utilities.class.getClassLoader().getResource(resourcePath);
151 if (resourceURL.getProtocol().equals("jar")) {
152 final JarURLConnection connection = (JarURLConnection) resourceURL.openConnection();
154 return listSubentryNames(connection.getJarFile(), connection.getEntryName());
156 else {
157 return listSubfilePaths(resourcePath);
162 * Lists the subfiles of <code>path</code>.
163 * @param resourcePath
164 * <br>Should not be null
165 * @return An unmodifiable list; empty if <code>path</code> is not a directory
166 * <br>A non-null value
167 * <br>A new value
168 * @throws IOException
170 public static final List<String> listSubfilePaths(final String resourcePath) throws IOException {
171 final List<String> result = new ArrayList<String>();
172 final File file = new File(Utilities.class.getClassLoader().getResource(resourcePath).getFile());
174 if (file.isDirectory()) {
175 final File[] subfiles = file.listFiles();
177 if (subfiles == null) {
178 throw new IOException("Could not list subfiles for " + file);
181 for (final File subFile : subfiles) {
182 result.add(resourcePath + File.separator + subFile.getName());
186 return Collections.unmodifiableList(result);
190 * Lists the subentries of the entry named <code>entryName</code> in <code>jarFile</code>.
191 * @param jarFile
192 * <br>Should not be null
193 * @param entryName
194 * <br>Should not be null
195 * @return An unmodifiable list; empty if the entry is not a directory
196 * <br>A new value
197 * <br>A non-null value
199 public static final List<String> listSubentryNames(final JarFile jarFile, final String entryName) {
200 final List<String> result = new ArrayList<String>();
202 for (final Enumeration<JarEntry> entries = jarFile.entries(); entries.hasMoreElements();) {
203 final String otherEntryName = entries.nextElement().getName();
205 if (otherEntryName.startsWith(entryName) && !otherEntryName.equals(entryName + "/")) {
206 result.add(otherEntryName);
210 return Collections.unmodifiableList(result);
215 * @return an unmodifiable list
216 * <br>A non-null value
217 * <br>A new value
218 * @throws RuntimeException if an IO exception occurs
220 public static final List<String> listBrushPaths() {
221 try {
222 final List<String> result = new LinkedList<String>(listSubresources(RESOURCE_BASE + "images/"));
224 for (final Iterator<String> iterator = result.iterator(); iterator.hasNext();) {
225 final String resourcePath = iterator.next();
227 if (!getResourceName(resourcePath).startsWith("brush_")) {
228 iterator.remove();
232 return Collections.unmodifiableList(result);
233 } catch (final IOException exception) {
234 throw new RuntimeException(exception);
240 * @param resourcePath
241 * <br>Should not be null
242 * @return
243 * <br>A non-null value
245 public static final String getResourceName(final String resourcePath) {
246 return resourcePath.substring(resourcePath.lastIndexOf(File.separator) + 1);
250 * A brush resource is an image where non-black pixels represent a particle generation point.
251 * @param resourcePath
252 * <br>Should not be null
253 * <br>Eg: "org/sourceforge/desert/resources/images/brush_dot_1x1.png"
254 * @return A boolean representation of the pixels of the resource image,
255 * where <code>true</code> indicate non-black pixels
256 * <br>A non-null value
257 * <br>A new value
258 * @throws RuntimeException if the resource couldn't be read
260 public static final boolean[][] getBrush(final String resourcePath) {
261 try {
262 final BufferedImage brush = ImageIO.read(Utilities.class.getClassLoader().getResourceAsStream(resourcePath));
264 final boolean[][] result = new boolean[brush.getHeight()][brush.getWidth()];
266 for (int y = 0; y < brush.getHeight(); ++y) {
267 for (int x = 0; x < brush.getWidth(); ++x) {
268 // A non-black pixels means "put a particle here"
269 result[y][x] = (brush.getRGB(x, y) & 0x00FFFFFF) != 0;
273 return result;
274 } catch (final IOException exception) {
275 throw new RuntimeException(exception);
280 * Concatenates the source location of the call and the string representations
281 * of the parameters separated by spaces.
282 * <br>This is method helps to perform console debugging using System.out or System.err.
283 * @param stackIndex 1 is the source of this mehod, 2 is the source of the call, 3 is the source of the call's caller, and so forth
284 * <br>Range: <code>[O .. Integer.MAX_VALUE]</code>
285 * @param objects
286 * <br>Should not be null
287 * @return
288 * <br>A new value
289 * <br>A non-null value
291 public static final String debug(final int stackIndex, final Object... objects) {
292 final StringBuilder builder = new StringBuilder(Thread.currentThread().getStackTrace()[stackIndex].toString());
294 for (final Object object : objects) {
295 builder.append(" ").append(object);
298 return builder.toString();
302 * Prints on the standard output the concatenation of the source location of the call
303 * and the string representations of the parameters separated by spaces.
304 * @param objects
305 * <br>Should not be null
307 public static final void debugPrint(final Object... objects) {
308 System.out.println(debug(3, objects));
314 * @author codistmonk (2010-04-28)
316 public static enum LengthAlgorithm {
318 MAXIMUM {
320 @Override
321 public final float length(final float deltaX, final float deltaY) {
322 return max(abs(deltaX), abs(deltaY));
327 EUCLIDIAN {
329 @Override
330 public final float length(final float deltaX, final float deltaY) {
331 return (float) sqrt(square(deltaX) + square(deltaY));
338 * @param x
339 * <br>Range: <code>]Float.NEGATIVE_INFINITY .. Float.POSITIVE_INFINITY[</code>
340 * @param y
341 * <br>Range: <code>]Float.NEGATIVE_INFINITY .. Float.POSITIVE_INFINITY[</code>
342 * @return
343 * <br>Range: <code>[0F .. Float.POSITIVE_INFINITY[</code>
345 public abstract float length(float x, float y);