001 package swingui;
002
003
004 import java.awt.BorderLayout;
005 import java.awt.Container;
006 import java.awt.GridLayout;
007 import java.awt.event.ActionEvent;
008 import java.awt.event.ActionListener;
009 import java.awt.event.KeyListener;
010 import java.awt.event.MouseListener;
011 import java.io.File;
012 import java.io.InputStream;
013 import java.net.URL;
014 import java.util.ArrayList;
015 import java.util.HashSet;
016 import java.util.List;
017 import java.util.Set;
018 import java.util.Timer;
019 import java.util.TimerTask;
020
021 import javax.media.opengl.GLCanvas;
022 import javax.media.opengl.GLCapabilities;
023 import javax.swing.JFileChooser;
024 import javax.swing.JFrame;
025 import javax.swing.JMenu;
026 import javax.swing.JMenuBar;
027 import javax.swing.JMenuItem;
028 import javax.swing.JOptionPane;
029 import javax.swing.JPanel;
030
031 import physics3d.Vect3;
032 import rendering.Renderer;
033 import rendering.Textures;
034
035 import components.Ball;
036 import components.GameObject;
037 import components.GameSettings;
038 import components.GameSpace;
039 import components.XMLReader;
040
041 public class MainGUI extends JFrame implements Runnable, ActionListener {
042 static final long serialVersionUID = 0;
043 //singleton
044 private static MainGUI maingui = new MainGUI();
045 private ClassLoader loader; //needed for java web start
046
047 //build or play mode
048 private boolean buildMode;
049
050 //GameSpace
051 private GameSpace gs;
052
053 //rendering stuff
054 private final GLCanvas canvasPanel;
055 private Renderer myRenderer;
056 private Timer animation;
057 private final TimerTask stepFrame;
058
059 //panels
060 private JPanel sideBar;
061 private ModePanel modeP;
062 private AddPanel addP;
063 private DetailPanel detP;
064
065 //menu stuff
066 private final JMenuBar menuBar;
067 private final JMenu fileMenu, skinMenu; // no modeMenu
068 private JMenuItem menuItem;
069 private JFileChooser jfc;
070
071 //listener
072 private MouseListener currentListener;
073
074 /** singleton of main GUI window/frame, use instance() to get it **/
075 public static MainGUI instance() {
076 return maingui;
077 }
078
079 //constructor is private
080 private MainGUI() {
081 super("Gizmoball 3D: IHTFC");
082 //class loader
083 loader = this.getClass().getClassLoader();
084 if (loader == null)
085 throw new RuntimeException("broken");
086
087 //default to play mode
088 buildMode = false;
089
090 this.setDefaultCloseOperation(EXIT_ON_CLOSE);
091 this.setResizable(false);
092 this.setSize(835, 645);
093
094 //GameSpace
095 gs = new GameSpace(new GameSettings());
096 this.addKeyListener(gs.getListener());
097
098 //////////////////
099 //GLCanvas Panel//
100 //////////////////
101 canvasPanel = new GLCanvas(new GLCapabilities());
102 myRenderer = new Renderer(gs);
103 canvasPanel.addGLEventListener(myRenderer);
104 canvasPanel.setSize(600, 600);
105
106 ////////////////
107 //Other Panels//
108 ////////////////
109 modeP = new ModePanel(this);
110 addP = new AddPanel(this);
111 detP = new DetailPanel(this);
112
113 ///////////
114 //MENUBAR//
115 ///////////
116 menuBar = new JMenuBar();
117 fileMenu = new JMenu("File");
118 skinMenu = new JMenu("Skins");
119
120 menuBar.add(fileMenu);
121 menuBar.add(skinMenu);
122
123 ///////
124 //new//
125 ///////
126 menuItem = new JMenuItem("New");
127 class NewGameListener implements ActionListener {
128 MainGUI parent;
129 public NewGameListener(MainGUI p) { parent = p; }
130 public void actionPerformed(ActionEvent e) {
131 GameSpace newGS = new GameSpace(new GameSettings());
132 parent.setGameSpace(newGS);
133 parent.reset();
134
135 //goes to build mode if it's not already
136 addP.setSelected(null); //clear
137 pause();
138 }
139 }
140 menuItem.addActionListener(new NewGameListener(this));
141 fileMenu.add(menuItem);
142
143 ////////
144 //load//
145 ////////
146
147 jfc = new JFileChooser();
148 jfc.setCurrentDirectory(new File("./xml"));
149
150 menuItem = new JMenuItem("Load");
151 class FileLoadListener implements ActionListener {
152 MainGUI parent;
153 public FileLoadListener(MainGUI p) { parent = p; }
154 public void actionPerformed(ActionEvent e) {
155 XMLReader reader = new XMLReader();
156 int returnVal = jfc.showOpenDialog(parent);
157 if (returnVal == JFileChooser.APPROVE_OPTION) {
158
159 try {
160 parent.setGameSpace(reader.readXMLFile(jfc.getSelectedFile().getPath()));
161 } catch (Exception e1) {
162 e1.printStackTrace();
163 JOptionPane.showMessageDialog(parent,
164 "Unable to read file. Violates schema",
165 "Error",
166 JOptionPane.ERROR_MESSAGE);
167
168 }
169 parent.reset();
170 play();
171 canvasPanel.display();
172 }
173 }
174 }
175 menuItem.addActionListener(new FileLoadListener(this));
176 fileMenu.add(menuItem);
177
178 ////////
179 //save//
180 ////////
181 menuItem = new JMenuItem("Save");
182 class SaveFileListener implements ActionListener {
183 MainGUI parent;
184 public SaveFileListener(MainGUI p) { parent = p; }
185 public void actionPerformed(ActionEvent e) {
186 int returnVal = jfc.showSaveDialog(parent);
187 if (returnVal == JFileChooser.APPROVE_OPTION) {
188 //System.out.println(jfc.getSelectedFile());
189 try {
190 gs.writeXML(jfc.getSelectedFile());
191 }
192 catch (Exception ex) {
193 JOptionPane.showMessageDialog(parent,
194 "Unable to save file. Violates schema: "+ex.getMessage(),
195 "Error",
196 JOptionPane.ERROR_MESSAGE);
197 }
198 }
199 }
200 }
201 menuItem.addActionListener(new SaveFileListener(this));
202 fileMenu.add(menuItem);
203
204 /////////
205 //skins//
206 /////////
207 menuItem = new JMenuItem("default");
208 menuItem.addActionListener(new ActionListener() {
209 public void actionPerformed(ActionEvent e) {
210 myRenderer.clearTextures();
211 gs.setTexLocations(Textures.getDefaultTex());
212 }
213 });
214 skinMenu.add(menuItem);
215
216 menuItem = new JMenuItem("natural");
217 menuItem.addActionListener(new ActionListener() {
218 public void actionPerformed(ActionEvent e) {
219 myRenderer.clearTextures();
220 gs.setTexLocations(Textures.getNaturalTex());
221 }
222 });
223 skinMenu.add(menuItem);
224
225 menuItem = new JMenuItem("cute");
226 menuItem.addActionListener(new ActionListener() {
227 public void actionPerformed(ActionEvent e) {
228 myRenderer.clearTextures();
229 gs.setTexLocations(Textures.getCuteTex());
230 canvasPanel.display();
231 }
232 });
233 skinMenu.add(menuItem);
234
235 ///////////////////////////
236 //Put everything together//
237 ///////////////////////////
238
239 Container mainPane = getContentPane();
240 mainPane.setLayout(new BorderLayout());
241
242 sideBar = new JPanel(new BorderLayout());
243 JPanel add_det = new JPanel(new GridLayout(2, 1));
244 add_det.add(addP);
245 add_det.add(detP);
246 sideBar.add(modeP, BorderLayout.NORTH);
247 sideBar.add(add_det, BorderLayout.CENTER);
248 sideBar.setSize(250, 600);
249
250 JPanel gamePanel = new JPanel(new BorderLayout());
251 gamePanel.add(sideBar, BorderLayout.WEST);
252 gamePanel.add(canvasPanel, BorderLayout.EAST);
253
254 mainPane.add(gamePanel, BorderLayout.CENTER);
255 mainPane.add(menuBar, BorderLayout.NORTH);
256
257 ///////////
258 //ANIMATE//
259 ///////////
260 //animation = new Timer(1000/gs.getSettings().getFPS(), this);
261 animation = new Timer();
262 stepFrame = new TimerTask() {
263 public void run() {
264 actionPerformed(null);
265 }
266 };
267 animation.scheduleAtFixedRate(stepFrame, 0, 1000/gs.getSettings().getFPS());
268 }
269
270 /** what to do at first **/
271 public void run() {
272 //start out in build mode
273 pause();
274 }
275
276 /** what do to when we switch to play mode:
277 * - notify each panel
278 * - unselect things from build mode
279 * - focus/display
280 */
281 public void play() {
282 buildMode = false;
283 //inform the panels
284 myRenderer.setPlayMode(true);
285 addP.deactivate();
286 detP.clear();
287 modeP.setPlayMode();
288
289 //unselect things if necessary, unregister listener
290 GameObject o = addP.getSelected();
291 if (o != null)
292 o.setSelected(false);
293 canvasPanel.removeMouseListener(getCurrentListener());
294
295 //focus on the game
296 this.requestFocus();
297 canvasPanel.display();
298 }
299
300 /** what to do when we switch from play to build mode:
301 * - restore last build-mode state
302 * - notify panels
303 */
304 public void pause() {
305 buildMode = true;
306 myRenderer.setPlayMode(false);
307 addP.activate();
308 modeP.setBuildMode();
309
310 //if already something selected from last build mode
311 GameObject o = addP.getSelected();
312 if (o != null) {
313 o.setSelected(true);
314 detP.update(o);
315 } else {
316 detP.clear();
317 }
318 //canvasPanel.display();
319 }
320
321 /** the main entry point for the application **/
322 public static void main(String[] args) {
323 MainGUI myGUI = MainGUI.instance();
324 myGUI.setVisible(true);
325 myGUI.run();
326 }
327
328 //do animation
329 public void actionPerformed(ActionEvent arg0) {
330 canvasPanel.display();
331 if (!buildMode) {
332 gs.stepFrame();
333 }
334 }
335
336 /**
337 * @return the gs
338 */
339 public GameSpace getGameSpace() {
340 return gs;
341 }
342
343
344 /**
345 * @param gs the gs to set
346 */
347 public void setGameSpace(GameSpace gs) {
348 this.gs = gs;
349 }
350
351 private void reset() {
352 for (KeyListener k : this.getKeyListeners())
353 this.removeKeyListener(k);
354 this.addKeyListener(gs.getListener());
355 canvasPanel.removeGLEventListener(myRenderer);
356 myRenderer = new Renderer(gs);
357 canvasPanel.addGLEventListener(myRenderer);
358 gs.getSettings().setFPS(20);
359 }
360
361 /**
362 * @return the GUI's GLCanvas
363 */
364 public GLCanvas getCanvas() {
365 return canvasPanel;
366 }
367
368 /**
369 * @return the Renderer of this GUI
370 */
371 public Renderer getRenderer() {
372 return myRenderer;
373 }
374
375 public MouseListener getCurrentListener() {
376 return currentListener;
377 }
378
379 /**
380 * @requires ml != null
381 * @modifies currentListener
382 * @effects sets currentListener to ml, registers with canvasPanel
383 */
384 public void setCurrentListener(MouseListener ml) {
385 canvasPanel.removeMouseListener(currentListener);
386 canvasPanel.addMouseListener(ml);
387 currentListener = ml;
388 }
389
390 /** @return true if in build mode **/
391 public boolean isBuildMode() {
392 return buildMode;
393 }
394
395 /**
396 * @return the DetailPanel of this GUI
397 */
398 public DetailPanel getDetailPanel() {
399 return detP;
400 }
401
402
403 public Vect3 getGridLocation(int x, int y) {
404 int xCoord = x/30;
405 int yCoord = y/30;
406 return new Vect3(xCoord, yCoord, 0);
407 }
408
409 /** get a gameobject in the given gridlocation. **/
410 public GameObject getObjectInGrid(Vect3 gridLoc) {
411 List<GameObject> objects = new ArrayList<GameObject>();
412 //find all objects in this gridLoc
413 for (GameObject obj : getGameSpace().getObjectsNoWalls()) {
414 if (obj instanceof Ball) {
415 //System.out.println("found a ball! " + obj.getTLF());
416 }
417 for(Vect3 p : obj.getOccupiedPositions()) {
418 //System.out.println(p);
419 if (gridLoc.equals(p)) {
420 //System.out.println("return value" + obj);
421 //return obj;
422 objects.add(obj);
423 }
424 }
425 }
426
427 //what to return?
428 if (objects.size() == 0) {
429 return null; //no objects, so return null
430 } else if (objects.size() == 1) {
431 return objects.get(0);
432 } else { //multiple objects
433 for (GameObject o : objects) {
434 if (o instanceof Ball)
435 continue;
436 else
437 return o;
438 }
439 //if we get here, all objects were Balls
440 return objects.get(0); //just return the first one
441 }
442 }
443
444 /** used to get a relative URL using ClassLoader... Java Web Start notameni **/
445 public static URL getFile(String filename) {
446 ////System.out.println("loader="+instance().loader);
447 ////System.out.println("filename="+filename);
448 return instance().loader.getResource(filename);
449 }
450
451 /** get a relative url as an inputstream, using classloader... req'd for jaws **/
452 public static InputStream getStream(String filename) {
453 return instance().loader.getResourceAsStream(filename);
454 }
455
456 }