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 }