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    }