gdx-studio
git clone https://git.pyrossh.dev/gdx-studio
An IDE for creating Games using libgdx and Java supported on all platforms Android, iOS, Desktop
src_libs/com/badlogic/gdx/tools/particleeditor/ParticlePanel.java
| a62d533 | 1 | /******************************************************************************* |
| a62d533 | 2 | * Copyright 2011 See AUTHORS file. |
| a62d533 | 3 | * |
| a62d533 | 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| a62d533 | 5 | * you may not use this file except in compliance with the License. |
| a62d533 | 6 | * You may obtain a copy of the License at |
| a62d533 | 7 | * |
| a62d533 | 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| a62d533 | 9 | * |
| a62d533 | 10 | * Unless required by applicable law or agreed to in writing, software |
| a62d533 | 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| a62d533 | 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| a62d533 | 13 | * See the License for the specific language governing permissions and |
| a62d533 | 14 | * limitations under the License. |
| a62d533 | 15 | ******************************************************************************/ |
| a62d533 | 16 | |
| a62d533 | 17 | package com.badlogic.gdx.tools.particleeditor; |
| a62d533 | 18 | |
| a62d533 | 19 | import java.awt.BorderLayout; |
| a62d533 | 20 | import java.awt.Component; |
| a62d533 | 21 | import java.awt.Dimension; |
| a62d533 | 22 | import java.awt.EventQueue; |
| a62d533 | 23 | import java.awt.GridBagConstraints; |
| a62d533 | 24 | import java.awt.GridBagLayout; |
| a62d533 | 25 | import java.awt.Insets; |
| a62d533 | 26 | import java.io.File; |
| a62d533 | 27 | import java.net.MalformedURLException; |
| a62d533 | 28 | import java.net.URL; |
| a62d533 | 29 | import java.util.HashMap; |
| a62d533 | 30 | |
| a62d533 | 31 | import javax.swing.BorderFactory; |
| a62d533 | 32 | import javax.swing.ImageIcon; |
| a62d533 | 33 | import javax.swing.JPanel; |
| a62d533 | 34 | import javax.swing.JScrollPane; |
| a62d533 | 35 | import javax.swing.JSplitPane; |
| a62d533 | 36 | import javax.swing.border.CompoundBorder; |
| a62d533 | 37 | |
| a62d533 | 38 | import com.badlogic.gdx.backends.lwjgl.LwjglAWTCanvas; |
| a62d533 | 39 | import com.badlogic.gdx.graphics.OrthographicCamera; |
| a62d533 | 40 | import com.badlogic.gdx.graphics.g2d.ParticleEffect; |
| a62d533 | 41 | import com.badlogic.gdx.graphics.g2d.ParticleEmitter; |
| a62d533 | 42 | import com.badlogic.gdx.graphics.g2d.ParticleEmitter.NumericValue; |
| a62d533 | 43 | |
| a62d533 | 44 | public class ParticlePanel extends JPanel {
|
| a62d533 | 45 | private static final long serialVersionUID = 1L; |
| a62d533 | 46 | JPanel rowsPanel; |
| a62d533 | 47 | JPanel editRowsPanel; |
| a62d533 | 48 | EffectPanel effectPanel; |
| a62d533 | 49 | private JSplitPane splitPane; |
| a62d533 | 50 | OrthographicCamera worldCamera; |
| a62d533 | 51 | OrthographicCamera textCamera; |
| a62d533 | 52 | NumericValue pixelsPerMeter; |
| a62d533 | 53 | NumericValue zoomLevel; |
| a62d533 | 54 | NumericValue deltaMultiplier; |
| a62d533 | 55 | |
| a62d533 | 56 | float pixelsPerMeterPrev; |
| a62d533 | 57 | float zoomLevelPrev; |
| a62d533 | 58 | |
| a62d533 | 59 | ParticleEffect effect = new ParticleEffect(); |
| a62d533 | 60 | final HashMap<ParticleEmitter, ParticleData> particleData = new HashMap<ParticleEmitter, ParticleData>(); |
| a62d533 | 61 | public ParticleRenderer particleRenderer; |
| a62d533 | 62 | |
| a62d533 | 63 | |
| a62d533 | 64 | public ParticlePanel() {
|
| a62d533 | 65 | super(new BorderLayout()); |
| a62d533 | 66 | setVisible(true); |
| a62d533 | 67 | } |
| a62d533 | 68 | |
| a62d533 | 69 | void reloadRows () {
|
| a62d533 | 70 | EventQueue.invokeLater(new Runnable() {
|
| a62d533 | 71 | public void run () {
|
| a62d533 | 72 | editRowsPanel.removeAll(); |
| a62d533 | 73 | addEditorRow(new NumericPanel(pixelsPerMeter, "Pixels per meter", "")); |
| a62d533 | 74 | addEditorRow(new NumericPanel(zoomLevel, "Zoom level", "")); |
| a62d533 | 75 | addEditorRow(new NumericPanel(deltaMultiplier, "Delta multiplier", "")); |
| a62d533 | 76 | |
| a62d533 | 77 | rowsPanel.removeAll(); |
| a62d533 | 78 | ParticleEmitter emitter = getEmitter(); |
| a62d533 | 79 | addRow(new ImagePanel(ParticlePanel.this, "Image", "")); |
| a62d533 | 80 | addRow(new CountPanel(ParticlePanel.this, "Count", |
| a62d533 | 81 | "Min number of particles at all times, max number of particles allowed.")); |
| a62d533 | 82 | addRow(new RangedNumericPanel(emitter.getDelay(), "Delay", |
| a62d533 | 83 | "Time from beginning of effect to emission start, in milliseconds.")); |
| a62d533 | 84 | addRow(new RangedNumericPanel(emitter.getDuration(), "Duration", "Time particles will be emitted, in milliseconds.")); |
| a62d533 | 85 | addRow(new ScaledNumericPanel(emitter.getEmission(), "Duration", "Emission", |
| a62d533 | 86 | "Number of particles emitted per second.")); |
| a62d533 | 87 | addRow(new ScaledNumericPanel(emitter.getLife(), "Duration", "Life", "Time particles will live, in milliseconds.")); |
| a62d533 | 88 | addRow(new ScaledNumericPanel(emitter.getLifeOffset(), "Duration", "Life Offset", |
| a62d533 | 89 | "Particle starting life consumed, in milliseconds.")); |
| a62d533 | 90 | addRow(new RangedNumericPanel(emitter.getXOffsetValue(), "X Offset", |
| a62d533 | 91 | "Amount to offset a particle's starting X location, in world units.")); |
| a62d533 | 92 | addRow(new RangedNumericPanel(emitter.getYOffsetValue(), "Y Offset", |
| a62d533 | 93 | "Amount to offset a particle's starting Y location, in world units.")); |
| a62d533 | 94 | addRow(new SpawnPanel(ParticlePanel.this, emitter.getSpawnShape(), "Spawn", "Shape used to spawn particles.")); |
| a62d533 | 95 | addRow(new ScaledNumericPanel(emitter.getSpawnWidth(), "Duration", "Spawn Width", |
| a62d533 | 96 | "Width of the spawn shape, in world units.")); |
| a62d533 | 97 | addRow(new ScaledNumericPanel(emitter.getSpawnHeight(), "Duration", "Spawn Height", |
| a62d533 | 98 | "Height of the spawn shape, in world units.")); |
| a62d533 | 99 | addRow(new ScaledNumericPanel(emitter.getScale(), "Life", "Size", "Particle size, in world units.")); |
| a62d533 | 100 | addRow(new ScaledNumericPanel(emitter.getVelocity(), "Life", "Velocity", "Particle speed, in world units per second.")); |
| a62d533 | 101 | addRow(new ScaledNumericPanel(emitter.getAngle(), "Life", "Angle", "Particle emission angle, in degrees.")); |
| a62d533 | 102 | addRow(new ScaledNumericPanel(emitter.getRotation(), "Life", "Rotation", "Particle rotation, in degrees.")); |
| a62d533 | 103 | addRow(new ScaledNumericPanel(emitter.getWind(), "Life", "Wind", "Wind strength, in world units per second.")); |
| a62d533 | 104 | addRow(new ScaledNumericPanel(emitter.getGravity(), "Life", "Gravity", "Gravity strength, in world units per second.")); |
| a62d533 | 105 | addRow(new GradientPanel(emitter.getTint(), "Tint", "")); |
| a62d533 | 106 | addRow(new PercentagePanel(emitter.getTransparency(), "Life", "Transparency", "")); |
| a62d533 | 107 | addRow(new OptionsPanel(ParticlePanel.this, "Options", "")); |
| a62d533 | 108 | for (Component component : rowsPanel.getComponents()) |
| a62d533 | 109 | if (component instanceof EditorPanel) ((EditorPanel)component).update(ParticlePanel.this); |
| a62d533 | 110 | rowsPanel.repaint(); |
| a62d533 | 111 | } |
| a62d533 | 112 | }); |
| a62d533 | 113 | } |
| a62d533 | 114 | |
| a62d533 | 115 | void addEditorRow (JPanel row) {
|
| a62d533 | 116 | row.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, java.awt.Color.black)); |
| a62d533 | 117 | editRowsPanel.add(row, new GridBagConstraints(0, -1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, |
| a62d533 | 118 | new Insets(0, 0, 0, 0), 0, 0)); |
| a62d533 | 119 | } |
| a62d533 | 120 | |
| a62d533 | 121 | void addRow (JPanel row) {
|
| a62d533 | 122 | row.setBorder(BorderFactory.createMatteBorder(0, 0, 1, 0, java.awt.Color.black)); |
| a62d533 | 123 | rowsPanel.add(row, new GridBagConstraints(0, -1, 1, 1, 1, 0, GridBagConstraints.CENTER, GridBagConstraints.HORIZONTAL, |
| a62d533 | 124 | new Insets(0, 0, 0, 0), 0, 0)); |
| a62d533 | 125 | } |
| a62d533 | 126 | |
| a62d533 | 127 | public void setVisible (String name, boolean visible) {
|
| a62d533 | 128 | for (Component component : rowsPanel.getComponents()) |
| a62d533 | 129 | if (component instanceof EditorPanel && ((EditorPanel)component).getName().equals(name)) component.setVisible(visible); |
| a62d533 | 130 | } |
| a62d533 | 131 | |
| a62d533 | 132 | public ParticleEmitter getEmitter () {
|
| a62d533 | 133 | return effect.getEmitters().get(effectPanel.editIndex); |
| a62d533 | 134 | } |
| a62d533 | 135 | |
| a62d533 | 136 | public ImageIcon getIcon (ParticleEmitter emitter) {
|
| a62d533 | 137 | ParticleData data = particleData.get(emitter); |
| a62d533 | 138 | if (data == null) particleData.put(emitter, data = new ParticleData()); |
| a62d533 | 139 | String imagePath = emitter.getImagePath(); |
| a62d533 | 140 | if (data.icon == null && imagePath != null) {
|
| a62d533 | 141 | try {
|
| a62d533 | 142 | URL url; |
| a62d533 | 143 | File file = new File(imagePath); |
| a62d533 | 144 | if (file.exists()) |
| a62d533 | 145 | url = file.toURI().toURL(); |
| a62d533 | 146 | else {
|
| a62d533 | 147 | url = ParticlePanel.class.getResource(imagePath); |
| a62d533 | 148 | if (url == null) return null; |
| a62d533 | 149 | } |
| a62d533 | 150 | data.icon = new ImageIcon(url); |
| a62d533 | 151 | } catch (MalformedURLException ex) {
|
| a62d533 | 152 | ex.printStackTrace(); |
| a62d533 | 153 | } |
| a62d533 | 154 | } |
| a62d533 | 155 | return data.icon; |
| a62d533 | 156 | } |
| a62d533 | 157 | |
| a62d533 | 158 | public void setIcon (ParticleEmitter emitters, ImageIcon icon) {
|
| a62d533 | 159 | ParticleData data = particleData.get(emitters); |
| a62d533 | 160 | if (data == null) particleData.put(emitters, data = new ParticleData()); |
| a62d533 | 161 | data.icon = icon; |
| a62d533 | 162 | } |
| a62d533 | 163 | |
| a62d533 | 164 | public void setEnabled (ParticleEmitter emitter, boolean enabled) {
|
| a62d533 | 165 | ParticleData data = particleData.get(emitter); |
| a62d533 | 166 | if (data == null) particleData.put(emitter, data = new ParticleData()); |
| a62d533 | 167 | data.enabled = enabled; |
| a62d533 | 168 | emitter.reset(); |
| a62d533 | 169 | } |
| a62d533 | 170 | |
| a62d533 | 171 | public boolean isEnabled (ParticleEmitter emitter) {
|
| a62d533 | 172 | ParticleData data = particleData.get(emitter); |
| a62d533 | 173 | if (data == null) return true; |
| a62d533 | 174 | return data.enabled; |
| a62d533 | 175 | } |
| a62d533 | 176 | |
| a62d533 | 177 | public void initializeComponents (LwjglAWTCanvas canvas) {
|
| a62d533 | 178 | canvas.getCanvas().setPreferredSize(new Dimension(300, 250)); |
| a62d533 | 179 | // Left |
| a62d533 | 180 | JPanel propertiesPanel = new JPanel(new BorderLayout()); |
| a62d533 | 181 | propertiesPanel.setBorder(new CompoundBorder(BorderFactory.createEmptyBorder(3, 0, 6, 6), BorderFactory |
| a62d533 | 182 | .createTitledBorder("Editor Properties")));
|
| a62d533 | 183 | editRowsPanel = new JPanel(new GridBagLayout()); |
| a62d533 | 184 | propertiesPanel.add(editRowsPanel, BorderLayout.CENTER); |
| a62d533 | 185 | |
| a62d533 | 186 | // Center |
| a62d533 | 187 | JPanel spacer = new JPanel(new BorderLayout()); |
| a62d533 | 188 | spacer.setBorder(new CompoundBorder(BorderFactory.createEmptyBorder(3, 0, 6, 6), BorderFactory |
| a62d533 | 189 | .createTitledBorder("Particle Effect")));
|
| a62d533 | 190 | spacer.add(canvas.getCanvas(), BorderLayout.CENTER); |
| a62d533 | 191 | |
| a62d533 | 192 | // Right |
| a62d533 | 193 | JPanel emittersPanel = new JPanel(new BorderLayout()); |
| a62d533 | 194 | emittersPanel.setBorder(new CompoundBorder(BorderFactory.createEmptyBorder(0, 6, 6, 0), BorderFactory |
| a62d533 | 195 | .createTitledBorder("Effect Emitters")));
|
| a62d533 | 196 | effectPanel = new EffectPanel(this); |
| a62d533 | 197 | emittersPanel.add(effectPanel, BorderLayout.CENTER); |
| a62d533 | 198 | emittersPanel.setPreferredSize(new Dimension(330, 250)); |
| a62d533 | 199 | |
| a62d533 | 200 | |
| a62d533 | 201 | JPanel propertiesPanel2 = new JPanel(new BorderLayout()); |
| a62d533 | 202 | propertiesPanel2.setBorder(new CompoundBorder(BorderFactory.createEmptyBorder(3, 0, 6, 6), BorderFactory |
| a62d533 | 203 | .createTitledBorder("Emitter Properties")));
|
| a62d533 | 204 | rowsPanel = new JPanel(new GridBagLayout()); |
| a62d533 | 205 | propertiesPanel2.add(rowsPanel, BorderLayout.CENTER); |
| a62d533 | 206 | |
| a62d533 | 207 | JPanel tool = new JPanel(new BorderLayout()); |
| a62d533 | 208 | tool.add(propertiesPanel, BorderLayout.WEST); |
| a62d533 | 209 | tool.add(spacer, BorderLayout.CENTER); |
| a62d533 | 210 | tool.add(emittersPanel, BorderLayout.EAST); |
| a62d533 | 211 | |
| a62d533 | 212 | splitPane = new JSplitPane(JSplitPane.VERTICAL_SPLIT); |
| a62d533 | 213 | splitPane.setDividerSize(4); |
| a62d533 | 214 | splitPane.add(tool, JSplitPane.TOP); |
| a62d533 | 215 | splitPane.add(new JScrollPane(propertiesPanel2), JSplitPane.BOTTOM); |
| a62d533 | 216 | splitPane.setDividerLocation(250); |
| a62d533 | 217 | add(splitPane, BorderLayout.CENTER); |
| a62d533 | 218 | } |
| a62d533 | 219 | |
| a62d533 | 220 | static class ParticleData {
|
| a62d533 | 221 | public ImageIcon icon; |
| a62d533 | 222 | public String imagePath; |
| a62d533 | 223 | public boolean enabled = true; |
| a62d533 | 224 | } |
| a62d533 | 225 | } |