PageRenderTime 65ms CodeModel.GetById 3ms app.highlight 51ms RepoModel.GetById 1ms app.codeStats 1ms

/src/org/mt4j/MTApplication.java

http://mt4j.googlecode.com/
Java | 1321 lines | 594 code | 182 blank | 545 comment | 114 complexity | 10e6e4395c6b1d61d13dbebe5b6ac02a MD5 | raw file
   1/***********************************************************************
   2 * mt4j Copyright (c) 2008 - 2009, C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
   3 *  
   4 *   This program is free software: you can redistribute it and/or modify
   5 *   it under the terms of the GNU General Public License as published by
   6 *   the Free Software Foundation, either version 3 of the License, or
   7 *   (at your option) any later version.
   8 *
   9 *   This program is distributed in the hope that it will be useful,
  10 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
  11 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12 *   GNU General Public License for more details.
  13 *
  14 *   You should have received a copy of the GNU General Public License
  15 *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16 *
  17 ***********************************************************************/
  18
  19package org.mt4j;
  20
  21import java.awt.Component;
  22import java.awt.Dimension;
  23import java.awt.DisplayMode;
  24import java.awt.GraphicsDevice;
  25import java.awt.GraphicsEnvironment;
  26import java.awt.Toolkit;
  27import java.awt.event.WindowAdapter;
  28import java.io.FileInputStream;
  29import java.io.FileNotFoundException;
  30import java.io.InputStream;
  31import java.util.ArrayDeque;
  32import java.util.ArrayList;
  33import java.util.Deque;
  34import java.util.Iterator;
  35import java.util.List;
  36import java.util.Properties;
  37
  38import javax.media.opengl.GL;
  39import javax.swing.ImageIcon;
  40
  41import org.mt4j.components.css.util.CSSStyleManager;
  42import org.mt4j.input.InputManager;
  43import org.mt4j.input.inputData.AbstractCursorInputEvt;
  44import org.mt4j.input.inputData.ActiveCursorPool;
  45import org.mt4j.input.inputData.InputCursor;
  46import org.mt4j.input.inputProcessors.globalProcessors.AbstractGlobalInputProcessor;
  47import org.mt4j.input.inputSources.AbstractInputSource;
  48import org.mt4j.sceneManagement.IPreDrawAction;
  49import org.mt4j.sceneManagement.ISceneChangeListener;
  50import org.mt4j.sceneManagement.Iscene;
  51import org.mt4j.sceneManagement.SceneChangeEvent;
  52import org.mt4j.sceneManagement.transition.ITransition;
  53import org.mt4j.util.MT4jSettings;
  54import org.mt4j.util.SettingsMenu;
  55import org.mt4j.util.animation.AnimationManager;
  56import org.mt4j.util.animation.ani.AniAnimation;
  57import org.mt4j.util.logging.ILogger;
  58import org.mt4j.util.logging.Log4jLogger;
  59import org.mt4j.util.logging.MTLoggerFactory;
  60import org.mt4j.util.math.Tools3D;
  61import org.mt4j.util.opengl.GLFBO;
  62
  63import processing.core.PApplet;
  64
  65
  66
  67/**
  68 * Use this class to create a new multitouch application.
  69 * <br>The best way to create your application would be to extend this class and
  70 * put the <code>main</code> method into that class.
  71 * In the <code>main</code> method call the <code>initialize()</code> method.
  72 * Then override the <code>startUp()</code> method which is called
  73 * automatically after the initialize method. The <code>startUp()</code> method can be used to
  74 * create your scenes (extend the <code>AbstractScene</code> class) and add them to
  75 * the application by calling <code>addScene</code> method.
  76 * 
  77 * <p>Internally, the main method of processings PApplet class is called with the class name
  78 * of the extended PApplet class as an argument. The PApplet class then instantiates the given
  79 * class and calls its setup() and then repeatedly its run() method.
  80 * 
  81 * @author Christopher Ruff
  82 */
  83public abstract class MTApplication extends PApplet {
  84	/** The Constant logger. */
  85	private static ILogger logger;
  86	
  87	public static String CUSTOM_OPENGL_GRAPHICS = "org.mt4j.util.opengl.CustomPGraphicsOpenGL"; //PApplet.OPENGL
  88	
  89	/** The Constant serialVersionUID. */
  90	private static final long serialVersionUID = 1L;
  91	
  92	/** The scene change locked. */
  93	private boolean sceneChangeLocked;
  94
  95//	private static MTApplication mtApp = null;
  96	
  97	/** The scene list. */
  98	private List<Iscene> sceneList;
  99	
 100	/** The current scene. */
 101	private Iscene currentScene;
 102	
 103	/** The animation mgr. */
 104	private AnimationManager animMgr;
 105	
 106	/** The time last frame. */
 107	private long timeLastFrame ;
 108	
 109	/** The already run. */
 110	private boolean alreadyRun;
 111	
 112	/** The input manager. */
 113	private InputManager inputManager;
 114	
 115	/** The scene changed listeners. */
 116	private List<ISceneChangeListener> sceneChangedListeners;
 117	
 118	/** The invoke later actions. */
 119	private Deque<Runnable> invokeLaterActions;
 120	
 121	/** The scene stack. */
 122	private ArrayDeque<Iscene> sceneStack;
 123	
 124	private Thread renderThread;
 125	
 126	public static String separator = "/";
 127	public static char separatorChar = '/';
 128	
 129	private static boolean settingsLoadedFromFile = false; //cant initialize in constructor, need it before that!
 130	
 131	private ImageIcon mt4jIcon;
 132
 133	private CSSStyleManager cssStyleManager;
 134
 135	private ArrayDeque<IPreDrawAction> preDrawActions;
 136	
 137//	private static boolean fullscreen;
 138	/*
 139	public static void main(String[] args){
 140//		MTApplication app  = new MTApplication();
 141		
 142		PApplet.main(new String[] {
 143//				   "--present", 
 144//				   "--exclusive",
 145				   "--bgcolor=#000000", 
 146				   "--hide-stop",
 147				   "org.mt4j.MTApplication"
 148				   }
 149				   ); 
 150	}
 151	@Override
 152	public void setup(){
 153		size(800,600, OPENGL); //TODO REMOVE
 154		logger.debug("Setup");
 155		System.out.println("Setup called");
 156		
 157		smooth();
 158		hint(ENABLE_OPENGL_2X_SMOOTH );
 159		smooth();
 160		noSmooth();
 161		
 162		background(0);
 163		
 164		GL gl = Tools3D.getGL(this);
 165//		 gl.glEnable(GL.GL_MULTISAMPLE);
 166//	     gl.glEnable(GL.GL_MULTISAMPLE_EXT);
 167	}
 168	@Override
 169	public void draw(){
 170//		background(255);
 171		
 172		fill(250,0,0,255);
 173		stroke(250,0,0,255);
 174		line(0,10, 280,20);
 175		
 176		GL gl = Tools3D.beginGL(this);
 177//		GL gl =  ((PGraphicsOpenGL)this.g).beginGL();
 178//		gl.glEnable(GL.GL_LINE_SMOOTH );  
 179		gl.glDisable(GL.GL_LINE_SMOOTH );  
 180//		gl.glHint(GL.GL_LINE_SMOOTH_HINT, GL.GL_NICEST);  
 181		// Enable Blending 
 182		gl.glEnable(GL.GL_BLEND);  
 183		// Specifies pixel arithmetic  
 184		gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); 
 185		gl.glLineWidth(1);
 186		gl.glColor4d(0.0, 0.0, 0.0, 1);
 187		
 188		gl.glBegin(GL.GL_LINE_STRIP);
 189		gl.glVertex3d(0, 20, 0);
 190		gl.glVertex3d(280, 30, 0);
 191		gl.glEnd();
 192		
 193		gl.glBegin(GL.GL_LINE_STRIP);
 194		gl.glVertex3d(0, 20, 0);
 195		gl.glVertex3d(711, 230, 0);
 196		gl.glVertex3d(200, 300, 0);
 197		gl.glVertex3d(100, 330, 0);
 198		gl.glEnd();
 199//		((PGraphicsOpenGL)this.g).endGL();
 200		
 201		Tools3D.endGL(this);
 202		
 203		if (this.mousePressed){
 204			fill(150);
 205			rect(mouseX, mouseY, 10,10);
 206		}
 207	}
 208	*/
 209	
 210	/*
 211	//TODO test to make window undecorated - seems to mess up some textures (maybe because opengl re-initialization)
 212	//put frame.setLocation(-1600, 0); at the end of setup() to position the frame 
 213	public void init(){
 214		  // to make a frame not displayable, you can
 215		  // use frame.removeNotify()
 216		  frame.removeNotify();
 217
 218		  frame.setUndecorated(true);
 219
 220		  // addNotify, here i am not sure if you have 
 221		  // to add notify again.  
 222		  frame.addNotify();
 223		  super.init();
 224		}
 225	*/
 226	
 227
 228
 229
 230	/**
 231	 * Dont instiatiate this class directly!
 232	 * It gets instantiated by the PApplet class via
 233	 * java reflection.
 234	 */
 235	public MTApplication(){
 236		sceneList 		= new ArrayList<Iscene>();
 237		currentScene 	= null;
 238		animMgr 		= AnimationManager.getInstance();
 239		alreadyRun 		= false;
 240		
 241		sceneChangedListeners = new ArrayList<ISceneChangeListener>();
 242		invokeLaterActions = new ArrayDeque<Runnable>();
 243		sceneStack = new ArrayDeque<Iscene>();
 244		
 245		sceneChangeLocked = false;
 246		cssStyleManager = new CSSStyleManager(this);
 247		
 248		preDrawActions = new ArrayDeque<IPreDrawAction>();
 249		
 250	}
 251	
 252	/**
 253	 * Initializes the processings settings.
 254	 * Call this method in your main method prior to anything else!
 255	 */
 256	public static void initialize(){
 257		initialize(new CurrentClassGetter().getClassName());
 258	}
 259	
 260	public static void initialize(boolean showSettingsMenu){
 261		initialize(new CurrentClassGetter().getClassName(), showSettingsMenu);
 262	}
 263	
 264	
 265	public static void initialize(String classToInstantiate){
 266		initialize(classToInstantiate, false);
 267	}
 268	
 269	
 270	/**
 271	 * Initializes the processings settings.
 272	 * Call this method in your main method prior to anything else!
 273	 * We have to provide the fully qualified name to the class that
 274	 * we are calling this from. (Should be our MTAplication extended class)
 275	 * This is needed because processing will use the reflection api to instantiate
 276	 * an instance of the MTApplication class.
 277	 * <br>E.g.: <code>initialize("myPackage.myMainClass");</code>
 278	 *
 279	 * @param classToInstantiate the class to instantiate
 280	 * @param showSettingsMenu show settings menu
 281	 */
 282	public static void initialize(String classToInstantiate, boolean showSettingsMenu){
 283		//Initialize Loggin facilities  - IMPORTANT TO DO THIS ASAP!
 284		MTLoggerFactory.setLoggerProvider(new Log4jLogger()); //FIXME TEST
 285//		MTLoggerFactory.setLoggerProvider(new JavaLogger()); //FIXME TEST
 286		logger = MTLoggerFactory.getLogger(MTApplication.class.getName());
 287		logger.setLevel(ILogger.INFO);
 288		logger.debug(classToInstantiate + " is the class instatiated by PApplet class.");
 289		 
 290		//FIXME TEST
 291		if (showSettingsMenu){
 292			settingsLoadedFromFile = true;
 293			SettingsMenu menu = new SettingsMenu(classToInstantiate);
 294			menu.setVisible(true);
 295		}else{
 296			getSettingsFromFile();
 297
 298			// Launch processing PApplet main() function
 299			if (MT4jSettings.getInstance().isFullscreen()){
 300				if (MT4jSettings.getInstance().isFullscreenExclusive()){
 301					PApplet.main(new String[] {
 302							"--display=" + MT4jSettings.getInstance().getDisplay(),
 303							"--present", 
 304							"--exclusive", 
 305							"--bgcolor=#000000", 
 306							"--hide-stop",
 307							classToInstantiate}
 308					); 
 309				}else{
 310					PApplet.main(new String[] {
 311							"--display=" + MT4jSettings.getInstance().getDisplay(),
 312							"--present", 
 313							"--bgcolor=#000000", 
 314							"--hide-stop",
 315							classToInstantiate}
 316					); 
 317				}
 318			}else{
 319				PApplet.main(new String[] { 
 320						"--display=" + MT4jSettings.getInstance().getDisplay(),
 321						classToInstantiate }); 
 322			}
 323		}
 324
 325	}
 326	
 327	
 328	private static void getSettingsFromFile(){
 329		 //Load some properties from Settings.txt file
 330		 Properties properties = new Properties();
 331		 try {
 332			 try {
 333				 FileInputStream fi = new FileInputStream(MT4jSettings.getInstance().getDefaultSettingsPath() + "Settings.txt");
 334				 properties.load(fi);	
 335			} catch (FileNotFoundException e) {
 336				logger.debug("Couldnt load Settings.txt from the File system. Trying to load it as a resource..");
 337				InputStream in = Thread.currentThread().getContextClassLoader().getResourceAsStream("Settings.txt");
 338				 if (in != null){
 339					 properties.load(in);	
 340				 }else{
 341					 logger.debug("Couldnt load Settings.txt as a resource. Using defaults.");
 342					 throw new FileNotFoundException("Couldnt load Settings.txt as a resource");
 343				 }
 344			}
 345
 346			 MT4jSettings.fullscreen = Boolean.parseBoolean(properties.getProperty("Fullscreen", Boolean.valueOf(MT4jSettings.getInstance().isFullscreen()).toString()).trim());
 347			 //Use java's fullscreen exclusive mode (real fullscreen) or just use an undecorated window at fullscreen size 
 348			 MT4jSettings.getInstance().fullscreenExclusive = Boolean.parseBoolean(properties.getProperty("FullscreenExclusive", Boolean.valueOf(MT4jSettings.getInstance().isFullscreenExclusive()).toString()).trim());
 349			 //Which display to use for fullscreen
 350			 MT4jSettings.getInstance().display = Integer.parseInt(properties.getProperty("Display", String.valueOf(MT4jSettings.getInstance().getDisplay())).trim());
 351
 352			 MT4jSettings.getInstance().windowWidth = Integer.parseInt(properties.getProperty("DisplayWidth", String.valueOf(MT4jSettings.getInstance().getWindowWidth())).trim());
 353			 MT4jSettings.getInstance().windowHeight = Integer.parseInt(properties.getProperty("DisplayHeight", String.valueOf(MT4jSettings.getInstance().getWindowHeight())).trim());
 354			 
 355			 //FIXME at fullscreen really use the screen dimension? -> we need to set the native resoultion ourselves!
 356			 //so we can have a lower fullscreen resolution than the screen dimensions
 357			 if (MT4jSettings.getInstance().isFullscreen() && !MT4jSettings.getInstance().isFullscreenExclusive()){
 358				 Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
 359				 MT4jSettings.getInstance().windowWidth = screenSize.width;
 360				 MT4jSettings.getInstance().windowHeight = screenSize.height;
 361			 }
 362			 /*
 363			 //Comment this to not change the window width to the screen width in fullscreen mode
 364			 else{
 365				 
 366			 }
 367			 */
 368			 
 369			 MT4jSettings.getInstance().maxFrameRate = Integer.parseInt(properties.getProperty("MaximumFrameRate", String.valueOf(MT4jSettings.getInstance().getMaxFrameRate())).trim());
 370			 MT4jSettings.getInstance().renderer = Integer.parseInt(properties.getProperty("Renderer", String.valueOf(MT4jSettings.getInstance().getRendererMode())).trim());
 371			 MT4jSettings.getInstance().numSamples = Integer.parseInt(properties.getProperty("OpenGLAntialiasing", String.valueOf(MT4jSettings.getInstance().getNumSamples())).trim());
 372
 373			 MT4jSettings.getInstance().vSync = Boolean.parseBoolean(properties.getProperty("Vertical_sync", Boolean.valueOf(MT4jSettings.getInstance().isVerticalSynchronization()).toString()).trim());
 374
 375			 //Set frametitle
 376			 String frameTitle = properties.getProperty("Frametitle", MT4jSettings.getInstance().getFrameTitle().trim());
 377			 MT4jSettings.getInstance().frameTitle = frameTitle;
 378
 379		 } catch (Exception e) {
 380			 logger.error("Error while loading Settings.txt. Using defaults.");
 381		 }
 382		 settingsLoadedFromFile = true;
 383	}
 384
 385
 386	protected void switchResolution() {
 387		logger.debug("Switching resolution..");
 388		try {
 389			frame.enableInputMethods(false);
 390			frame.setIgnoreRepaint(true);
 391			final GraphicsDevice myGraphicsDevice = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();
 392			
 393			// Get the current display mode
 394	        final DisplayMode previousDisplayMode= myGraphicsDevice.getDisplayMode();
 395			
 396//			final int width = 1280;
 397//			final int height = 768;
 398			final int width = MT4jSettings.getInstance().getWindowWidth();
 399			final int height = MT4jSettings.getInstance().getWindowHeight();
 400			int bitDepth = 32;
 401			int refreshRate = myGraphicsDevice.getDisplayMode().getRefreshRate();
 402			
 403			myGraphicsDevice.setFullScreenWindow(this.frame); 
 404			
 405            // Check if display mode changes are supported by the OS
 406            if (myGraphicsDevice.isDisplayChangeSupported()) {
 407                // Get all available display modes
 408                DisplayMode[] displayModes = myGraphicsDevice.getDisplayModes();
 409                DisplayMode multiBitsDepthSupportedDisplayMode = null;
 410                DisplayMode refreshRateUnknownDisplayMode = null;
 411                DisplayMode multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode = null;
 412                DisplayMode matchingDisplayMode = null;
 413                DisplayMode currentDisplayMode;
 414                // Look for the display mode that matches with our parameters
 415                // Look for some display modes that are close to these parameters
 416                // and that could be used as substitutes
 417                // On some machines, the refresh rate is unknown and/or multi bit
 418                // depths are supported. If you try to force a particular refresh 
 419                // rate or a bit depth, you might find no available display mode
 420                // that matches exactly with your parameters
 421                for (int i = 0; i < displayModes.length && matchingDisplayMode == null; i++) {
 422                    currentDisplayMode = displayModes[i];
 423                    if (currentDisplayMode.getWidth()  == width &&
 424                        currentDisplayMode.getHeight() == height) {
 425                        if (currentDisplayMode.getBitDepth() == bitDepth) {
 426                            if (currentDisplayMode.getRefreshRate() == refreshRate) {
 427                                matchingDisplayMode = currentDisplayMode;
 428                            } else if (currentDisplayMode.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN) {
 429                                refreshRateUnknownDisplayMode = currentDisplayMode;
 430                            }
 431                        } else if (currentDisplayMode.getBitDepth() == DisplayMode.BIT_DEPTH_MULTI) {
 432                            if (currentDisplayMode.getRefreshRate() == refreshRate) {
 433                                multiBitsDepthSupportedDisplayMode = currentDisplayMode;
 434                            } else if (currentDisplayMode.getRefreshRate() == DisplayMode.REFRESH_RATE_UNKNOWN) {
 435                                multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode = currentDisplayMode;
 436                            }
 437                        }
 438                    }
 439                }
 440                DisplayMode nextDisplayMode = null;
 441                if (matchingDisplayMode != null) {
 442                    nextDisplayMode = matchingDisplayMode;                    
 443                } else if (multiBitsDepthSupportedDisplayMode != null) {
 444                    nextDisplayMode = multiBitsDepthSupportedDisplayMode;
 445                } else if (refreshRateUnknownDisplayMode != null) {
 446                    nextDisplayMode = refreshRateUnknownDisplayMode;
 447                } else if (multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode != null) {
 448                    nextDisplayMode = multiBitsDepthSupportedAndRefreshRateUnknownDisplayMode;
 449                } else {
 450//                    isFullScreenSupported = false;
 451                	logger.error("No matching fullscreen display mode found!");
 452                }
 453
 454                if (nextDisplayMode != null){
 455                	/*
 456                		DisplayMode myDisplayMode = new DisplayMode(
 457                				width,
 458                				height,
 459                				myGraphicsDevice.getDisplayMode().getBitDepth(),
 460                				DisplayMode.REFRESH_RATE_UNKNOWN);
 461                				myGraphicsDevice.setDisplayMode(myDisplayMode);
 462                	 */
 463
 464                	myGraphicsDevice.setDisplayMode(nextDisplayMode);
 465
 466                	Component[] myComponents = frame.getComponents();
 467                	for (int i = 0; i < myComponents.length; i++) {
 468                		if (myComponents[i] instanceof PApplet) {
 469                			myComponents[i].setLocation(0, 0);
 470                		}
 471                	}
 472                	
 473                	frame.addWindowListener(new WindowAdapter() {
 474                		 @Override
 475                		public void windowClosing(java.awt.event.WindowEvent e) {
 476                			// If required, restore the previous display mode
 477                                myGraphicsDevice.setDisplayMode(previousDisplayMode);
 478                            // If required, get back to the windowed mode
 479                            if (myGraphicsDevice.getFullScreenWindow() == frame) {
 480                            	myGraphicsDevice.setFullScreenWindow(null);
 481                            }
 482                		}
 483                    });
 484                }
 485            }
 486		} 
 487		catch (Exception e) {
 488			e.printStackTrace();
 489		}
 490	}
 491
 492	/**
 493	 * ***********************************************************
 494	 * Processings setup. this is called once when the applet is started
 495	 * Used to define some initial settings
 496	 * **********************************************************.
 497	 */
 498	@Override
 499	public void setup(){
 500		//TOGGLES ALWAYS ON TOP MODE
 501		//this.frame.setAlwaysOnTop(true);
 502		if (logger == null){
 503			//Initialize Loggin facilities  - IMPORTANT TO DO THIS ASAP!//////
 504			MTLoggerFactory.setLoggerProvider(new Log4jLogger()); 
 505			logger = MTLoggerFactory.getLogger(MTApplication.class.getName());
 506			logger.setLevel(ILogger.INFO);
 507		}
 508
 509		logger.debug("-> setup called");
 510
 511		//Check if OS 32/64 Bit
 512		String bit = System.getProperty("sun.arch.data.model");
 513		logger.info("Platform: \"" + System.getProperty("os.name") + "\" -> Version: \"" + System.getProperty("os.version") +  "\" -> JVM Bit: \"" + bit + "\""); 
 514		MT4jSettings.getInstance().architecture = bit.contains("64")? MT4jSettings.ARCHITECTURE_64_BIT : MT4jSettings.ARCHITECTURE_32_BIT;
 515
 516		if (!settingsLoadedFromFile){
 517			getSettingsFromFile();
 518		}
 519		
 520		// Applet size - size() must be the first command in setup() method
 521		if (MT4jSettings.getInstance().getRendererMode() == MT4jSettings.OPENGL_MODE)
 522			this.size(MT4jSettings.getInstance().getWindowWidth(), MT4jSettings.getInstance().getWindowHeight(), MTApplication.CUSTOM_OPENGL_GRAPHICS);
 523		else if (MT4jSettings.getInstance().getRendererMode() == MT4jSettings.P3D_MODE)
 524			this.size(MT4jSettings.getInstance().getWindowWidth(), MT4jSettings.getInstance().getWindowHeight(), PApplet.P3D);
 525		
 526		//Switch to different resolution in fullscreen exclusive mode if neccessary
 527		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
 528		if (MT4jSettings.getInstance().isFullscreen() && MT4jSettings.getInstance().isFullscreenExclusive() && MT4jSettings.getInstance().getWindowWidth() != screenSize.width && MT4jSettings.getInstance().getWindowHeight() != screenSize.height){
 529			switchResolution();
 530		}
 531		
 532	    /*
 533	    //Processing Bug? seems to always use 2 samples 
 534	    if (MT4jSettings.getInstance().getNumSamples() <= 0){
 535	    	hint(DISABLE_OPENGL_2X_SMOOTH);
 536	    }else if (MT4jSettings.getInstance().getNumSamples() == 2){
 537	    	//Nothing to set, Processing default anyway
 538	    }else if (MT4jSettings.getInstance().getNumSamples() == 4){
 539	    	hint(DISABLE_OPENGL_2X_SMOOTH);
 540	    	hint(ENABLE_OPENGL_4X_SMOOTH);
 541	    }
 542	    */
 543	    
 544//	    pContext.hint( PApplet.ENABLE_OPENGL_4X_SMOOTH );  // ENABLES OPENGL EXTRA SMOOTHING -> DOESENT GET CONSISTENT RESULTS ON ALL MACHINES! DISABLE WHEN PROBLEMS OCCUR!
 545		//hint(ENABLE_DEPTH_SORT); // Enable primitive z-sorting of triangles and lines in P3D and OPENGL. This can slow performance considerably, and the algorithm is not yet perfect.
 546		//hint(DISABLE_ERROR_REPORT); // Speeds up the OPENGL renderer setting by not checking for errors while running.
 547		//hint(ENABLE_ACCURATE_TEXTURES); //Enables better texture accuracy for the P3D renderer. This option will do a better job of dealing with textures in perspective.  
 548		
 549		// Save this applets rendering thread for reference
 550		this.renderThread = Thread.currentThread();
 551		//System.out.println("Current Thread: "+  Thread.currentThread());
 552		
 553		// Set frame icon image
 554		try {
 555			//Set the window frame's title
 556			frame.setTitle(MT4jSettings.getInstance().getFrameTitle()); 
 557//			this.mt4jIcon = new ImageIcon(MT4jSettings.getInstance().getDefaultImagesPath() + 
 558//					"MT4j.gif");
 559			this.mt4jIcon = new ImageIcon(Thread.currentThread().getContextClassLoader().getResource(MT4jSettings.getInstance().getDefaultImagesPath() + 
 560			"MT4j.gif"));
 561			this.frame.setIconImage(mt4jIcon.getImage()); 
 562		}catch (Exception e){
 563			e.printStackTrace();
 564		}
 565		
 566		logger.info("MT4j window dimensions: \"" + MT4jSettings.getInstance().getWindowWidth() + " X " +  MT4jSettings.getInstance().getWindowHeight() + "\"");
 567		
 568//		//Set background color
 569//	    pContext.background(MT4jSettings.getInstance().getBackgroundClearColor());
 570		background(150);
 571		
 572		//Set the framerate
 573	    frameRate(MT4jSettings.getInstance().getMaxFrameRate());
 574	    logger.info("Maximum framerate: \"" + MT4jSettings.getInstance().getMaxFrameRate() + "\"");
 575	    
 576	    //FIXME TODO add in settings.txt?
 577	    hint(MTApplication.DISABLE_OPENGL_ERROR_REPORT);
 578		
 579		MT4jSettings.getInstance().programStartTime = System.currentTimeMillis();
 580		
 581		//Apply some opengl settings like V-Syncing or multi-Sampling
 582		this.applyOpenGLStartSettings();
 583		
 584		//Create a new inputsourcePool
 585		this.setInputManager(new InputManager(this));
 586		
 587		AniAnimation.init(this); //Initialize Ani animation library
 588		
 589		/*
 590		* Resizable Window test
 591		* Problems:
 592		* - all textures, shaders etc get destroyed because a new gl context is created
 593		* - cursor coordiantes are calculated wrong? we prolly have to update Papplet width/height 
 594		frame.setResizable(true);
 595		frame.addComponentListener(new ComponentAdapter() {
 596			public void componentResized(ComponentEvent e) {
 597				if(e.getSource() == frame) { 
 598					frame.setSize(frame.getWidth(), minHeight); 
 599				}
 600			}
 601		} );
 602		*/ 
 603		
 604		//Call startup at the end of setup(). Should be overridden in extending classes
 605		this.startUp();
 606	}
 607	
 608	/**
 609	 * Apply open gl start settings.
 610	 */
 611	private void applyOpenGLStartSettings(){
 612		//TODO pa.smooth() / pa.noSmooth() ver?ndert auch line_smooth!
 613		//f?r test ob multisampling lines ohne Line_smooth okay rendered m?ssen
 614		//sicherheitshalber auch die pa.smoot() etc abgefangen werden und line_smooth immer disabled sein!
 615		
 616		//TODO check line drawing and abstractvisible at stencil in this context (line_smooth)
 617		
 618	    //TODO 
 619		// - if multisampling enabled dont do line smoothing at all
 620		// - OR: disable multisampling each time before doing line_smoothing! (better but expensive?) 
 621		//   -> info: disabling multisampling isnt possible at runtime..
 622
 623	    // - or disable mutisample before drawing with line_smooth!
 624		//TOOD dont use lines to smooth some objects then (fonts, etc)
 625	    if (MT4jSettings.getInstance().isOpenGlMode() ){
 626	    	GL gl = Tools3D.getGL(this);
 627	    	
 628	    	logger.info("OpenGL Version: \"" + gl.glGetString(GL.GL_VERSION) + "\"" + " - Vendor: \"" + gl.glGetString(GL.GL_VENDOR) + "\"" + " - Renderer: \"" + gl.glGetString(GL.GL_RENDERER) + "\"");
 629//	    	logger.info("Shading language version: \"" +  gl.glGetString(GL.GL_SHADING_LANGUAGE_VERSION) + "\"");
 630	    	logger.info("Non power of two texture sizes allowed: \"" + Tools3D.supportsNonPowerOfTwoTexture(this) + "\"");
 631	    	logger.info("OpenGL Framebuffer Object Extension available: \"" + GLFBO.isSupported(this) + "\"");
 632	    	
 633			//Set VSyncing on -> to avoid tearing 
 634			//-> check if gfx card settings allow apps to set it!
 635			//-> Use with caution! only use with fps rate == monitor Hz!
 636			//and fps never drop below Hz! -> else choppy!
 637			//-> only works with opengl!
 638	    	Tools3D.setVSyncing(this, MT4jSettings.getInstance().isVerticalSynchronization());
 639			logger.info("Vertical Sync enabled: \"" + MT4jSettings.getInstance().isVerticalSynchronization() + "\"");
 640	    	
 641	    	if ( MT4jSettings.getInstance().isMultiSampling()){
 642	    		gl.glEnable(GL.GL_MULTISAMPLE);
 643//	    		gl.glDisable(GL.GL_MULTISAMPLE);
 644	    		logger.info("OpenGL multi-sampling enabled.");
 645	    	}
 646	    	gl.glEnable(GL.GL_LINE_SMOOTH);
 647//	    	gl.glDisable(GL.GL_LINE_SMOOTH);
 648	    }
 649	}
 650	
 651	public void setOpenGLErrorReportingEnabled(boolean reportErros){
 652		if (reportErros){
 653			hint(MTApplication.ENABLE_OPENGL_ERROR_REPORT);
 654		}else{
 655			hint(MTApplication.DISABLE_OPENGL_ERROR_REPORT);
 656		}
 657	}
 658	
 659	/**
 660	 * ********************************************************************************************
 661	 * Processings draw() gets called repeatedly by processings PApplet Class - unless noloop() is called
 662	 * ********************************************************************************************.
 663	 */
 664	@Override
 665	public void draw(){
 666		this.runApplication();
 667	}
 668	
 669	
 670	/**
 671	 * Is called at the end of the setup() method.
 672	 * <br>Override this method in your extended MTApplication class!
 673	 */
 674	public abstract void startUp();
 675	
 676	
 677	/**
 678	 * Registers an action to be processed before the next frame
 679	 * in the main drawing thread.
 680	 * 
 681	 * @param action the action
 682	 */
 683	public void registerPreDrawAction(final IPreDrawAction action){
 684		synchronized (preDrawActions) {
 685//			this.preDrawActions.addLast(action);
 686			invokeLater(new Runnable() {
 687				public void run() {
 688					preDrawActions.addLast(action);
 689				}
 690			});
 691		}
 692	}
 693
 694	
 695	/**
 696	 * Unregisters an PreDrawAction.
 697	 * 
 698	 * @param action the action
 699	 */
 700	public void unregisterPreDrawAction(final IPreDrawAction action){
 701		synchronized (preDrawActions) {
 702			if (preDrawActions.contains(action)){
 703//				this.preDrawActions.remove(action);
 704				invokeLater(new Runnable() {
 705					public void run() {
 706						preDrawActions.remove(action);
 707					}
 708				});
 709			}
 710		}
 711	}
 712	
 713	
 714	/**
 715	 * Main run loop.
 716	 * <li>Updates the time passed since the last time drawn.
 717	 * <li>Updates any animations with the new time delta.
 718	 * <li>Updates and draws the current scene.
 719	 * <li>Updates and draws the current scene transitions.
 720	 */
 721	private void runApplication(){ 
 722		//Process preDrawActions
 723		synchronized (preDrawActions) {
 724			for (Iterator<IPreDrawAction> iter = preDrawActions.iterator(); iter.hasNext();) {
 725				IPreDrawAction action = iter.next();
 726				action.processAction();
 727				if (!action.isLoop()){
 728					iter.remove(); 
 729				}
 730			}
 731		}
 732
 733		//Use nanoTime
 734		if (!alreadyRun){
 735			alreadyRun = true;
 736			timeLastFrame = System.nanoTime();
 737		}
 738		long nanos = System.nanoTime();
 739		long timeDelta = (nanos - timeLastFrame) / 1000000L;
 740		timeLastFrame = nanos;
 741		
 742		/*
 743		//Use currentTimeMillis
 744		if (!alreadyRun){
 745			alreadyRun = true;
 746			timeLastFrame = System.currentTimeMillis();
 747		}
 748		long millis = System.currentTimeMillis();
 749		long timeDelta = millis - timeLastFrame;
 750		timeLastFrame = millis;
 751		*/
 752		
 753//		System.out.println("TimeDelta: " + timeDelta);
 754		
 755		//Run invoke later actions
 756		synchronized (invokeLaterActions) {
 757			while (!invokeLaterActions.isEmpty()){
 758				invokeLaterActions.pollFirst().run();
 759			}
 760		}
 761		
 762		//Update animation manager
 763		animMgr.update(timeDelta);
 764		
 765//		/*
 766		//Handle scene transitions
 767		if (this.pendingTransition != null){
 768			//Run the transition
 769			this.pendingTransition.transition.drawAndUpdate(this.g, timeDelta);
 770			
 771			if (this.pendingTransition.transition.isFinished()){
 772				this.pendingTransition.transition.onLeave();
 773				this.doSceneChange(this.getCurrentScene(), this.pendingTransition.nextScene);
 774				this.pendingTransition = null;
 775			}
 776		}else{
 777			//Draw the current scene
 778			Iscene theCurrentScene = this.getCurrentScene();
 779			if (theCurrentScene != null){
 780				theCurrentScene.drawAndUpdate(this.g, timeDelta);	
 781			}
 782		}
 783//		 */
 784		
 785		/*
 786		//Update scene
 787		sceneMgr.updateCurrentScene(timeDelta);
 788		//Draw scene
 789		sceneMgr.drawCurrentScene();
 790		 */
 791	}
 792
 793	
 794	/**
 795	 * Checks if is render thread is current.
 796	 *
 797	 * @return true, if is render thread current
 798	 */
 799	public boolean isRenderThreadCurrent(){
 800		return Thread.currentThread().equals(renderThread);
 801	}
 802	
 803	
 804	/**
 805	 * Invokes the specified runnable at the beginning the next rendering loop in the rendering thread.
 806	 * This is especially useful for executing opengl commands from another thread - which would lead to errors
 807	 * if not synchronized with the rendering thread.
 808	 * 
 809	 * @param runnable the runnable
 810	 */
 811	public void invokeLater(Runnable runnable){
 812		synchronized (invokeLaterActions) {
 813			invokeLaterActions.addLast(runnable);	
 814		}
 815	}
 816	
 817	
 818	/**
 819	 * Checks which scene is on top of the scene stack at the moment.
 820	 * If no scene has been pushed on the stack, null is returned.
 821	 * 
 822	 * @return the iscene
 823	 */
 824	public Iscene peekScene(){
 825		return sceneStack.peek();
 826	}
 827	
 828	public int getSceneStackCount(){
 829		return sceneStack.size();
 830	}
 831	
 832	/**
 833	 * Pushes the current scene on the scene stack.
 834	 */
 835	public void pushScene(){
 836		if (getCurrentScene() == null){
 837			logger.debug("Scene stack is empty! No scene to put on the stack!");
 838		}else{
 839			logger.debug("Putting scene: " + getCurrentScene().getName() +  " on the stack.");
 840			sceneStack.offerFirst(getCurrentScene());
 841		}
 842	}
 843	
 844	
 845	/**
 846	 * Pops the scene thats currently ontop of the scene stack and changes back to it. 
 847	 * If the stack is empty no error is thrown and no scene change will happen.
 848	 */
 849	public boolean popScene(){
 850//		Iscene stackScene = sceneStack.pollFirst();
 851		
 852		Iscene stackScene = sceneStack.peek();
 853		if (stackScene != null){
 854			logger.debug("Popping scene: " + stackScene.getName() +  " back from the stack.");
 855			boolean changed = this.changeScene(stackScene);
 856			if (changed){
 857				sceneStack.pollFirst();
 858				return true;
 859			}else{
 860				return false;
 861			}
 862		}else{
 863			logger.warn("Scene stack is empty! No scene to pop from the stack!");
 864			return false;
 865		}
 866	}
 867	
 868	
 869	
 870	private boolean inDoSceneChange = false;
 871	private TransitionInfo pendingTransition;
 872	
 873	/**
 874	 * The Class TransitionInfo. Holding info about a scene change transition.
 875	 * @author Christopher Ruff
 876	 */
 877	private class TransitionInfo{
 878		ITransition transition;
 879		Iscene lastScene;
 880		Iscene nextScene;
 881		boolean destroyLastSceneAfterTransition = false; 
 882		public TransitionInfo(ITransition transition, Iscene lastScene, Iscene nextScene){
 883			this.transition = transition;
 884			this.lastScene = lastScene;
 885			this.nextScene = nextScene;
 886		}
 887	}
 888	
 889	
 890	/**
 891	 * Initiates the scene change. Checks if the old scene has a transition
 892	 * and sets it to be used in the main loop.
 893	 * 
 894	 * @param oldScene the old scene
 895	 * @param newScene the new scene
 896	 */
 897	private boolean initiateSceneChange(Iscene oldScene, Iscene newScene){
 898		//FIXME TEST!
 899		if (oldScene.equals(newScene)){
 900			logger.error("Trying to change from and to the same scene.");
 901			return false;
 902		}
 903		
 904		//Lock scene changes to only 1 at a time. At sending the bridge events during the 
 905		//scene change, it could occur that a scene change could be triggered again which we prevent
 906		if (!sceneChangeLocked){
 907			sceneChangeLocked = true;
 908			
 909			Iscene lastScene = this.getCurrentScene();
 910			
 911			//Remove pending animations // 
 912			//FIXME problemes, if new animations are defined in a scenes constructor, they get removed here..
 913			//AnimationManager.getInstance().clear();
 914			
 915			//Flush events so that enqueued input ended get sent to the last scene
 916			//(Problem: they have been removed from active cursor pool already so they dont
 917			//appear there and no ended and started evts are sent to the scenes!
 918			//IF input started or updated should be flushed with this they should appear in active
 919			//cursor list after that and be sended the right events
 920			//- maybe only flush input_ended?
 921			for (AbstractInputSource abstractInputSource : getInputManager().getInputSources()) {
 922				abstractInputSource.flushEvents();
 923			}
 924			
 925			//Check which cursors are still active and clone their last evt as INPUT_ENDED
 926			//so the scene can complete its state (i.e. buttons are be released etc)
 927			this.sendEndedEvents(lastScene); 
 928
 929			//Disable the last scene's global input processors
 930			this.getInputManager().disableGlobalInputProcessors(lastScene);
 931			
 932//			/*
 933			if (lastScene.getTransition() != null){
 934				ITransition t = lastScene.getTransition();
 935				this.pendingTransition = new TransitionInfo(t, lastScene, newScene);
 936				t.onEnter();
 937				t.setup(lastScene, newScene);
 938				return true;
 939			}else{
 940				return this.doSceneChange(lastScene, newScene);
 941			}
 942//			 */
 943			//doSceneChange(oldScene, newScene);
 944		}else{
 945			logger.debug("Couldnt change scene -> Change is locked from another scene change.");
 946			return false;
 947		}
 948	}
 949	
 950	
 951	/**
 952	 * Does the scene change after the transition (if existing) is completed.
 953	 * @param oldScene the old scene
 954	 * @param newScene the new scene
 955	 */
 956	private boolean doSceneChange(Iscene oldScene, Iscene newScene){
 957		if (sceneChangeLocked && !inDoSceneChange){
 958			inDoSceneChange = true;
 959			
 960			//Maybe show loading progress for newScenne.Init first?
 961			oldScene.onLeave();
 962			
 963			//Initialize new Scene
 964			newScene.onEnter();
 965
 966			//Enable input Processors previously registered with that scene
 967			this.getInputManager().enableGlobalInputProcessors(newScene);
 968
 969			//Check which cursors are active and clone their last evt as INPUT_DETECTED
 970			//so the scene doesent get INPUT_UPDATED without the start events
 971			this.sendStartedEvents(newScene); 
 972
 973			//Set new current scene
 974			this.currentScene = newScene;
 975			
 976			//FIXME TEST -> Make it possible to destroy scenes after a transition
 977			//(During a transition the old scene cant be removed or destroyed because
 978			//its still the current scene!)
 979			if (pendingTransition != null){
 980				if (pendingTransition.destroyLastSceneAfterTransition){
 981					logger.debug("Destroying scene: " + pendingTransition.lastScene.getName() + " after the transition.");
 982					pendingTransition.lastScene.destroy();
 983				}
 984			}
 985
 986			if (!this.sceneChangedListeners.isEmpty()){
 987				this.fireSceneChangeEvent(new SceneChangeEvent(this, oldScene, newScene));
 988			}
 989			logger.debug("Scene changed from: '" + oldScene + "' to: '" + newScene + "'");
 990			sceneChangeLocked = false;
 991			
 992			inDoSceneChange = false;
 993			return true;
 994		}else{
 995			return false;
 996		}
 997	}
 998
 999	
1000	
1001	/**
1002	 * Changes the scene to the specified scene.
1003	 * <p>NOTE: This is not threadsafe while using OpenGL mode. If in openGL mode make,
1004	 * sure to call this only from the same thread. If running in a different thread,
1005	 * execute the scene change using the <code>invokeLater(Runnable runnable)</code> method 
1006	 * of the MTApplication instance!
1007	 * <p>NOTE: If the scene is not already added to the application by invoking <code>addScene()</code>, the scene
1008	 * is automatically added to the mtapplication.
1009	 * 
1010	 * @param newScene the new scene
1011	 */
1012	public synchronized boolean changeScene(Iscene newScene){
1013		if (!this.sceneList.contains(newScene)){
1014			this.addScene(newScene);
1015		}
1016		return this.initiateSceneChange(this.getCurrentScene(), newScene);
1017	}
1018
1019	
1020	/**
1021	 * Checks which cursors are active during the scene change and
1022	 * sends input_ended events of the active cursors to last scene's global input processors 
1023	 * so actions in the last scene can be completed correctly.
1024	 * This means that one cursor can have more than one input_ended and input_started event
1025	 * in its event list!
1026	 * 
1027	 * @param lastScene the last scene
1028	 * @param newScene the new scene
1029	 */
1030	private void sendEndedEvents(Iscene lastScene){
1031		logger.debug("Sending INPUT_ENDED events to the last scene, Active motions: " + ActiveCursorPool.getInstance().getActiveCursorCount());
1032		InputCursor[] activeCursors = ActiveCursorPool.getInstance().getActiveCursors();
1033        for (InputCursor inputCursor : activeCursors) {
1034            if (inputCursor.getCurrentEvent() != null) {
1035                AbstractCursorInputEvt lastEvt = inputCursor.getCurrentEvent();
1036                if (lastEvt.getId() != AbstractCursorInputEvt.INPUT_ENDED) {
1037                    try {
1038                        AbstractCursorInputEvt endedEvt = (AbstractCursorInputEvt) lastEvt.clone();
1039                        endedEvt.setId(AbstractCursorInputEvt.INPUT_ENDED);
1040                        endedEvt.onFired();
1041
1042                        this.sendEvtToSceneProcessors(lastScene, endedEvt);
1043                        logger.debug("Sending INPUT_ENDED evt to scene: " + lastScene.getName() + " Cursor: " + endedEvt.getCursor());
1044                    } catch (CloneNotSupportedException e) {
1045                        e.printStackTrace();
1046                    }
1047                }
1048            }
1049        }
1050	}
1051	
1052	
1053	/**
1054	 * Checks which cursors are active during the scene change and
1055	 * sends input_started to the new scene's global input processors so actions in the
1056	 * last scene can be completed correctly.
1057	 * This means that one cursor can have more than one input_ended and input_started event
1058	 * in its event list!
1059	 * 
1060	 * @param lastScene the last scene
1061	 * @param newScene the new scene
1062	 */
1063	private void sendStartedEvents(Iscene newScene){
1064		logger.debug("Sending INPUT_DETECTED events to the new scene, Active motions: " + ActiveCursorPool.getInstance().getActiveCursorCount());
1065		InputCursor[] activeCursors = ActiveCursorPool.getInstance().getActiveCursors();
1066        for (InputCursor inputCursor : activeCursors) {
1067            if (inputCursor.getCurrentEvent() != null) {
1068                //PROBLEM: if in lastscene last event in cursor was input_started enqueued
1069                //but not added to cursor yet,
1070                //shall we send it again in new scene? -> will input_started be sent twice?
1071                //- what if input started was enqueued during transition and not sent to any scene
1072                AbstractCursorInputEvt lastEvt = inputCursor.getCurrentEvent();
1073                /*
1074                    if (//lastEvt.getId() != AbstractCursorInputEvt.INPUT_DETECTED
1075                            true
1076                        ){
1077                    */
1078                try {
1079                    AbstractCursorInputEvt startedEvt = (AbstractCursorInputEvt) lastEvt.clone();
1080                    startedEvt.setId(AbstractCursorInputEvt.INPUT_STARTED);
1081                    startedEvt.onFired();
1082
1083                    this.sendEvtToSceneProcessors(newScene, startedEvt);
1084                    logger.debug("Sending INPUT_DETECTED evt to scene: " + newScene.getName() + " Cursor: " + startedEvt.getCursor());
1085                } catch (CloneNotSupportedException e) {
1086                    e.printStackTrace();
1087                }
1088//				}
1089            }
1090        }
1091	}
1092	
1093	
1094	/**
1095	 * Send evt to scene processors.
1096	 * 
1097	 * @param scene the scene
1098	 * @param evtToFire the evt to fire
1099	 */
1100	private void sendEvtToSceneProcessors(Iscene scene, AbstractCursorInputEvt evtToFire){
1101		AbstractGlobalInputProcessor[] sceneInputProcessors = this.getInputManager().getGlobalInputProcessors(scene);
1102        for (AbstractGlobalInputProcessor a : sceneInputProcessors) {
1103            //Hack, because processInputEvt() is disabled at this moment! -> not anymore..
1104//			a.processInputEvtImpl(evtToFire);
1105            a.processInputEvent(evtToFire);
1106        }
1107	}
1108	
1109	/**
1110	 * Gets the currently active scene.
1111	 * 
1112	 * @return the current scene
1113	 */
1114	public Iscene getCurrentScene(){
1115		return currentScene;
1116	}
1117	
1118	/*
1119	public void drawCurrentScene(){
1120		getCurrentScene().draw();
1121	}
1122	public void updateCurrentScene(long timeDelta){
1123		getCurrentScene().update(timeDelta);
1124	}
1125	*/
1126
1127	/**
1128	 * Adds the scene to the list of scenes. 
1129	 * Also changes to that scene if it is the first one to be added.
1130	 * 
1131	 * @param scene the scene
1132	 */
1133	public void addScene(Iscene scene){
1134		if (this.getSceneCount() == 0){
1135			scene.onEnter();
1136			this.currentScene = scene;
1137			this.getInputManager().enableGlobalInputProcessors(scene);
1138			this.fireSceneChangeEvent(new SceneChangeEvent(this, this.currentScene, this.currentScene));
1139		}
1140		if (!sceneList.contains(scene))
1141			sceneList.add(scene);
1142	}
1143	
1144	
1145	/**
1146	 * Adds all scenes.
1147	 * 
1148	 * @param scenes the scenes
1149	 */
1150	public void addAll(Iscene[] scenes){
1151//		if (this.getSceneCount() == 0 && scenes[0] != null){
1152//			this.currentScene = scenes[0];
1153//		}
1154        for (Iscene scene : scenes) {
1155            //			sceneList.add(scene);
1156            this.addScene(scene);
1157        }
1158	}
1159	
1160	/**
1161	 * Removes the scene from the list of scenes. Fails if the scene is the currently active scene.
1162	 * If the scene isnt going to be used anymore, calling the scene's destroy() method is the better choice
1163	 * than the removeScene method alone.
1164	 * 
1165	 * @param scene the scene
1166	 */
1167	public boolean removeScene(Iscene scene){
1168		if (sceneList.contains(scene)){
1169			if (scene.equals(this.currentScene)){
1170				logger.warn("Cant remove the scene if it is the currently active scene! (" + scene + ")");
1171				return false;
1172			}else{
1173				sceneList.remove(scene);
1174				return true;
1175			}
1176		}
1177		else{
1178			return false;	
1179		}
1180		
1181//		return true;
1182	}
1183	
1184	/**
1185	 * Destroy scene after transition. Workaround so that if a scene's destroy() method is called
1186	 * but the scene is in a transition (cant be removed then) we call destroy on the scene after
1187	 * the transition.
1188	 * Only has an impact if there is a pending transition with the specified scene as the last scene.
1189	 * 
1190	 * @param scene the scene
1191	 */
1192	public void destroySceneAfterTransition(Iscene scene){
1193		if (pendingTransition != null && pendingTransition.lastScene.equals(scene)){
1194			pendingTransition.destroyLastSceneAfterTransition = true;
1195		}
1196	}
1197	
1198	/**
1199	 * Gets the registered scenes.
1200	 * 
1201	 * @return the scenes
1202	 */
1203	public Iscene[] getScenes(){
1204		return sceneList.toArray(new Iscene[sceneList.size()]);
1205	}
1206	
1207	/**
1208	 * Gets the scene by name.
1209	 * 
1210	 * @param name the name
1211	 * 
1212	 * @return the scene
1213	 */
1214	public Iscene getScene(String name){
1215		Iscene returnScene = null;
1216		for(Iscene scene : sceneList){
1217			if (scene.getName().equals(name))
1218				returnScene = scene; 
1219		}
1220		return returnScene;
1221	}
1222	
1223	
1224	/**
1225	 * Gets the scene count.
1226	 * 
1227	 * @return the scene count
1228	 */
1229	public int getSceneCount(){
1230		return sceneList.size();
1231	}
1232	
1233
1234	/**
1235	 * Gets the input manager.
1236	 * 
1237	 * @return the input manager
1238	 */
1239	public InputManager getInputManager() {
1240		return inputManager;
1241	}
1242
1243	/**
1244	 * Sets the input manager.
1245	 * 
1246	 * @param inputManager the new input manager
1247	 */
1248	public void setInputManager(InputManager inputManager) {
1249		this.inputManager = inputManager;
1250	}
1251	
1252
1253/////////////////////////	
1254	/**
1255	 * Fire scene change event.
1256	 * 
1257	 * @param sc the sc
1258	 */
1259	protected void fireSceneChangeEvent(SceneChangeEvent sc) {
1260		for (ISceneChangeListener listener : sceneChangedListeners){
1261			listener.processSceneChangeEvent(sc);
1262		}
1263	}
1264
1265	/**
1266	 * Adds a scene change listener.
1267	 * 
1268	 * @param listener the listener
1269	 */
1270	public synchronized void addSceneChangeListener(ISceneChangeListener listener){
1271		if (!this.sceneChangedListeners.contains(listener)){
1272			sceneChangedListeners.add(listener);
1273		}
1274		
1275	}
1276	
1277	/**
1278	 * Removes the scene change listener.
1279	 * 
1280	 * @param listener the listener
1281	 */
1282	public synchronized void removeSceneChangeListener(ISceneChangeListener listener){
1283		if (sceneChangedListeners.contains(listener)){
1284			sceneChangedListeners.remove(listener);
1285		}
1286	}
1287	
1288	/**
1289	 * Gets the scene change listeners.
1290	 * 
1291	 * @return the scene change listeners
1292	 */
1293	public synchronized ISceneChangeListener[] getSceneChangeListener(){
1294		return sceneChangedListeners.toArray(new ISceneChangeListener[this.sceneChangedListeners.size()]);
1295	}
1296/////////////////////////////////	
1297
1298
1299	/**
1300	 * Gets the class name.
1301	 * 
1302	 * @author C.Ruff
1303	 */
1304	public static class CurrentClassGetter extends SecurityManager {
1305		/**
1306		 * Gets the class name.
1307		 * 
1308		 * @return the class name
1309		 */
1310		public String getClassName() {
1311			return getClassContext()[2].getName(); //FIXME is this reliable to always work?
1312		}
1313	}
1314
1315
1316	public CSSStyleManager getCssStyleManager() {
1317		return this.cssStyleManager;
1318	}
1319
1320
1321}