Updated ParticleEngineDMapImplementation.
[desert.git] / src / org / sourceforge / desert / ui / DesertPanel.java
blobf5fce27ec76fa12170ec5bb970e122530f86b98b
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 org.sourceforge.desert.ui;
28 import java.awt.BorderLayout;
29 import java.awt.Button;
30 import java.awt.Checkbox;
31 import java.awt.Choice;
32 import java.awt.Component;
33 import java.awt.Label;
34 import java.awt.Panel;
35 import java.awt.event.ActionEvent;
36 import java.awt.event.ActionListener;
37 import java.awt.event.ItemEvent;
38 import java.awt.event.ItemListener;
39 import java.awt.event.MouseMotionListener;
40 import java.awt.event.MouseEvent;
41 import java.util.List;
42 import java.util.ResourceBundle;
43 import java.util.logging.Level;
44 import java.util.logging.Logger;
45 import javax.swing.Box;
46 import org.sourceforge.desert.ImageFilter;
47 import org.sourceforge.desert.ImageFilterClearImplementation;
48 import org.sourceforge.desert.ImageFilterFadeImplementation;
49 import org.sourceforge.desert.Particle;
50 import org.sourceforge.desert.ParticleEngine;
51 import org.sourceforge.desert.ParticleEngineCustomImplementation;
52 import org.sourceforge.desert.ParticleEngineDMapImplementation;
53 import org.sourceforge.desert.ParticleEngineDMapImplementation;
54 import org.sourceforge.desert.ParticleEngineJBulletImplementation;
55 import org.sourceforge.desert.ParticleEngineOde4JImplementation;
56 import org.sourceforge.desert.ParticleEnginePhys2DImplementation;
57 import org.sourceforge.desert.Utilities;
59 /**
61 * @author codistmonk (creation 2010-04-15)
63 @SuppressWarnings("serial")
64 public class DesertPanel extends Panel {
66 private final Timer timer;
68 private final DrawingBoard drawingBoard;
70 private final GCThread gcThread;
72 public DesertPanel() {
73 super(new BorderLayout());
74 this.timer = new Timer(FRAMERATE);
75 this.drawingBoard = new DrawingBoard();
77 final CursorPositionLabel xyMouse = new CursorPositionLabel();
78 final FramerateLabel framerateLabel = new FramerateLabel();
79 final ParticleCountLabel particleCountLabel = this.new ParticleCountLabel();
80 final Checkbox pauseButton = new Checkbox("Pause");
81 final Button resetButton = new Button("Reset");
83 this.add(this.getDrawingBoard(), BorderLayout.CENTER);
84 this.add(verticalBox(
85 horizontalBox(framerateLabel, particleCountLabel, xyMouse),
86 horizontalBox(resetButton, pauseButton),
87 horizontalBox(new Label("Particle engine: "), this.new ParticleEngineChoice()),
88 horizontalBox(new Label("Particle type: "), this.new ParticleTypeChoice()),
89 horizontalBox(new Label("Image filter: "), this.new ImageFilterChoice()),
90 horizontalBox(new Label("Particle brush: "), this.new BrushChoice())
91 ), BorderLayout.SOUTH);
93 pauseButton.addItemListener(this.new Pause());
94 resetButton.addActionListener(this.new Reset());
96 this.getTimer().addActionListener(this.getDrawingBoard());
97 this.getDrawingBoard().addMouseMotionListener(xyMouse);
98 this.getTimer().addActionListener(framerateLabel);
99 this.getTimer().addActionListener(particleCountLabel);
100 this.gcThread = new GCThread();
101 this.gcThread.start();
106 * @return
107 * <br>A non-null value
108 * <br>A reference
110 public final Timer getTimer() {
111 return this.timer;
116 * @return
117 * <br>A non-null value
118 * <br>A reference
120 public final DrawingBoard getDrawingBoard() {
121 return this.drawingBoard;
126 * @author codistmonk (creation 2010-04-20)
128 private final class Reset implements ActionListener {
130 @Override
131 public final void actionPerformed(final ActionEvent event) {
132 DesertPanel.this.getDrawingBoard().getParticleEngine().removeAllParticles();
139 * @author codistmonk (creation 2010-04-20)
141 private final class Pause implements ItemListener {
143 @Override
144 public final void itemStateChanged(final ItemEvent event) {
145 DesertPanel.this.getDrawingBoard().setPaused(event.getStateChange() == ItemEvent.SELECTED);
152 * @author codistmonk (creation 2010-04-17)
154 @SuppressWarnings("serial")
155 private final class ParticleEngineChoice extends Choice {
157 public ParticleEngineChoice() {
158 this.add("Custom");
159 this.add("DMap");
160 this.add("JBullet");
161 this.add("Phys2D");
162 this.add("Ode4J");
164 this.addItemListener(this.new ItemHandler());
169 * @author codistmonk (creation 2010-04-17)
171 private final class ItemHandler implements ItemListener {
173 @Override
174 public final void itemStateChanged(final ItemEvent event) {
175 if (event.getStateChange() == ItemEvent.SELECTED) {
176 try {
177 DesertPanel.this.getDrawingBoard().setParticleEngine(this.createParticleEngine());
178 } catch (final InstantiationException exception) {
179 Logger.getLogger(DesertPanel.class.getName()).log(Level.SEVERE, null, exception);
180 } catch (final IllegalAccessException exception) {
181 Logger.getLogger(DesertPanel.class.getName()).log(Level.SEVERE, null, exception);
187 * @return
188 * <br>A new value
189 * <br>A non-null value
190 * @throws InstantiationException
191 * @throws IllegalAccessException
193 private final ParticleEngine createParticleEngine() throws InstantiationException, IllegalAccessException {
194 return (ParticleEngine) new Class<?>[] {
195 ParticleEngineCustomImplementation.class,
196 ParticleEngineDMapImplementation.class,
197 ParticleEngineJBulletImplementation.class,
198 ParticleEnginePhys2DImplementation.class,
199 ParticleEngineOde4JImplementation.class
200 }[ParticleEngineChoice.this.getSelectedIndex()].newInstance();
209 * @author codistmonk (creation 2010-04-21)
211 @SuppressWarnings("serial")
212 private final class ImageFilterChoice extends Choice {
214 public ImageFilterChoice() {
215 this.add("Clear");
216 this.add("Fade");
218 this.addItemListener(this.new ItemHandler());
223 * @author codistmonk (creation 2010-04-17)
225 private final class ItemHandler implements ItemListener {
227 @Override
228 public final void itemStateChanged(final ItemEvent event) {
229 if (event.getStateChange() == ItemEvent.SELECTED) {
230 try {
231 DesertPanel.this.getDrawingBoard().setImageFilter(this.createImageFilter());
232 } catch (final InstantiationException exception) {
233 Logger.getLogger(DesertPanel.class.getName()).log(Level.SEVERE, null, exception);
234 } catch (final IllegalAccessException exception) {
235 Logger.getLogger(DesertPanel.class.getName()).log(Level.SEVERE, null, exception);
241 * @return
242 * <br>A new value
243 * <br>A non-null value
244 * @throws InstantiationException
245 * @throws IllegalAccessException
247 private final ImageFilter createImageFilter() throws InstantiationException, IllegalAccessException {
248 return (ImageFilter) new Class<?>[] {
249 ImageFilterClearImplementation.class,
250 ImageFilterFadeImplementation.class
251 }[ImageFilterChoice.this.getSelectedIndex()].newInstance();
260 * @author andrew (creation 2010-04-17)
262 @SuppressWarnings("serial")
263 private final class ParticleTypeChoice extends Choice {
265 public ParticleTypeChoice() {
266 final ResourceBundle resourceBundle = ResourceBundle.getBundle(Utilities.RESOURCE_BASE + "messages");
268 for (final Particle.Type type : Particle.Type.values()) {
269 this.add(resourceBundle.getString(type.toString()));
272 this.updateDrawingBoardParticleType();
274 this.addItemListener(this.new ItemHandler());
277 final void updateDrawingBoardParticleType() {
278 DesertPanel.this.getDrawingBoard().setParticleType(
279 Particle.Type.values()[ParticleTypeChoice.this.getSelectedIndex()]);
284 * @author andrew (creation 2010-04-17)
286 private final class ItemHandler implements ItemListener {
288 @Override
289 public final void itemStateChanged(final ItemEvent event) {
290 if (event.getStateChange() == ItemEvent.SELECTED) {
291 ParticleTypeChoice.this.updateDrawingBoardParticleType();
301 * @author codistmonk (creation 2010-04-25)
303 @SuppressWarnings("serial")
304 private final class BrushChoice extends Choice {
306 private final List<String> brushPaths;
308 public BrushChoice() {
309 this.brushPaths = Utilities.listBrushPaths();
311 for (final String brushPath : this.brushPaths) {
312 this.addItem(getUserReadableBrushName(brushPath));
315 this.updateDrawingBoardBrush();
317 this.addItemListener(this.new ItemHandler());
320 final void updateDrawingBoardBrush() {
321 DesertPanel.this.getDrawingBoard().setBrush(
322 Utilities.getBrush(this.brushPaths.get(BrushChoice.this.getSelectedIndex())));
327 * @author condistmonk (creation 2010-04-25)
329 private final class ItemHandler implements ItemListener {
331 @Override
332 public final void itemStateChanged(final ItemEvent event) {
333 if (event.getStateChange() == ItemEvent.SELECTED) {
334 BrushChoice.this.updateDrawingBoardBrush();
344 * @author codistmonk (creation 2010-04-15)
346 @SuppressWarnings("serial")
347 private final class ParticleCountLabel extends Label implements ActionListener {
349 @Override
350 public final void actionPerformed(final ActionEvent event) {
351 this.setText("Particle count: " + DesertPanel.this.getDrawingBoard().getParticleCount());
358 * @author andrew (creation 2010-04-19)
360 @SuppressWarnings("serial")
361 private final class CursorPositionLabel extends Label implements MouseMotionListener {
363 @Override
364 public final void mouseMoved(final MouseEvent event) {
365 this.updateText(event);
368 @Override
369 public final void mouseDragged(final MouseEvent event) {
370 this.updateText(event);
375 * @param event
376 * <br>Should not be null
378 private final void updateText(final MouseEvent event) {
379 this.setText("(" + event.getX() + ", " +
380 (DesertPanel.this.getDrawingBoard().getHeight() - event.getY() - 1) + ")");
385 public static final int FRAMERATE = 25;
389 * @param components
390 * <br> Should not be null
391 * @return
392 * <br>A new value
393 * <br>A non-null value
395 private static final Box horizontalBox(final Component... components) {
396 // TODO do not use Swing
397 final Box result = Box.createHorizontalBox();
399 for (final Component component : components) {
400 result.add(component);
403 return result;
408 * @param components
409 * <br> Should not be null
410 * @return
411 * <br>A new value
412 * <br>A non-null value
414 private static final Box verticalBox(final Component... components) {
415 // TODO do not use Swing
416 final Box result = Box.createVerticalBox();
418 for (final Component component : components) {
419 result.add(component);
422 return result;
426 * Transforms the brush resource path into a user-readable form.
427 * <br>Eg: "org/sourceforge/desert/resources/images/dot_1x1.png" becomes "Dot 1x1"
428 * @param brushPath
429 * <br>Should not be null
430 * @return
431 * <br>A non-null value
432 * <br>A new value
434 static final String getUserReadableBrushName(final String brushPath) {
435 final String result = Utilities.getResourceName(brushPath).split("brush_")[1].split("\\.")[0].replaceAll("_", " ");
437 return Character.toUpperCase(result.charAt(0)) + result.substring(1);
442 * @author codistmonk (creation 2010-04-15)
444 @SuppressWarnings("serial")
445 private static final class FramerateLabel extends Label implements ActionListener {
447 @Override
448 public final void actionPerformed(final ActionEvent event) {
449 this.setText("Framerate: " + String.format("%.1f", 1.0 / ((Timer.Event) event).getDeltaTime()));
456 * @author andrew
458 private static final class GCThread extends Thread {
459 int rune;
461 @Override
462 public void run() {
463 rune = 0;
464 while (rune == 0) {
465 try {
466 Thread.sleep(2000);
467 } catch (Exception e) {
468 // nothing
470 System.gc();