Package org.mt4j.components

Source Code of org.mt4j.components.MTComponent

/***********************************************************************
* mt4j Copyright (c) 2008 - 2009 C.Ruff, Fraunhofer-Gesellschaft All rights reserved.
*   This program is free software: you can redistribute it and/or modify
*   it under the terms of the GNU General Public License as published by
*   the Free Software Foundation, either version 3 of the License, or
*   (at your option) any later version.
*
*   This program is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*   GNU General Public License for more details.
*
*   You should have received a copy of the GNU General Public License
*   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
***********************************************************************/
package org.mt4j.components;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.media.opengl.GL;

import org.apache.log4j.ConsoleAppender;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.apache.log4j.SimpleLayout;
import org.mt4j.components.PickResult.PickEntry;
import org.mt4j.components.bounds.IBoundingShape;
import org.mt4j.components.clipping.Clip;
import org.mt4j.components.interfaces.IMTComponent3D;
import org.mt4j.components.interfaces.IMTController;
import org.mt4j.input.ComponentInputProcessorSupport;
import org.mt4j.input.GestureEventSupport;
import org.mt4j.input.IMTInputEventListener;
import org.mt4j.input.inputData.InputCursor;
import org.mt4j.input.inputData.MTInputEvent;
import org.mt4j.input.inputProcessors.IGestureEventListener;
import org.mt4j.input.inputProcessors.IInputProcessor;
import org.mt4j.input.inputProcessors.MTGestureEvent;
import org.mt4j.input.inputProcessors.componentProcessors.AbstractComponentProcessor;
import org.mt4j.util.MT4jSettings;
import org.mt4j.util.camera.IFrustum;
import org.mt4j.util.camera.Icamera;
import org.mt4j.util.math.Matrix;
import org.mt4j.util.math.Ray;
import org.mt4j.util.math.Tools3D;
import org.mt4j.util.math.Vector3D;

import processing.core.PApplet;
import processing.core.PGraphics;
import processing.core.PGraphics3D;
import processing.opengl.PGraphicsOpenGL;

/**
* This is the base class for all MT4j scene graph nodes. It provides basic methods
* for adding and managing child nodes/components. It also allows for changing the components position and
* orientation in space. Picking those components with a picking ray is also supported, if intersection
* testing is properly implemented by extending subclasses.
* <p>
* This base class has no visible representation an thus can be used
* as a group container node for other scene graph components.
*
* @author Christopher Ruff
*/
public class MTComponent implements IMTComponent3D, IMTInputEventListener, IGestureEventListener{
  /** The Constant logger. */
  private static final Logger logger = Logger.getLogger(MTComponent.class.getName());
  static{
//    logger.setLevel(Level.ERROR);
    logger.setLevel(Level.WARN);
//    logger.setLevel(Level.DEBUG);
    SimpleLayout l = new SimpleLayout();
    ConsoleAppender ca = new ConsoleAppender(l);
    logger.addAppender(ca);
  }
 
  /** The ID. */
  private int ID;
 
  /** The current id. */
  private static int currentID;
 
  /** The renderer. */
  private PApplet renderer;
 
  /** The name. */
  private String name;
 
  /** The visible. */
  private boolean visible;
 
  /** The enabled. */
  private boolean enabled;
 
  /** The pickable. */
  private boolean pickable;
 
  /** The drawn on top. */
  private boolean drawnOnTop;
 
  /** The parent. */
  private MTComponent parent;
 
  /** The child components. */
  private List<MTComponent> childComponents;
 
//  /** The custom view port. */
//  private ViewportSetting customViewPort;
// 
//  /** The default view port setting. */
//  private ViewportSetting defaultViewPortSetting;
 
  /** The composite. */
  private boolean composite;
 
  //  Matrix Stuff
  /** The local matrix. */
  private Matrix localMatrix;
 
  /** The local inverse matrix. */
  private Matrix localInverseMatrix;
 
  /** The local to Global matrix. */
  private Matrix globalMatrix;
 
  /** The Global to local matrix. */
  private Matrix globalToLocalMatrix;
 
  /** The local to Global matrix dirty. */
  private boolean globalMatrixDirty;
 
  /** The Global to local matrix dirty. */
  private boolean globalInverseMatrixDirty;
 
  /** The pgraphics3 d. */
  private PGraphics3D pgraphics3D;
 
  /** The controller. */
  private IMTController controller;
 
  //FIXME EXPERIMENTAL
  /** The light. */
  private MTLight light;
 
//  private PropertyChangeSupport propertyChangeSupport;
  /** The state change support. */
  private StateChangeSupport stateChangeSupport;
 
  /** The _translation computation. */
  private Matrix[] _translationComputation;
 
  /** The _x rotation computation. */
  private Matrix[] _xRotationComputation;
 
  /** The _y rotation computation. */
  private Matrix[] _yRotationComputation;
 
  /** The _z rotation computation. */
  private Matrix[] _zRotationComputation;
 
  /** The _scaling computation. */
  private Matrix[] _scalingComputation;
 
  /** The input processors support. */
  private ComponentInputProcessorSupport inputProcessorsSupport;
 
  /** The gesture evt support. */
  private GestureEventSupport gestureEvtSupport;
 
  /** The allowed gestures. */
  private List<Class<? extends IInputProcessor>> allowedGestures;
 
  /** The attached camera. */
  private Icamera attachedCamera;
 
  /** The viewing camera. */
  private Icamera viewingCamera;
 
  /** The input listeners. */
  private List<IMTInputEventListener> inputListeners;
 
  /** The user data. */
  private Map<Object, Object> userData;
 
  private int inversePrecisionErrors;
  private int orthogonalityErrors;
  private static final int invPrecisionThreshold = 1000;
  private static final int reOrthogonalizeThreshold = 1500;
 
  /**
   * Creates a new component. The component has no initial visual representation.
   *
   * @param pApplet the applet
   */
  public MTComponent(PApplet pApplet){
    this(pApplet , "unnamed component", null);
  }
 
  /**
   * Creates a new component. The component has no visual representation.
   *
   * @param pApplet the applet
   * @param name the name
   */
  public MTComponent(PApplet pApplet, String name){
    this(pApplet , name, null);
  }
 
 
  /**
   * Creates a new component. The component has no visual representation.
   *
   * @param pApplet the applet
   * @param attachedCamera the camera to view this and this components children with
   */
  public MTComponent(PApplet pApplet, Icamera attachedCamera){
    this(pApplet , "unnamed component", attachedCamera);
  }
 
  /**
   * Creates a new component. The component has no visual representation.
   *
   * @param pApplet the applet
   * @param name the name of the component
   * @param attachedCamera a camera to view this and this components children with
   */
  public MTComponent(PApplet pApplet, String name, Icamera attachedCamera){
    synchronized (this) {
      this.ID = currentID++;
    }
    //Defaults
    this.renderer = pApplet;
    this.visible = true;
    this.enabled = true;
    this.pickable = true;
    this.drawnOnTop = false;
    this.name = name;
    this.composite = false;
   
    this.childComponents = new ArrayList<MTComponent>();

    //      //Default viewport, can be changed in subclass //FIXME REMOVE?
    //      this.defaultViewPortSetting   = new ViewportSetting(0, 0, this.getRenderer().width ,this.getRenderer().height);
    //      this.customViewPort       = null;

    //(Cached) Matrices of this component
    this.localMatrix     = new Matrix();
    this.localInverseMatrix  = new Matrix();
    this.globalMatrix    = new Matrix();
    this.globalToLocalMatrix= new Matrix();

    this.globalMatrixDirty = true;
    this.globalInverseMatrixDirty = true;

    //This class should only be used with a renderer derived from pgraphics3D!
    this.pgraphics3D = (PGraphics3D)pApplet.g;

    //FIXME EXPERIMENTAL
    light = null;

    //      propertyChangeSupport   = new PropertyChangeSupport(this);

    //      stateChangeSupport     = new StateChangeSupport(this);

    _translationComputation   = new Matrix[]{new Matrix(), new Matrix()};
    _xRotationComputation     = new Matrix[]{new Matrix(), new Matrix()};
    _yRotationComputation     = new Matrix[]{new Matrix(), new Matrix()};
    _zRotationComputation     = new Matrix[]{new Matrix(), new Matrix()};
    _scalingComputation     = new Matrix[]{new Matrix(), new Matrix()};

    allowedGestures = new ArrayList<Class<? extends IInputProcessor>>(5);

    //TODO lazily instantiate gesturehandler/arraylist so that graphicobjects arent expensive at creation?

    this.inputListeners = new ArrayList<IMTInputEventListener>(3);

    //Delegate input processing/gesture detection to a special handler
    this.inputProcessorsSupport = new ComponentInputProcessorSupport(pApplet, this);
    //Let the input processor support class listen to the component's input events
    this.addInputListener(inputProcessorsSupport);

    this.gestureEvtSupport = new GestureEventSupport();

    this.attachedCamera = attachedCamera;
    this.viewingCamera = attachedCamera;

    //FIXME TEST
    this.boundsGlobalVerticesDirty = true;

    this.inversePrecisionErrors = 0;
    this.orthogonalityErrors  = 0;
  }

 
  //TODO
  // BOUNDS STUFF ///////////////////////////////////
  /** The bounds */
  private IBoundingShape bounds;
 
  /** The bounds global vertices dirty. */
  private boolean boundsGlobalVerticesDirty;
 
  //TODO REMOVE THESE DEPRECATED METHODS IN THE NEXT RELEASE!
  /**
   * Sets the bounding shape.
   *
   * @param boundingShape the new bounding shape
   * @deprecated renamed to <code>setBounds</code>
   */
  public void setBoundingShape(IBoundingShape boundingShape){
    this.bounds = boundingShape;
    this.setBoundsGlobalDirty(true);
 
  /**
   * Gets the bounding shape.
   *
   * @return the bounding shape
   * @deprecated renamed to <code>getBounds</code>
   */
  public IBoundingShape getBoundingShape(){
    return this.bounds;
  }
  /**
   * Checks if is bounding shape set.
   * @return true, if is bounding shape set
   * @deprecated renamed to <code>hasBounds</code>
   */
  public boolean isBoundingShapeSet(){
    return this.bounds != null;
  }
 
  /**
   * Sets the bounding shape.
   * @param boundingShape the new bounding shape
   */
  public void setBounds(IBoundingShape boundingShape){
    this.bounds = boundingShape;
    this.setBoundsGlobalDirty(true);
 
 
  /**
   * Gets the bounding shape.
   * @return the bounding shape
   */
  public IBoundingShape getBounds(){
    return this.bounds;
  }
 
  /**
   * Checks if is bounding shape set.
   * @return true, if is bounding shape set
   */
  public boolean hasBounds(){
    return this.bounds != null;
  }
 
  //TODO REMOVE?
  /**
   * Sets the bounds global vertices dirty.
   *
   * @param boundsWorldVerticesDirty the new bounds world vertices dirty
   */
  private void setBoundsGlobalDirty(boolean boundsWorldVerticesDirty) {
    this.boundsGlobalVerticesDirty = boundsWorldVerticesDirty;
    if (this.hasBounds()){
      this.getBounds().setGlobalBoundsChanged();
    }
  }
  // BOUNDS STUFF ////////////////////////////////
 
 
 
  // INPUT LISTENER STUF ////
  /**
   * Adds an input listener to this component. The listener will be informed if
   * this component recieves an input event.
   *
   * @param inputListener the input listener
   */
  public synchronized void addInputListener(IMTInputEventListener inputListener){
    if (inputListener instanceof AbstractComponentProcessor) {
      logger.warn("An abstract component processor (" + inputListener + ") was added to component '" + this + "' using addInputListener(). You probably need to use the registerInputProcessor() method instead!");
    }
    this.inputListeners.add(inputListener);
  }
 
  /**
   * Removes the input listener.
   * @param inputListener the input listener
   */
  public synchronized void removeInputListener(IMTInputEventListener inputListener){
    this.inputListeners.remove(inputListener);
  }
 
  /**
   * Gets the input listeners.
   * @return the input listeners
   */
  public IMTInputEventListener[] getInputListeners(){
    return this.inputListeners.toArray(new IMTInputEventListener[this.inputListeners.size()]);
  }
 
  /**
   * Fire input event.
   *
   * @param iEvt the i evt
   */
  protected boolean fireInputEvent(MTInputEvent iEvt){
    boolean handled = false; //TODO REALLY IMPLEMENT, CHECK LISTENERS WHAT THEY RETURN, PROPAGET ETC!
    for (IMTInputEventListener listener : inputListeners){
      boolean handledListener = listener.processInputEvent(iEvt);
      if (!handled && handledListener){
        handled = true;
      }
    }
    return handled;
  }
  // INPUT LISTENER STUF ////
 
/// CAMERA SETTINGS ///////////////////////////////////// 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent3D#getViewingCamera()
   */
  public Icamera getViewingCamera(){
    if (this.viewingCamera != null){
      return this.viewingCamera;
    }else{
      //Search up the component tree for a attached camera
      //automatically sets this viewcamera to the attached camera if found
      this.searchViewingCamera();
      return this.viewingCamera;
    }
  }
 
  /**
   * Search viewing camera.
   */
  private void searchViewingCamera(){
     this.viewingCamera = this.searchViewingCamRecur(this);
  }
 
  /**
   * Search viewing cam recur.
   *
   * @param current the current
   * @return the icamera
   */
  private Icamera searchViewingCamRecur(MTComponent current){
    if (current.attachedCamera != null){
      return current.attachedCamera;
    }else{
      if (current.getParent() != null){
        return searchViewingCamRecur(current.getParent());
      }else{
        return null;
      }
    }
  }
 
  /**
   * Propagate cam change.
   *
   * @param cam the cam
   */
  private void propagateCamChange(Icamera cam){
    this.propagateCamChangeRecur(this, cam);
  }
 
  /**
   * Propagate cam change recur.
   *
   * @param current the current
   * @param cam the cam
   */
  private void propagateCamChangeRecur(MTComponent current, Icamera cam){
    //Only propagate further if current has no attached cam of its own
    //or it is the same as the propagated one
    //-> dont overwrite other attached cams down the tree!
    if (current.getAttachedCamera() == null
            ||
      (current.getAttachedCamera() != null
            &&
      (current.getAttachedCamera().equals(cam)))
    ){
      current.viewingCamera = cam;
      for (MTComponent child: current.getChildList()){
        child.propagateCamChange(cam);
      }
    }
  }
 
  /**
   * Gets the camera attached to this component or null if it doesent
   * have one.
   *
   * @return the attached camera
   */
  public Icamera getAttachedCamera() {
    return attachedCamera;
  }
 
  /**
   * Attaches a camera to this component.
   * This component and all its children will be viewed
   * through the specified camera.
   *
   * @param attachedCamera the attached camera
   */
  public void attachCamera(Icamera attachedCamera) {
    this.attachedCamera = attachedCamera;
    this.viewingCamera = attachedCamera;
    this.propagateCamChange(attachedCamera);
  }
  /// CAMERA SETTINGS /////////////////////////////////////
 
 
  // INPUT HANDLER ////////////////////////////////////////
  /**
   * Registers an component input processor with this component. Input processors are used to process
   * the input events a component recieves by checking them for special patterns and conditions and
   * firing gesture events back to the component.
   * To recognize a multi-touch drag gesture on a component for example, we would register a
   * <code>DragProcessor</code> object with this component.
   *
   * @param inputProcessor the input processor
   */
  public void registerInputProcessor(AbstractComponentProcessor inputProcessor) {
    AbstractComponentProcessor[] processors = inputProcessorsSupport.getInputProcessors();
    for (int i = 0; i < processors.length; i++) {
      AbstractComponentProcessor abstractComponentProcessor = processors[i];
      if (inputProcessor.getClass() == abstractComponentProcessor.getClass()){
        logger.warn("Warning: The same type of input processor (" + inputProcessor.getName() + ") is already registered at component: " + this );
      }
    }
    inputProcessorsSupport.registerInputProcessor(inputProcessor);
    this.setGestureAllowance(inputProcessor.getClass(), true); //Enable by default
  }
 
  /**
   * Unregister a component input processor.
   * @param inputProcessor the input processor
   */
  public void unregisterInputProcessor(AbstractComponentProcessor inputProcessor) {
    inputProcessorsSupport.unregisterInputProcessor(inputProcessor);
  }
 
  /**
   * Unregister all previously registered component input processors.
   */
  public void unregisterAllInputProcessors() {
    AbstractComponentProcessor[] ps = inputProcessorsSupport.getInputProcessors();
    for (int i = 0; i < ps.length; i++) {
      AbstractComponentProcessor p = ps[i];
      inputProcessorsSupport.unregisterInputProcessor(p);
    }
  }
 
  /**
   * Gets the component input processors.
   * @return the input processors
   */
  public AbstractComponentProcessor[] getInputProcessors() {
    return inputProcessorsSupport.getInputProcessors();
  }
  // INPUT HANDLER ////////////////////////////////////////

 
  // GESTURE LISTENER EVENT SUPPORT ///////////////////////////////////////
  /**
   * Adds a gesture listener to this component. The specified gesture listener's
   * <code>processGestureEvent(..)</code> method will be called when a gesture event
   * is processed by this component. The <code>IInputProcessor</code> paramter type specifies the source of
   * the gesture event we are interested in. So to listen to drag events only for example, we would specify
   * the <code>DragProcessor.class</code> as the first parameter.
   *
   * @param gestureEvtSender the gesture evt sender
   * @param listener the listener
   */
  public void addGestureListener(Class<? extends IInputProcessor> gestureEvtSender, IGestureEventListener listener){
    this.gestureEvtSupport.addGestureEvtListener(gestureEvtSender, listener);
  }
 
  /**
   * Removes the gesture event listener.
   * @param gestureEvtSender the gesture evt sender
   * @param listener the listener
   */
  public void removeGestureEventListener(Class<? extends IInputProcessor> gestureEvtSender, IGestureEventListener listener) {
    gestureEvtSupport.removeGestureEventListener(gestureEvtSender, listener);
  }
 
  /**
   * Removes the all gesture event listeners.
   */
  public void removeAllGestureEventListeners() {
    this.gestureEvtSupport.clearListeners();
  }
 
  /**
   * Removes the all gesture event listeners who listen to the specified input processor.
   * @param gestureEvtSender the gesture evt sender
   */
  public void removeAllGestureEventListeners(Class<? extends IInputProcessor> gestureEvtSender) {
    IGestureEventListener[] l = this.getGestureListeners();
      for (int j = 0; j < l.length; j++) {
      IGestureEventListener gestureEventListener = l[j];
      this.removeGestureEventListener(gestureEvtSender, gestureEventListener);
    }
  }
 
  /**
   * Returns the gesture listeners.
   * @return the gesture listeners
   */
  public final IGestureEventListener[] getGestureListeners() {
    return gestureEvtSupport.getListeners();
  }
  // GESTURE LISTENER EVENT SUPPORT ///////////////////////////////////////


 
//Property Change Support ////////////////////
  /*
  //TODO use? remove?
  public void addPropertyChangeListener(PropertyChangeListener listener){
    this.propertyChangeSupport.addPropertyChangeListener( listener );
  }

  public void removePropertyChangeListener(PropertyChangeListener listener){
    this.propertyChangeSupport.removePropertyChangeListener( listener );
  }

 
  protected void firePropertyChange(PropertyChangeEvent arg0) {
    propertyChangeSupport.firePropertyChange(arg0);
  }

  protected void firePropertyChange(String arg0, boolean arg1, boolean arg2) {
    propertyChangeSupport.firePropertyChange(arg0, arg1, arg2);
  }
  protected void firePropertyChange(String arg0, int arg1, int arg2) {
    propertyChangeSupport.firePropertyChange(arg0, arg1, arg2);
  }
  protected void firePropertyChange(String arg0, Object arg1, Object arg2) {
    propertyChangeSupport.firePropertyChange(arg0, arg1, arg2);
  }
 
  static final String PROPERTY_NAME_STRING = "name";
  */
//  Propery Change Support ////////////////////
 


  ////STATE CHANGE SUPPORT /////
  /**
     * Checks if the map is null and then lazily initializes it.
     */
    private void lazyInitStateChangeSupport(){
      if (stateChangeSupport == null){
        stateChangeSupport = new StateChangeSupport(this);
      }
    }
   
  /**
   * Adds the state change listener.
   *
   * @param state the state
   * @param listener the listener
   */
  public void addStateChangeListener(StateChange state, StateChangeListener listener) {
    this.lazyInitStateChangeSupport();
    stateChangeSupport.addStateChangeListener(state, listener);
  }
 

  /**
   * Removes the state change listener.
   *
   * @param state the state
   * @param listener the listener
   */
  public void removeStateChangeListener(StateChange state, StateChangeListener listener) {
    if (stateChangeSupport != null){
      stateChangeSupport.removeStateChangeListener(state, listener);     
    }
  }
 
  /**
   * Fire state change.
   *
   * @param evt the evt
   */
  protected void fireStateChange(StateChangeEvent evt) {
    this.lazyInitStateChangeSupport();
    stateChangeSupport.fireStateChange(evt);
  }

  /**
   * Fire state change.
   *
   * @param state the state
   */
  protected void fireStateChange(StateChange state) {
    this.lazyInitStateChangeSupport();
    stateChangeSupport.fireStateChange(state);
  }
/////STATE CHANGE SUPPORT /////

  /**
   * <li>Removes this component from its parent.
   * <li>Calls <code>destroyComponent</code> on this component which
   * can be used to free resources that the component used.
   * <li>Recursively calls destroy on alls its child components
   */
  public void destroy(){
//    System.out.println(this + " -> DESTROY() -> (MTComponent)");
   
//    List<MTComponent> children = this.getChildList();
    //We save the children in an array because the childList might get modified
    //during destruction and we wont call destroy on all children then!
    MTComponent[] childArr = this.getChildren();
   
    if (this.getParent() != null){
      this.removeFromParent(); //really do this?
      this.fireStateChange(StateChange.REMOVED_FROM_PARENT);
    }
    this.destroyComponent();
    this.fireStateChange(StateChange.COMPONENT_DESTROYED);
   
//    /*
    if (userData != null){
      this.userData.clear()
    }
    this.unregisterAllInputProcessors();
   
//    if (this.stateChangeSupport != null){
//      this.stateChangeSupport = null;
//    }
//    if (this.gestureEvtSupport != null){
//      this.gestureEvtSupport = null;
//    }
//    */
   
    for (int i = 0; i < childArr.length; i++) {
      childArr[i].destroy();
    }
  }
 
  /**
   * <br>Override this to clean up resources when destroying a component.
   * This method gets called by the <code>destroy</code> method. So you shouldnt
   * invoke this method directly.
   */
  protected void destroyComponent(){   }

 
  /**
   * Applies (multiplies) this component's local matrix to processings current matrix.
   */
  protected void applyLocalMatrix(){
    this.applyMatrixToProcessingModelView(localMatrix);
  }
 
  /**
   * Applies (multiplies) the matrix to processings current matrix.
   * Developer note: Processings <code>applyMatrix</code> is saver than <code>g.modelview.apply</code>(?)
   * because it also calculates a new inverse. (important for lightning calculations?)
   *
   * @param m the m
   */
  private void applyMatrixToProcessingModelView(Matrix m){
//This is slower because it also calcs the inverse..
//    pgraphics3D.applyMatrix(m.m00, m.m01, m.m02,  m.m03,
//        m.m10, m.m11, m.m12,  m.m13,
//        m.m20, m.m21, m.m22,  m.m23,
//        m.m30, m.m31, m.m32,  m.m33);
    pgraphics3D.modelview.apply(
        m.m00, m.m01, m.m02,  m.m03,
        m.m10, m.m11, m.m12,  m.m13,
        m.m20, m.m21, m.m22,  m.m23,
        m.m30, m.m31, m.m32,  m.m33
    );
    /*
    Matrix mInv = localInverseMatrix;
    pgraphics3D.modelviewInv.preApply(
        mInv.m00, mInv.m01, mInv.m02,  mInv.m03,
        mInv.m10, mInv.m11, mInv.m12,  mInv.m13,
        mInv.m20, mInv.m21, mInv.m22,  mInv.m23,
        mInv.m30, mInv.m31, mInv.m32,  mInv.m33
    );
    */
  }
 
  //TODO REMOVE?
//  /**
//   * Checks if is matrices dirty.
//   *
//   * @return true, if is matrices dirty
//   */
//  public boolean isMatricesDirty(){
//    return (this.globalMatrixDirty || this.globalInverseMatrixDirty);
//  }
 
  /**
   * Informs the object (and its children), that its matrix - OR ONE OF ITS PARENT'S MATRIX - has been altered.
   * <br>Usually this shouldnt be called by the user himself.
   *
   * @param matricesDirty the matrices dirty
   */
  public void setMatricesDirty(boolean matricesDirty) {
//    System.out.println("Setting matrices dirty->" + matricesDirty + " on: "  + this.getName());
    if (matricesDirty == true){
      //FIXME BOUNDS TEST
      this.setBoundsGlobalDirty(true);
     
      //absolute matrix �ndert sich damit auch auch wenn dr�ber parents geadded werden!
      this.setGlobalMatrixDirty(true);
     
      this.setGlobalInverseMatrixDirty(true);
     
      //Also inform the children, so they know that parent changed
      this.propagateMatrixChange(true);
    }else{//baseMatrixDiry == false
      this.globalMatrixDirty = matricesDirty;
      this.globalInverseMatrixDirty = matricesDirty;
    }
  }
 
  /**
   * Inform the children of the matrix change.
   *
   * @param matrixDirty the matrix dirty
   */
  private void propagateMatrixChange(boolean matrixDirty){
//    System.out.println("Setting basematrix dirty on obj: " + this.getName());
    for (int i = 0; i < childComponents.size(); i++) {
      MTComponent object = childComponents.get(i);
      //TEST - only propagate unitil we get to a already dirty component
      //this should work because the dirty component should also have dirty children already
      //CAUTION: object can have for example a dirty global matrix and a clean global inverse matrix
      //so we check if both are dirty and only then dont propagate the dirty state
      //FIXME NOT WORKING WITH SVG EXAMPLEaaaaaaaaa - cause of composite?
//      if ((!object.isGlobalInverseMatrixDirty() || !object.isGlobalMatrixDirty())){
        object.setMatricesDirty(matrixDirty);
//      }
//      else{
//        System.out.println("Stopping matrix changed propagation at: " + object.getName() +  " because both its matrices are already dirty.");
//      }
    }
  }
 
  /**
   * Checks if Global matrix is dirty.
   *
   * @return true, if checks if is abs local to Global matrix dirty
   *
   * whether the cached  Global matrix is still valid
   */
  private boolean isGlobalMatrixDirty() {
    return globalMatrixDirty;
  }

  /**
   * Sets the Global matrix dirty.
   *
   * @param globalMatrixDirty the local to Global matrix dirty
   */
  private void setGlobalMatrixDirty(boolean globalMatrixDirty) {
    /*
    if (localToGlobalMatrixDirty){
      System.out.println(this.getName() + ": Setting global Matrix DIRTY!");
    }else{
      System.out.println(this.getName() + ": Setting global Matrix NOT dirty!");
    }
    */
    this.globalMatrixDirty = globalMatrixDirty;
  }
 
  /**
   * Checks if is global to local matrix dirty.
   *
   * @return true, if checks if is global to local matrix dirty
   *
   * whether the cached absolute inverse global matrix is still valid
   */
  private boolean isGlobalInverseMatrixDirty() {
    return globalInverseMatrixDirty;
  }
 
  /**
   * Sets the Global Inverse matrix dirty.
   *
   * @param dirty the dirty
   */
  private void setGlobalInverseMatrixDirty(boolean dirty) {
    /*
    if (dirty){
      System.out.println(this.getName() + ": Setting global inverse Matrix DIRTY!");
    }else{
      System.out.println(this.getName() + ": Setting global inverse Matrix NOT dirty!");
    }
    */
    this.globalInverseMatrixDirty = dirty;
  }
 
  /**
   * Gets the local basis matrix.
   * This is the matrix responsible for transforming this component relative to its parent.
   *
   * @return the local basis matrix
   *
   * The matrix describing the local coordinate space of this object.
   */
  public Matrix getLocalMatrix() {
    return localMatrix;
  }
 
  /**
   * Sets a matrix by which this component and its children will be transformed.
   * <br>Also calculates and sets the corresponding local inverse matrix. (expensive call!)
   *
   * @param localBasisMatrix the local basis matrix
   */
  public void setLocalMatrix(Matrix localBasisMatrix) {
    this.setLocalMatrixInternal(localBasisMatrix);
    try {
      //THIS OPERATION IS NOT CHEAP!
      this.setLocalInverseMatrixInternal(this.getLocalMatrix().invert());
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

  /**
   * Sets a matrix by which this component and its children will be transformed.
   * <br>This should only be called internally. The corresponding inverse matrix
   * has to be calculated and set also for the object to be consistent!
   * <br>This method doesent calculate the inverse matrix!
   *
   * @param localMatrix the local matrix
   */
  private void setLocalMatrixInternal(Matrix localMatrix) {
    this.localMatrix = localMatrix;
    this.setMatricesDirty(true);
  }
 
  /**
   * Gets the local inverse matrix.
   *
   * @return the local inverse matrix
   *
   * the local inverse transform matrix
   */ 
  public Matrix getLocalInverseMatrix() {
    return this.localInverseMatrix;
  }
 
  /**
   * Sets the local inverse matrix.
   *
   * @param localInverseMatrix the local inverse matrix
   */
  private void setLocalInverseMatrixInternal(Matrix localInverseMatrix) {
    this.localInverseMatrix = localInverseMatrix;
  }
 
 
  /**
   * Multiplies all transformation matrices of the
   * objects parents up the this object and returns it.
   * <br>This is so to speak the <b>"global matrix"</b> of the object.
   * This matrix can be used to transform points in the components local space
   * to the global space, the space where they actually appear in 3D space.
   *
   * @return the local to global matrix
   *
   * the absolute transformation (global) matrix of the object
   */
  public Matrix getGlobalMatrix(){
    Matrix resMatrix = this.globalMatrix;
    //Calculate the absolute local to global matrix only if necessary
    if (this.isGlobalMatrixDirty()){
//      System.out.println(this.getName() + "'s global matrix is dirty! calculate it:");
      resMatrix = new Matrix();
      this.getGlobalMatrixRecursive(this, resMatrix);
      //System.out.println("Applying Matrix of: '" + this.getName() + "' Matrix: " + this.getLocalBasisMatrix().toString());
      resMatrix.multLocal(this.getLocalMatrix());
     
      this.globalMatrix = resMatrix;
     
      this.setGlobalMatrixDirty(false);
    }
    //System.out.println(this.getName() + "'s global matrix is not dirty!");
    return resMatrix;
  }
 
 
  /**
   * Gets the abs matrix recursive.
   *
   * @param current the current
   * @param currentMatrix the current matrix
   *
   * @return the abs matrix recursive
   */
  private MTComponent getGlobalMatrixRecursive(MTComponent current, Matrix currentMatrix){
    //System.out.println("Processing: " + current.getName());
    if (current.getParent() != null){
      if (current.getParent().isGlobalMatrixDirty()){
        //System.out.println(">Parent not null: " + current.getParent().getName());
//        System.out.println(" Recursive loop - " + current.getParent().getName() + "'s global matrix IS dirty");
        MTComponent res = this.getGlobalMatrixRecursive(current.getParent(), currentMatrix);
        if (!res.getLocalMatrix().isIdentity()){
          currentMatrix.multLocal(res.getLocalMatrix());
          //We can set
//          System.out.println(" Recursive loop - setting " + res.getName() + " global matrix");
          res.globalMatrix = new Matrix(currentMatrix);
          res.setGlobalMatrixDirty(false);
        }
        //System.out.println("Applying Matrix of: '" + res.getName() + "' Matrix: " + res.getLocalBasisMatrix().toString());
      }else{
        //Currents global matrix isnt dirty -> apply the global matrix and stop recursion upwards
//        System.out.println(" Recursive loop - " + current.getParent().getName() + "'s global matrix is NOT dirty - stop recursion");
        Matrix parentLocalToGlobal = current.getParent().getGlobalMatrix();
        currentMatrix.multLocal(parentLocalToGlobal);
      }
    }else{
//      System.out.println(" Recursive loop - " + current.getName() + " has no parent - stop recursion and use its local as its global matrix");
      if (current.isGlobalMatrixDirty()){
        current.globalMatrix = new Matrix(current.getLocalMatrix());
        current.setGlobalMatrixDirty(false);
      }
    }
    return current;
  }
 
 
 
  /**
   * Returns the absolute inverse matrix (inverse of the global) which inverts all transforms made
   * from the parents down to this child.
   * This matrix can be used to transform a point in global space to the component's local object space (untransformed space).
   *
   * @return the absolute global to local matrix
   * , the absolute inverse transformation matrix of the object
   */
  public Matrix getGlobalInverseMatrix() {
    Matrix resMatrix = this.globalToLocalMatrix;
    //Calculate the absolute local to global matrix only if necessary
    if (this.isGlobalInverseMatrixDirty()){
//      System.out.println("Getting global inverse of: " + this.getName() + " -its dirty!");
      if (this.getParent()!= null){
        resMatrix = new Matrix(this.getLocalInverseMatrix());
        this.getGlobalInvMatrixRecursive(this.getParent(), resMatrix);
        this.globalToLocalMatrix = resMatrix;
      }else{
        //no parent -> Global inverse is local inverse
        this.globalToLocalMatrix = this.getLocalInverseMatrix();
        resMatrix = this.globalToLocalMatrix;
      }
      this.setGlobalInverseMatrixDirty(false);
    }
    return resMatrix;
  }
 

  //TODO maybe cheaper to call globalMatrix.invert() than get the matrix recursively?
  /**
   * Gets the global inverse matrix recursive.
   *
   * @param current the current
   * @param currentMatrix the current matrix
   *
   * @return the abs inv matrix recursive
   */
  private void getGlobalInvMatrixRecursive(MTComponent current, Matrix currentMatrix){
//    System.out.println("processing: " + current.getName() + " Inverse Matrix: " + current.getLocalInverseMatrix()) ;
   
    if (current.isGlobalInverseMatrixDirty()){
//      System.out.println(" Recursive Loop -> " +  current.getName() + "'s global inverse is dirty - applying it");
      if (!current.getLocalInverseMatrix().isIdentity()){
        currentMatrix.multLocal(current.getLocalInverseMatrix());
      }
      if (current.getParent() != null)
        this.getGlobalInvMatrixRecursive(current.getParent(), currentMatrix);
    }else{
      //current isnt dirty, -> get the current absolute global inverse and apply it and stop recursion
//      System.out.println(" Recursive Loop -> " +  current.getName() + "'s global inverse is not dirty - get "  + current.getName() + "'s currents global inverse matrix and stop recursion");
      if (!current.getGlobalInverseMatrix().isIdentity()){
        currentMatrix.multLocal(current.getGlobalInverseMatrix());
      }
    }
  }
 
 
  /**
   * Transforms the point - defined in the objects coordinate space - into parent relative space.
   * This is done by multiplying the point with the objects local basis matrix.
   *
   * @param referenceComp the reference comp
   * @param point the point
   *
   * @return the obj space vec to parent relative space
   */
  public static Vector3D getLocalVecToParentRelativeSpace(MTComponent referenceComp, Vector3D point){
    Vector3D ret = point.getCopy();
    ret.transform(referenceComp.getLocalMatrix());
    return ret;
  }

  /**
   * Transforms the given vector in global space coordinates
   * to be relative to the given reference objects parent space.
   * <br>Applies the inverse transforms associated with this parents actor
   * and its ancestors to the vector.
   * <br>NOTE: This transforms the global vector into the reference objects partent
   * space! Not the reference obj's local space!
   *
   * <br>Example:<br>
   * If we would want to rotate an object that is in an arbitrary
   * transformation hierarchy in the scene graph, around a point that is defined in Global coordinates,
   * we have to transform the point to be relative to the object's parent transformation space.
   *
   * <br>This is done by transforming the point by the inverse Global matrix of the objects parent.
   *
   * @param referenceComp the vector will be relative to this components parent space
   * @param point the point
   *
   * @return the global vec to parent relative space
   *
   * the transformed Vector
   */
  public static Vector3D getGlobalVecToParentRelativeSpace(MTComponent referenceComp, Vector3D point){
    //Returns point relative to the references parent!
    if (referenceComp.getParent() == null){
      return point.getCopy();
    }else{
      Vector3D ret = point.getCopy();
//      System.out.println("parent abs world to local matrix: " + referenceComp.getParent().getAbsoluteWorldToLocalMatrix());
      ret.transform(referenceComp.getParent().getGlobalInverseMatrix());
      return ret;
    }
//    Vector3D ret = point.getCopy(); //OLD WAY
//    ret.transform(referenceComp.getAbsoluteWorldToLocalMatrix());
//    return ret;
  }
 
 
  /**
   * Calculates the transformation necessary to transform a component to be relative
   * to the destination component.
   * <p>
   * So for example, if you want to add a component from a random position in the scence graph
   * to a different component somewhere else in the scene graph, with the component remaining at the same global position,
   * you would transform the first component with the Matrix from the call of
   * <code>getTransformToDestinationParentSpace(originComponent,destinationComponent)</code>.
   * Then you would add the component to the destination component as its child.
   * The component will have the same global coordinates as before, but will now
   * be under the influence of the new parents transforms etc.
   *
   * @param originComponent the origin component
   * @param destinationComponent the destination component
   *
   * @return the transform to destination parent space
   *
   * the matrix
   */
  public static Matrix getTransformToDestinationParentSpace(MTComponent originComponent, MTComponent destinationComponent){
//    /*
    if (originComponent.getParent() != null){
      //Transform to world space, keeping only the objects internal transform
      Matrix compParentWorld = new Matrix(originComponent.getParent().getGlobalMatrix());
      //Transform to destination space, so that the destination
      //will not change the actual objects transform, shape and position
      //by negating the destination obj's absolute transform
      destinationComponent.getGlobalInverseMatrix().mult(compParentWorld, compParentWorld);
      return compParentWorld;
    }else{
//      componentToTransform.transform(destinationComponent.getAbsoluteWorldToLocalMatrix());
      return destinationComponent.getGlobalInverseMatrix();
    }
//    */
   
    /*
      //Transform to world space, keeping only the objects internal transform
//      componentToTransfrom.transform(componentToTransform.getParent().getAbsoluteLocalToWorldMatrix());
      Matrix compParentWorld = new Matrix(originComponent.getAbsoluteLocalToWorldMatrix());
     
      //Transform to destination space, so that the destination
      //will not change the actual objects transform, shape and position
      //by negating the destination obj's absolute transform
//      componentToTransform.transform(destinationComponent.getAbsoluteWorldToLocalMatrix());
      if (destinationComponent.getParent() != null){
        destinationComponent.getParent().getAbsoluteWorldToLocalMatrix().mult(compParentWorld, compParentWorld);
        return compParentWorld;
      }else{
        return compParentWorld;
      }
      */
  }
 
  /**
   * Gets the transform to destination local space.
   *
   * @param originComponent the origin component
   * @param destinationComponent the destination component
   *
   * @return the transform to destination local space
   */
  public static Matrix getTransformToDestinationLocalSpace(MTComponent originComponent, MTComponent destinationComponent){
//    /*  //Worked with centerpoint
      //Transform to global space, keeping only the objects internal transform
//      componentToTransfrom.transform(componentToTransform.getParent().getAbsoluteLocalToWorldMatrix());
      Matrix compParentWorld = new Matrix(originComponent.getGlobalMatrix());
     
      //Transform to destination space, so that the destination
      //will not change the actual objects transform, shape and position
      //by negating the destination obj's absolute transform
//      componentToTransform.transform(destinationComponent.getAbsoluteWorldToLocalMatrix());
      if (destinationComponent.getParent() != null){
        destinationComponent.getParent().getGlobalInverseMatrix().mult(compParentWorld, compParentWorld);
        return compParentWorld;
      }else{
        return compParentWorld;
      }
//      */
      /*
      //Transform to world space, keeping only the objects internal transform
      //Works with textarea dragaway
      Matrix compParentWorld;
      if (originComponent.getParent() != null){
//        compParentWorld = new Matrix(originComponent.getAbsoluteLocalToWorldMatrix());
        compParentWorld = new Matrix(originComponent.getParent().getAbsoluteLocalToWorldMatrix());
      }else{
        compParentWorld = new Matrix();
      }
      //Transform to destination space, so that the destination
      //will not change the actual objects transform, shape and position
      //by negating the destination obj's absolute transform
      destinationComponent.getAbsoluteWorldToLocalMatrix().mult(compParentWorld, compParentWorld);
      return compParentWorld;
      */
  }
 

  /**
   *  Converts the Vector3D object from the component's (local) coordinates to the world/canvas (global) coordinates.
   *  <br><br>
   *  This method allows you to convert any given x, y and z coordinates from values that are relative to
   *  the origin (0,0) of a specific component (local coordinates) to values that are relative to
   *  the origin of the canvas (global coordinates).
   *  <br><br>
   *  To use this method, first create an instance of the Vector3D class.
   *  The x, y and z values that you assign represent local coordinates because they relate to the origin of the component.
   *  <br><br>
   *  You then pass the Vector3D instance that you created as the parameter to the localToGlobal() method.
   *<br>
   *  The method returns a new Vector3D object with x, y and z values that relate to the origin of the global/canvas instead of
   *  the origin of the component.
   *
   * @param point the point
   *
   * @return A new vector3D object with coordinates relative to the global/canvas.
   */
  public Vector3D localToGlobal(Vector3D point){
    Vector3D ret = point.getCopy();
    ret.transform(this.getGlobalMatrix());
    return ret;
  }
 
 
  /**
   *  Converts the Vector3D object from the component's (local) coordinates to the parent component's coordinates.
   *  <br><br>
   *  This method allows you to convert any given x, y and z coordinates from values that are relative to
   *  the origin (0,0) of a specific component (local coordinates) to values that are relative to
   *  the origin of the parent component.
   *  <br><br>
   *  To use this method, first create an instance of the Vector3D class.
   *  The x, y and z values that you assign represent local coordinates because they relate to the origin of the component.
   *  <br><br>
   *  You then pass the Vector3D instance that you created as the parameter to the localToParent() method.
   *<br>
   *  The method returns a new Vector3D object with x, y and z values that relate to the origin of the parent instead of
   *  the origin of the component.
   *
   * @param point the point
   *
   * @return A new vector3D object with coordinates relative to the parent component.
   */
  public Vector3D localToParent(Vector3D point){
    Vector3D ret = point.getCopy();
    ret.transform(this.getLocalMatrix());
    return ret;
  }
 
 
  /**
   *  Converts the Vector3D object from the parent component's coordinates to this component's (local) coordinates.
   *  <br><br>
   *  This method allows you to convert any given x, y and z coordinates from values that are relative to
   *  the origin (0,0) of a parent to values that are relative to
   *  the origin of this component.
   *  <br><br>
   *  To use this method, first create an instance of the Vector3D class.
   *  The x, y and z values that you assign represent parent relative coordinates because they relate to the origin of
   *  the component's parent.
   *  <br><br>
   *  You then pass the Vector3D instance that you created as the parameter to the parentToLocal() method.
   *  <br>
   *  The method returns a new Vector3D object with x, y and z values that relates to the origin of this component
   *  instead of the origin of the parent component.
   *
   * @param point the point
   *
   * @return A new vector3D object with coordinates relative to the components local space.
   */
  public Vector3D parentToLocal(Vector3D point){
    Vector3D ret = point.getCopy();
    ret.transform(this.getLocalInverseMatrix());
    return ret;
  }
 
 
  /**
   * Converts the Vector3D object from the world (global) coordinates to the component's (local) coordinates.
   *<br><br>
   * To use this method, first create an instance of the Vector3D class.
   * <br>
   * The x, y and z values that you assign represent global coordinates because they relate to the origin (0,0) of the main display area.
   * Then pass the Vector3D instance as the parameter to the globalToLocal() method.
   * <br>
   * The method returns a new Vector3D object with x and y values that relate to the origin of the component 
   * instead of the origin of the world.
   *
   * @param point the point
   *
   * @return a new vector3D object with coordinates relative to the component.
   */
  public Vector3D globalToLocal(Vector3D point){
    Vector3D ret = point.getCopy();
    ret.transform(this.getGlobalInverseMatrix());
    return ret;
  }
 
 
  /**
   * Transforms the global ray into local coordinate space and returns the new ray.
   *
   * @param globalRay the global ray
   *
   * @return the ray
   */
  public Ray globalToLocal(Ray globalRay){
//    return Ray.getTransformedRay(globalRay, this.getGlobalMatrix().invert());
    return Ray.getTransformedRay(globalRay, this.getGlobalInverseMatrix());
  }
 
//////////////////////////////////////////////////////////////
//          COMPONENT TRANSFORMATIONS        //
//////////////////////////////////////////////////////////////
  /*
   * NOTE: the matrix and the inverse may suffer from rounding erros and not be exact inverse to each other!
   * we calc the inverse incrementally -> rounding off errors accumulate
   * -> after a certain number of rotations we use the invert() method on the localMatrices instead
   * Also from incremental rotations the matrix may loose its orthogonality
   * -> we re-orthogonalize after a certain number of rotations
  */
 
  /**
   * Transforms the shapes local coordinate space by the specified matrix. This operation
   * can be quite costly since it involves a matrix multiplication and a calculation of its inverse.
   *
   * @param transformMatrix the transform matrix
   */
  public void transform(Matrix transformMatrix) {
    this.setLocalMatrixInternal(transformMatrix.mult(this.getLocalMatrix(), this.getLocalMatrix()));
    try {
      //THIS OPERATION IS NOT CHEAP!
      //TODO maybe also only calculate this on demand? (at getLocalInverse() or getGlobalInverse())
      this.setLocalInverseMatrixInternal(this.getLocalMatrix().invert());
      this.inversePrecisionErrors = 0;
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 


  /**
   * Translate. Move the component in the direction of the specified vector.
   * The transformspace specifies the space, which the translation should be relative
   * to.
   *
   * @param dirVect the dir vect
   * @param transformSpace the transform space
   */
  public void translate(Vector3D dirVect, TransformSpace transformSpace) {
    switch (transformSpace) {
    case LOCAL:
      dirVect.transformDirectionVector(this.getLocalMatrix());
      break;
    case RELATIVE_TO_PARENT:
      //default
      break;
    case GLOBAL:
      if (this.getParent()!= null){
        //Transform direction vector from world space to this objs parent space
        dirVect.transformDirectionVector(this.getParent().getGlobalInverseMatrix());
      }
      break;
    default:
      break;
    }
    this.translate(dirVect);
  }
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#translateGlobal(org.mt4j.util.math.Vector3D)
   */
  public void translateGlobal(Vector3D dirVect) {
    this.translate(dirVect, TransformSpace.GLOBAL);
  }
 
 
  /**
   * Translates this component in the give direction, relative to its parent component.
   *
   * @param dirVect the dir vect
   */
  public void translate(Vector3D dirVect) {
//    Matrix[] ms = Matrix.getTranslationMatrixAndInverse(dirVect.getX(), dirVect.getY(), dirVect.getZ());
    Matrix[] ms = _translationComputation; //use existing object to avoid object creation
    Matrix.toTranslationMatrixAndInverse(ms[0], ms[1], dirVect.x, dirVect.y, dirVect.z);
   
//    this.setLocalBasisMatrixInternal(ms[0].mult(this.getLocalBasisMatrix(), this.getLocalBasisMatrix()));
    //Using special multiplication with fewer operations - seems to work ;)
    this.setLocalMatrixInternal(ms[0].translateMult(this.getLocalMatrix(), this.getLocalMatrix()));
    try {
//      this.setLocalInverseMatrixInternal(this.getLocalInverseMatrix().multLocal(ms[1]));
      this.setLocalInverseMatrixInternal(this.getLocalInverseMatrix().translateMultLocal(ms[1]));
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 
 
  /**
   * X rotate.
   * The transformspace parameter indicates in which
   * coordinate space the point is specified in.
   * @param rotationPoint the rotation point
   * @param degree the degree
   * @param transformSpace the transform space
   */
  public void rotateX(Vector3D rotationPoint, float degree, TransformSpace transformSpace) {
    switch (transformSpace) {
    case LOCAL:
      rotationPoint = MTComponent.getLocalVecToParentRelativeSpace(this, rotationPoint);
      break;
    case RELATIVE_TO_PARENT:
      //default
      break;
    case GLOBAL:
      rotationPoint = MTComponent.getGlobalVecToParentRelativeSpace(this, rotationPoint);
      break;
    default:
      break;
    }
    this.rotateX(rotationPoint, degree);
  }
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent3D#rotateXGlobal(org.mt4j.util.math.Vector3D, float)
   */
  public void rotateXGlobal(Vector3D rotationPoint, float degree) {
    this.rotateX(rotationPoint, degree, TransformSpace.GLOBAL);
  }
 
  /**
   * X rotate.
   * Rotates relative to the parent coordinate space.
   *
   * @param rotationPoint the rotation point
   * @param degree the degree
   */
  public void rotateX(Vector3D rotationPoint, float degree) {
//    Matrix[] ms = Matrix.getXRotationMatrixAndInverse(rotationPoint, degree);
    Matrix[] ms = _xRotationComputation;
    Matrix.toXRotationMatrixAndInverse(ms[0], ms[1], rotationPoint, degree);
   
    this.setLocalMatrixInternal(ms[0].mult(this.getLocalMatrix(), this.getLocalMatrix()));
    this.inversePrecisionErrors ++;
    this.orthogonalityErrors ++;
   
    if (this.orthogonalityErrors >= reOrthogonalizeThreshold){
//      System.out.println("Matrix re-orthogonalized and inverted at: " + this);
      this.reOrthogonalize(); //This also calculates the inverse in call of setLocalMatrix(..)
      this.orthogonalityErrors = 0;
      this.inversePrecisionErrors = 0;
    }else{
      try {
        if (this.inversePrecisionErrors >= invPrecisionThreshold){
          this.inversePrecisionErrors = 0;
//          System.out.println("Matrix inverted at: " + this);
          this.setLocalInverseMatrixInternal(new Matrix(this.getLocalMatrix()).invertLocal());
        }else{
          this.setLocalInverseMatrixInternal(this.getLocalInverseMatrix().multLocal(ms[1]));
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
 
  /**
   * Y rotate.
   * The transformspace parameter indicates in which
   * coordinate space the point is specified in.
   *
   * @param rotationPoint the rotation point
   * @param degree the degree
   * @param transformSpace the transform space
   */
  public void rotateY(Vector3D rotationPoint, float degree, TransformSpace transformSpace) {
    switch (transformSpace) {
    case LOCAL:
      rotationPoint = MTComponent.getLocalVecToParentRelativeSpace(this, rotationPoint);
      break;
    case RELATIVE_TO_PARENT:
      //default
      break;
    case GLOBAL:
      rotationPoint = MTComponent.getGlobalVecToParentRelativeSpace(this, rotationPoint);
      break;
    default:
      break;
    }
    this.rotateY(rotationPoint, degree);
  }
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent3D#rotateYGlobal(org.mt4j.util.math.Vector3D, float)
   */
  public void rotateYGlobal(Vector3D rotationPoint, float degree) {
    this.rotateY(rotationPoint, degree, TransformSpace.GLOBAL);
  }
 
  /**
   * Y rotate.
   * Rotates relative to the parent coordinate space.
   *
   * @param rotationPoint the rotation point
   * @param degree the degree
   */
  public void rotateY(Vector3D rotationPoint, float degree) {
//    Matrix[] ms = Matrix.getYRotationMatrixAndInverse(rotationPoint, degree);
    Matrix[] ms = _yRotationComputation;
    Matrix.toYRotationMatrixAndInverse(ms[0], ms[1], rotationPoint, degree);
   
    this.setLocalMatrixInternal(ms[0].mult(this.getLocalMatrix(), this.getLocalMatrix()));
    this.inversePrecisionErrors ++;
    this.orthogonalityErrors ++;
   
    if (this.orthogonalityErrors >= reOrthogonalizeThreshold){
//      System.out.println("Matrix re-orthogonalized and inverted at: " + this);
      this.reOrthogonalize(); //This also calculates the inverse in call of setLocalMatrix(..)
      this.orthogonalityErrors = 0;
      this.inversePrecisionErrors = 0;
    }else{
      try {
        if (this.inversePrecisionErrors >= invPrecisionThreshold){
          this.inversePrecisionErrors = 0;
//          System.out.println("Matrix inverted at: " + this);
          this.setLocalInverseMatrixInternal(new Matrix(this.getLocalMatrix()).invertLocal());
        }else{
          this.setLocalInverseMatrixInternal(this.getLocalInverseMatrix().multLocal(ms[1]));
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }
 
  /**
   * Rotates the component around the specified point on the Z axis.
   * The transformspace parameter indicates in which
   * coordinate space the point is specified in.
   *
   * @param rotationPoint the rotation point
   * @param degree the degree
   * @param transformSpace the transform space
   */
  public void rotateZ(Vector3D rotationPoint, float degree, TransformSpace transformSpace) {
    switch (transformSpace) {
    case LOCAL:
      rotationPoint = MTComponent.getLocalVecToParentRelativeSpace(this, rotationPoint);
      break;
    case RELATIVE_TO_PARENT:
      //default
      break;
    case GLOBAL:
      rotationPoint = MTComponent.getGlobalVecToParentRelativeSpace(this, rotationPoint);
      break;
    default:
      break;
    }
    this.rotateZ(rotationPoint, degree);
  }
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#rotateZGlobal(org.mt4j.util.math.Vector3D, float)
   */
  public void rotateZGlobal(Vector3D rotationPoint, float degree) {
    this.rotateZ(rotationPoint, degree, TransformSpace.GLOBAL);
  }
 
 
  /**
   * Rotates the obj around the z-axis around the rotationpoint.
   * The rotation point is parent-transformation space-relative.
   *
   * @param rotationPoint the rotation point
   * @param degree the degree
   */
  public void rotateZ(Vector3D rotationPoint, float degree) {
//    Matrix[] ms = Matrix.getZRotationMatrixAndInverse(rotationPoint, degree);
    Matrix[] ms = _zRotationComputation;
    Matrix.toZRotationMatrixAndInverse(ms[0], ms[1], rotationPoint, degree);
   
    //Using special multiplication with fewer operations - seems to work ;)
    this.setLocalMatrixInternal(ms[0].zRotateMult(this.getLocalMatrix(), this.getLocalMatrix()));
    this.inversePrecisionErrors ++;
    this.orthogonalityErrors ++;
   
    if (this.orthogonalityErrors >= reOrthogonalizeThreshold){
//      System.out.println("Matrix re-orthogonalized and inverted at: " + this);
      this.reOrthogonalize(); //This also calculates the inverse in call of setLocalMatrix(..)
      this.orthogonalityErrors = 0;
      this.inversePrecisionErrors = 0;
    }else{
      try {
        if (this.inversePrecisionErrors >= invPrecisionThreshold){
          this.inversePrecisionErrors = 0;
//          System.out.println("Matrix inverted at: " + this);
          this.setLocalInverseMatrixInternal(new Matrix(this.getLocalMatrix()).invertLocal());
        }else{
          this.setLocalInverseMatrixInternal(this.getLocalInverseMatrix().fastMult43(ms[1],this.getLocalInverseMatrix()));
        }
      } catch (Exception e) {
        e.printStackTrace();
      }
    }
  }

 
  /**
   * Scales the obj around the scalingPoint. The transformspace parameter indicates in which
   * coordinate space the point is specified in.
   * <br><strong>Note:</strong> Non-uniform scaling may lead to bad results!
   *
   * @param X the x
   * @param Y the y
   * @param Z the z
   * @param scalingPoint the scaling point
   * @param transformSpace the transform space
   */
  public void scale(float X, float Y, float Z, Vector3D scalingPoint, TransformSpace transformSpace) {
    switch (transformSpace) {
    case LOCAL:
      scalingPoint = MTComponent.getLocalVecToParentRelativeSpace(this, scalingPoint);
      break;
    case RELATIVE_TO_PARENT:
      //default
      break;
    case GLOBAL:
      scalingPoint = MTComponent.getGlobalVecToParentRelativeSpace(this, scalingPoint);
      break;
    default:
      break;
    }
    this.scale(X, Y, Z, scalingPoint);
  }
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#scaleGlobal(float, float, float, org.mt4j.util.math.Vector3D)
   */
  public void scaleGlobal(float X, float Y, float Z, Vector3D scalingPoint) {
    this.scale(X, Y, Z, scalingPoint, TransformSpace.GLOBAL);
  }
 
 
  //FIXME scale non uniform um parent space punkt realisieren,
  //so gibts bug z.b. beim picking, und bei tastatur
  /**
   * <b>CURRENTLY DOES NOT REALLY SUPPORT NON-UNIFORM SCALING!</b>
   * <p>Scales the polygon around the scalingPoint.
   *
   * @param X the x
   * @param Y the y
   * @param Z the z
   * @param scalingPoint the scaling point
   */
  public void scale(float X, float Y, float Z, Vector3D scalingPoint) {
    /*//TODO !!//TODO mit scaling point umgehen, im moment ignoriert! also immer um 0,0,0/z in der diagonalen
    if (!isScaleUniformXY(X,Y,Z)){
      //TODO mit scaling point umgehen, im moment ignoriert! also immer um 0,0,0/z in der diagonalen
      //SetSize scaled jetzt um object frame origin! :(
      Matrix m = Matrix.getNonUniformScalingTrialMatrix(this.getLocalBasisMatrix(), X, Y, Z);
//      this.setLocalBasisMatrix(m);
      this.setLocalBasisMatrixInternal(m);
     
      //TODO Funktionier auch? unterschied zu unten?? dann k�nnte man auch einfach setLocalBasisMatrix(m) aufrufen..
      this.setLocalInverseMatrixInternal(this.getLocalBasisMatrix().invert());
     
      //Inverse wird von hand unten berechnet und ist nicht die directe inverse
//      Matrix mInv = Matrix.getInvScalingMatrix(scalingPoint, X, Y, Z);
//      this.setLocalInverseMatrixInternal(this.getLocalInverseMatrix().mult(mInv));
    }else
    */
    {
//      /*//For uniform scalings or non uniform scalings before any other transform has happened
//      Matrix[] ms = Matrix.getScalingMatrixAndInverse(scalingPoint, X, Y, Z);
      Matrix[] ms = _scalingComputation;
      Matrix.toScalingMatrixAndInverse(ms[0], ms[1], scalingPoint, X, Y, Z);
     
//      this.setLocalBasisMatrixInternal(ms[0].mult(this.getLocalBasisMatrix(), this.getLocalBasisMatrix())); //working original
//      this.setLocalBasisMatrixInternal(this.getLocalBasisMatrix().mult(ms[0])); //FIXME TRIAL! PROBLEM WITH NON-UNIFORM SCALING!!
      this.setLocalMatrixInternal(ms[0].scaleMult(this.getLocalMatrix(), this.getLocalMatrix()));
      try {
//        this.setLocalInverseMatrixInternal(this.getLocalInverseMatrix().multLocal(ms[1])); //working original!
//        this.setLocalInverseMatrixInternal(ms[1].mult(this.getLocalInverseMatrix()));
        this.setLocalInverseMatrixInternal(this.getLocalInverseMatrix().scaleMultLocal(ms[1]));
      } catch (Exception e) {
        e.printStackTrace();
      }
//      */
    }
   
    //TODO this is a hack to allow non-uniform scaling for
    //Abstract shapes. This scales the shapes geometry, not their transformation.
    //Thus, children arent scaled.
    //=>Problem with complexpolys for ex. since they have more geometry than in the geometryInfo..
    //=>setSize() wont work then
    //non uniform scaling makes problems when comp has been rotated and isnt axis aligned
    /*
    if (!isScaleUniformXY(X,Y,Z) && this instanceof AbstractShape) {
      AbstractShape shape = (AbstractShape) this;
     
      Vertex[] localVecs = shape.getVerticesLocal();
      Vector3D scalingInv = scalingPoint.getCopy();
     
      //Transform local scalingpoint into object space
//      scalingInv.transform(this.getLocalInverseMatrix());
//      scalingInv.transform(this.getAbsoluteWorldToLocalMatrix());
     
      scalingInv.transformDirectionVector(this.getLocalBasisMatrix());
     
      //Transform object vertices
      Vector3D.transFormArray(Matrix.getScalingMatrix(scalingInv, X, Y, Z), localVecs);
     
      shape.setVerticesLocal(localVecs);
      //TODO bei kindern das gleich probieren?
      //TODO auch bei global machen
    }else
    */
  }
 
  /*
  private boolean isScaleUniformXY(float x, float y, float z){
    return x==y;
  }
  */
 

  
  /**
   * This method is called just before the components drawComponent method is invoked.
   * It sets up the components matrix, clipping and other stuff.
   * @param g the graphics context
   */
  public void preDraw(PGraphics g) {
    if (this.isDepthBufferDisabled()){
      Tools3D.disableDepthBuffer(g);
    }
   
    g.pushMatrix();

    MTLight aLight = this.getLight();
    if (aLight != null){
      GL gl = ((PGraphicsOpenGL)g).gl;
      gl.glEnable(GL.GL_LIGHTING); //this is expensive
      aLight.enable();
    }

    if (!this.getLocalMatrix().isIdentity())
      this.applyLocalMatrix();

    if (this.getClip() != null){
      this.getClip().enableClip(g);
    }
  }

 
  /**
   * Executes this component's drawing commands (Not its children!).
   * The component's matrix has to be made current before drawing.
   * <br>This method can be overridden in subclasses
   * and filled with drawing commands.
   * <br>NOTE: This method is called by the application. Usually you should
   * not invoke this method directly!
   * @param g the graphics context
   */
  public void drawComponent(PGraphics g){   }
 
 
  /**
   * Post draw.
   * Called immediatly after drawing this component.
   *
   * @param g the g
   */
  public void postDraw(PGraphics g) {
    if (this.getClip() != null){
      this.getClip().disableClip(g);
    }
   
    if (this.getChildClip() != null){
      this.getChildClip().enableClip(g);
    }
  }
 
 
  /**
   * Post draw Children.
   * Called after drawing this component and its children.
   * @param g the graphics context
   */
  public void postDrawChildren(PGraphics g) {
    if (this.isDepthBufferDisabled()){
      Tools3D.restoreDepthBuffer(g);
    }
   
    if (this.getChildClip() != null){
      this.getChildClip().disableClip(g);
    }
     
    renderer.popMatrix();

    //FIXME TRIAL
    MTLight aLight = this.getLight();
    if (aLight != null){
      aLight.disable();
      GL gl = ((PGraphicsOpenGL)g).gl;
      gl.glDisable(GL.GL_LIGHTING);
    }
  }
 
  // CLIP ////////////////
  /** The clip. */
  protected Clip clip;
 
  /**
   * Gets the clip.
   * @return the clip
   */
  public Clip getClip() {
    return clip;
  }
 
  /**
   * Sets the clip mask for this component. This restricts the drawing
   * of this component to the specified clip area.
   * <br>NOTE: Only supported when using OpenGL as the renderer!
   *
   * @param clip the new clip
   */
  public void setClip(Clip clip) {
    if (MT4jSettings.getInstance().isOpenGlMode()){
      this.clip = clip; 
    }
  }
  // CLIP ////////////////

 
  // CHILDREN CLIP /////////////////////
  /** The child clip. */
  private Clip childClip;
 
  /**
   * Gets the child clip.
   * @return the child clip
   */
  public Clip getChildClip() {
    return childClip;
  }

  /**
   * Sets the clip mask for this components children.
   * Only children contained in the specified clipping shape will be visible.
   * <br>NOTE: Only supported when using OpenGL as the renderer!
   *
   * @param childClip the child clip mask
   */
  public void setChildClip(Clip childClip) {
    if (MT4jSettings.getInstance().isOpenGlMode()){
      this.childClip = childClip; 
    }
  }
  // CHILD CLIP MASK /////////////////////
 
 
  //FIXME TRIAL OPENGL LIGHTS ////////////
  /**
   * Sets the light.
   * <br>NOTE: Only supported when using OpenGL as the renderer!
   *
   * @param light the new light
   */
  public void setLight(MTLight light){
    this.light = light;
  }

  /**
   * Gets the light.
   *
   * @return the light
   */
  public MTLight getLight() {
    return light;
  }
  //TRIAL OPENGL LIGHTS ////////////
 
 
  //FIXME REMOVE THIS? THIS IS OBSOLETE BECAUSE OF UPDATECOMPONENT AND drawAndUpdateRectursive!
//  /**
//   * Calls the updateComponent() method on this component
//   * and the update() method on its children.
//   * This is handled automatically by the MTCanvas! Dont invoke this!
//   *
//   * @param timeDelta the time delta since the last frame
//   */
//  public void update(long timeDelta){
//    this.updateComponent(timeDelta);
//   
//    for (MTComponent child : childComponents)
//      child.update(timeDelta);
//  }
 
  /**
   * Tells the component to update its state if neccessary. This is called
   * shortly before the component's <code>drawComponent()</code> method is invoked at every frame.
   *  The <code>timeDelta</code>
   * parameter indicates the time passed since the last frame was drawn and can be used
   * for animations for example.<br>
   * Also, this updates the associated <code>IMTController</code> object if existing.
   * If overriden, the superclass implementation should always be called!
   * <br>NOTE: Be aware that this method is called every frame, so doing expensive calculations in it may slow down the
   * application.
   *
   * @param timeDelta the time delta
   */
  public void updateComponent(long timeDelta) {
    if (controller != null){
      controller.update(timeDelta);
    }
  }

 
  /**
   * Adds a component as a child to this component.
   * By doing this, it will be under the influence of the parents
   * transformations.
   * <br>NOTE: adding children during traversal of the component hierarchy
   * will result in a concurrent modification error (e.g. in methods like
   * drawComponent or updateComponent).
   * To resolve this, we can use the AddNodeActionThreadSafe class to add
   * as an IPreDrawAction to our current scene
   * (looking something like this: yourScene.addPreDrawAction(new AddNodeActionThreadSafe(..));)
   * The component will then be added before the next rendering loop.
   *
   * @param tangibleComp the tangible comp
   */
  public void addChild(MTComponent tangibleComp){
    this.addChild(this.childComponents.size(), tangibleComp);
  }
 
  /**
   * Adds the child at the specified position in the list of children.
   *
   * @param i the i
   * @param tangibleComp the tangible comp
   *
   * @see MTComponent#addChild
   */
  public void addChild(int i, MTComponent tangibleComp){
    MTComponent oldParent = tangibleComp.getParent();
    boolean sameParent = false;
    if (oldParent != null){
      oldParent.removeChild(tangibleComp);
      if (oldParent.equals(this)){
        i--;//If we removed the comp from this (same parent) we have to decrease the index
        sameParent = true;
      }
      i = (i<0)? 0 : i; //ensure i > 0
    }
    tangibleComp.setParent(this);
    childComponents.add(i, tangibleComp);
   
    if (!sameParent){ //TEST - only mark dirty if comp was added to different parent
      //To inform its children, that they have to update their
      //global matrices, because this new parent could
      //change it with its own
      tangibleComp.setMatricesDirty(true);
      //search up the tree and update the camera responsible for drawing the component
      tangibleComp.searchViewingCamera();
    }
    //Fire state change event
    this.fireStateChange(StateChange.CHILD_ADDED);
    tangibleComp.fireStateChange(StateChange.ADDED_TO_PARENT);
  }
 
 
 
  /**
   * Adds an array of components to this component as children.
   *
   * @param tangibleComps the tangible comps
   */
  public void addChildren(MTComponent[] tangibleComps){
    for (int i = 0; i < tangibleComps.length; i++) {
      MTComponent object = tangibleComps[i];
      this.addChild(object);
    }
  }
 
 
  /**
   * Gets the child list which is also used internally in <code>MTComponent</code>.
   * Therefor, this should be used for read operations only!
   * <p>This method is provided for performance reasons, because <code>getChildren()</code>
   * contains overhead because it creates a new array for each call.
   *
   * @return the child list
   */
  protected List<MTComponent> getChildList(){
    return childComponents;
  }
 
  /**
   * Gets the children.
   * @return the children
   */
  public MTComponent[] getChildren(){
    return childComponents.toArray(new MTComponent[childComponents.size()]);
  }
 
  /**
   * Gets the child by its unique ID.
   * <br>NOTE: the specified number is the unique component ID, not the index in the children array!
   *
   * @param ID the iD
   *
   * @return the child
   */
  public MTComponent getChildbyID(int ID){
    MTComponent returnObject = null;
    for (int i = 0; i < childComponents.size(); i++) {
      MTComponent object = (MTComponent)childComponents.get(i);
      if (object.getID() == ID)
        returnObject = object;
    }
    return returnObject;
  }
 
  /**
   * Gets the child by index.
   *
   * @param index the index
   *
   * @return the child by index
   */
  public MTComponent getChildByIndex(int index){
    return childComponents.get(index);
  }
 
  /**
   * Gets the child by name.
   *
   * @param name the name
   *
   * @return the child by name
   */
  public MTComponent getChildByName(String name){
    MTComponent returnObject = null;
    for (int i = 0; i < childComponents.size(); i++) {
      MTComponent object = (MTComponent)childComponents.get(i);
      if (object.getName().equals(name))
        returnObject = object;
    }
    return returnObject;
  }
 
 
  /**
   * Goes through all children and their children
   * to check if this component tree contains the given component.
   *
   * @param tangibleComp the tangible comp
   *
   * @return true, if contains child
   */
  public boolean containsChild(MTComponent tangibleComp){
    if (tangibleComp==null)
      return false;
   
    for (int i = 0; i < childComponents.size(); i++) {
      MTComponent currentChildComponent = childComponents.get(i);
      if (currentChildComponent.equals(tangibleComp))
        return true;
      else if (currentChildComponent.containsChild(tangibleComp))
        return true;
    }
    return false;
  }
 
  /**
   * Checks if the given component is a direct child of this component.
   *
   * @param tangibleComp the tangible comp
   *
   * @return true, if contains direct child
   */
  public boolean containsDirectChild(MTComponent tangibleComp){
    return (childComponents.contains(tangibleComp));
  }
 
/*
//  ///////Mal ausproibern und evtl removen
  public boolean containsRecursive(TComponent tangibleComp){
    return (containsRecursiveRec(this.getChildren(), tangibleComp));
  }
 
  private boolean containsRecursiveRec(TComponent[] tangibleComps, TComponent tangibleComp){
    boolean returnBool = false;
    for (int i = 0; i < tangibleComps.length; i++) {
      TComponent currentComponent = tangibleComps[i];
      System.out.println(currentComponent.getName());
      if (currentComponent.equals(tangibleComp)){
        //return true;
        return true;
      }else{
        TComponent[] childComps = currentComponent.getChildren();
        //return containsRecursiveRec(childComps, tangibleComp);
        returnBool = containsRecursiveRec(childComps, tangibleComp);
      }
    }
    return returnBool;
  }
//  ///////Mal ausproibern und evtl removen
*
*/

  /**
   * Gets the ancestor.
   *
   * @return the ancestor
   *
   * the ancestor - the upper most parent in the hierarchy of this component
   */
  public MTComponent getRoot(){
    return getRootRecursive(this);
  }
 
  /* careful not to have cycles in the hierarchy! */
  /**
   * Gets the ancestor recursive.
   *
   * @param current the current
   *
   * @return the ancestor recursive
   */
  private MTComponent getRootRecursive(MTComponent current){
    if (current.getParent() == null){
      return current;
    }else{
      return getRootRecursive(current.getParent());
    }
  }
 
  /**
   * Gets the child count.
   *
   * @return the child count
   *
   * the number of childs this component has
   */
  public int getChildCount(){
    return childComponents.size();
  }
 
  /**
   * Gets the parent.
   *
   * @return the parent
   *
   * the parent of this child or null if it has none.
   */
  public MTComponent getParent(){
    return this.parent;
  }
 
  /**
   * Used internally when adding a component to another.
   *
   * @param parent the parent
   */
  private void setParent(MTComponent parent){
    //remove this from old parent //THIS IS DONE AT ADDCHILD()!
//    if (this.getParent() != null){
//      this.getParent().removeChild(this);
//    }
    this.parent = parent;
  }
 
 
 
  /**
   * Tries to remove the specified child from this component.
   *
   * @param i the i
   */
  public void removeChild(int i){
    try {
      MTComponent comp = childComponents.get(i);
      this.removeChild(comp);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }

 
  /**
   * Removes this component from its parent.
   */
  public void removeFromParent(){
    if (this.getParent() != null){
      this.getParent().removeChild(this);
    }
  }
 
 
  /**
   * Tries to remove the specified child from this component.
   *
   * @param comp the comp
   */
  public void removeChild(MTComponent comp){
    try {
      comp.setParent(null);
      childComponents.remove(comp);
     
      //search up the tree and update the camera responsible for drawing the component
      //will probably be null here
      comp.searchViewingCamera();
     
      comp.fireStateChange(StateChange.REMOVED_FROM_PARENT);
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
 
  /**
   * Removes all direct children of this component.
   */
  public void removeAllChildren(){
    for (int i = childComponents.size()-1; i >= 0; i--) {
      MTComponent child = childComponents.get(i);
      child.removeFromParent();
    }
    childComponents.clear();
  }
 
 
  /**
   * Gets the child index of a child.
   * @param comp the comp
   *
   * @return the child index of
   */
  public int getChildIndexOf(MTComponent comp){
    return childComponents.indexOf(comp);
  }
 
 
  /**
   * <br>If the depth buffer is disabled, the order in which the components are drawn alone decides which objects will appear
   * ontop of others, instead of their distance to the camera. This is useful to avoid "z-fighting" when drawing
   * co-planar objects (ie. 2D windows with ui objects on them).
   * If set to true, this component <b>and all its children</b> will always be drawn above all previously drawn objects,
   * even if the other objects are "in front" of this component.
   *
   * @param drawOnTop the draw on top option
   */
  public void setDepthBufferDisabled(boolean drawOnTop){
    this.sendToFront();
    this.drawnOnTop = drawOnTop;
  }

  /**
   * Checks if is always drawn on top.
   *
   * @return true, if is always drawn on top
   */
  public boolean isDepthBufferDisabled() {
    return drawnOnTop;
  }
 
  /**
   * Puts this components to the end of the children list of
   * its parent.
   * This will result in this component being drawn last and on top
   * of others at the same z-position.
   */
  public void sendToFront(){
    if (this.getParent()!= null){
      this.getParent().sendChildToFront(this);
    }
  }
 
  /**
   * Puts this child to the end of the children list of this component.
   * This will result in this child being drawn last and on top
   * of others at the same Z-position.
   * @param child the child
   */
  protected void sendChildToFront(MTComponent child){
    if (this.containsDirectChild(child)
      && !getChildByIndex(getChildCount()-1).equals(child)
    ){
      //System.out.println("Drawlast: " + tangibleComp.getName());
//      this.removeChild((child));
//      this.addChild((child)); //FIXME THIS DOES A LOT OF UNNECESSARY STUFF - statechange, cam search, matrix dirty!

      childComponents.add(getChildCount(),child);
      childComponents.remove(child);
     
//      childComponents.remove(child);
//      childComponents.add(getChildCount(),child);
    }
  }
 

  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#setVisible(boolean)
   */
  public void setVisible(boolean visible){
    this.visible = visible;
  }
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#isEnabled()
   */
  public boolean isEnabled() {
    return enabled;
  }

 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#setEnabled(boolean)
   */
  public void setEnabled(boolean enabled) {
    this.enabled = enabled;
  }

 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#getID()
   */
  public int getID(){
    return this.ID;
  }
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#setName(java.lang.String)
   */
  public void setName(String name){
    this.name = name;
  }
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#getName()
   */
  public String getName(){
    return this.name;
  }
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#getRenderer()
   */
  public PApplet getRenderer(){
    return this.renderer;
  }

  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#isVisible()
   */
  public boolean isVisible() {
    return visible;
  }
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent3D#isPickable()
   */
  public boolean isPickable() {
    return pickable;
  }


  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent3D#setPickable(boolean)
   */
  public void setPickable(boolean pickable) {
    this.pickable = pickable;
  }


  /*
  public Point getCenterPoint() { //TODO get centerPoint ffrom all childs and integrate?
    float x=0,y=0,z=0;
    x+=this.getCenterPoint().getX();
    y+=this.getCenterPoint().getY();
    z+=this.getCenterPoint().getZ();
   
    TComponent[] childs = this.getChildren();
    for (int i = 0; i < childs.length; i++) {
      TComponent child = childs[i];
     
      x+=child.getCenterPoint().getX();
      y+=child.getCenterPoint().getY();
      z+=child.getCenterPoint().getZ();
    }
   
    //GO TRHOUGH ALL CHILDS
    return null;
  }
 
  protected Point getComponentCenterPoint() { //get centerPoint ffrom all childs and integrate?
    // Auto-generated method stub
    return null;
  }
  */
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#containsPointGlobal(org.mt4j.util.math.Vector3D)
   */
  public boolean containsPointGlobal(Vector3D testPoint) {
//    if (this.componentContainsPointLocal(testPoint))
//      return true;
//    for (int i = childComponents.size()-1; i >= 0; i--) {
//      MTComponent component = childComponents.get(i);
//      if (component.containsPointLocal(testPoint))
//        return true;
//    }
//    return false;
    if (this.componentContainsPointLocal(this.globalToLocal(testPoint)))
      return true;
    for (int i = childComponents.size()-1; i >= 0; i--) {
      if (childComponents.get(i).containsPointGlobal(testPoint))
        return true;
    }
    return false;
  }
 
  /**
   * Checks whether the specified point is contained in this component.
   * This method gets called from the componentContainsPointGlobal method.
   * So in a extending class we would override the componentContainsPointLocal
   * with our intersection code only!
   *
   * @param testPoint the test point
   *
   * @return true, if successful
   */
  protected boolean componentContainsPointLocal(Vector3D testPoint) { //TODO rename containPointLocal
//    return this.containsPointBoundsLocal(testPoint);
    if (this.hasBounds()){
//      System.out.println("\"" + this.getName() + "\": -> BOUNDS only check");
      return this.getBounds().containsPointLocal(testPoint);
    }else{
      return false;
    }
  }
 
//  /**
//   * Contains point bounds local.
//   *
//   * @param testPoint the test point in local coordiantes
//   * @return true, if successful
//   */
//  protected boolean containsPointBoundsLocal(Vector3D testPoint){
//    if (this.isBoundingShapeSet()){
////      System.out.println("\"" + this.getName() + "\": -> BOUNDS only check");
//      return this.getBoundingShape().containsPointLocal(testPoint);
//    }else{
//      return false;
//    }
//  }
 
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent3D#getIntersectionGlobal(org.mt4j.util.math.Ray)
   */
  public Vector3D getIntersectionGlobal(Ray ray) {
    float currentDistance = Float.MAX_VALUE; //high value so that the first time a object is found this distance is exchanged with his
    float objDistance     = 0;
    Vector3D returnPoint   = null;
    Vector3D interSP     = null;
   
    if (this.isVisible() && this.isPickable()) {
      //Get the real ray for this obj, takes the custom camera and viewport of this obj into account
      //-> changes rayStartPoint and point in ray direction
      if (this.getAttachedCamera() != null){
        ray  = getChangedCameraPickRay(this.getRenderer(), this, ray);
      }
     
      //Transforms the ray into local object space
      Ray invertedRay = this.globalToLocal(ray);
     
      //Check if component is clipped and only proceed if the ray intersects the clip shape
      Clip clip = this.getClip();
      if (clip == null || (clip != null && clip.getClipShapeIntersectionLocal(invertedRay) != null)){
        interSP = this.getIntersectionLocal(invertedRay);
        if (interSP != null){
          //FIXME TRIAL - muss f�r die distance messung der world ray genommen
          //werden oder geht der invertierte ray?
          interSP.transform(this.getGlobalMatrix());
          //Get distance from raystart to the intersecting point
          objDistance = interSP.getSubtracted(ray.getRayStartPoint()).length();

          //If the distance is the smalles yet = closest to the raystart replace the returnObject and current distanceFrom
          if ((objDistance - PickResult.HIT_TOLERANCE) < currentDistance ){
            returnPoint = interSP;
            currentDistance = objDistance;
          }
        }
      }

      //Check for child clip intersection, if not intersecting, dont try to pick children
      Clip childClip = this.getChildClip();
      if (childClip != null && childClip.getClipShapeIntersectionLocal(invertedRay) == null){
        return returnPoint;
      }
     
    }
   
    /* Go through all Children */
//    for (int i = childComponents.size()-1; i >= 0; i--) {
    for (int i = 0; i < childComponents.size(); i++) { 
      MTComponent child = childComponents.get(i);
        //Get the intersectionpoint ray/object if there is one
        interSP = child.getIntersectionGlobal(ray);
       
        if (interSP != null ){ //if ray intersects object at a point
          //System.out.println("Intersection at: " + interSP);
          //Get distance from raystart to the intersecting point
          objDistance = interSP.getSubtracted(ray.getRayStartPoint()).length();
          //If the distance is the smalles yet = closest to the raystart replace the returnObject and current distanceFrom
          if (objDistance < currentDistance ){
            returnPoint = interSP;
            currentDistance = objDistance;
          }
        }//if intersection!=null
    }// for
    return returnPoint;
  }
 
 
 
 
  /**
   * Returns the intersection point of the ray and this component (children are not checked for
   * intersections). Usually, if the component has a bounding shape assigned, the bounds are checked
   * for an intersection. Shapes may also check the shape itself for intersection.
   * <br>The ray is assumed to already be in local component space (not in global space).
   * <br>If the component is not intersected, null is returned.
   *
   * @param localRay the rays, in local space
   * @return the component local intersection point
   * @see #globalToLocal
   */
  public Vector3D getIntersectionLocal(Ray localRay) {
//    return this.getBoundsIntersectionLocal(localRay);//FIXME TEST
    if (this.hasBounds()){
      return this.getBounds().getIntersectionLocal(localRay);
    }else{
      return null;
    }
  }
 
//  /**
//   * Gets the bounds intersection local. Test if the ray in local coordinates
//   * intersection this component's bounding shape.
//   * Return the local intersection point or null if there is no intersection or no bounding shape
//   * is set.
//   *
//   * @param localRay the local ray
//   * @return the local intersection point
//   */
//  protected Vector3D getBoundsIntersectionLocal(Ray localRay){//FIXME TEST
//    if (this.isBoundingShapeSet()){
//      return this.getBoundingShape().getIntersectionLocal(localRay);
//    }else{
//      return null;
//    }
//  }


//  /**
//   * Sometimes the wrong obj gets picked if they are on the same plane but with different inverted rays..
//   * probably math rounding off errors with floats etc. (at inverting the ray?)
//   * <br>This makes sure, objs which are checked later for a hit,
//   * (and are probably drawn ontop of the previous ones because drawn later),
//   * are picked more likely.
//   * <br>Still this is kind of a hack
//   */
//  private static final float HIT_TOLERANCE = 0.3f; //0.03f; //FIXME reset to old value!?
 
//  /**
//   * This method allows to pick (Select) an object in the scene.
//   *
//   *
//   * @param pickInfo the pick info
//   *
//   * @return the pick result
//   */
//  public PickResult pick(PickInfo pickInfo){
//    PickResult pickResult = new PickResult();
//    this.pickRecursive(pickInfo, pickResult, Float.MAX_VALUE, pickInfo.getPickRay());
//    return pickResult;
//  }
 
  /**
   * Checks which object lies under the specified screen coordinates.
   * The the results are stored in the returned PickResult object. This component and
   * its children will be checked.
   *
   * @param x the x
   * @param y the y
   *
   * @return the pick result
   */
  public PickResult pick(float x, float y){
    PickResult pickResult = new PickResult();
    PickInfo pickInfo = new PickInfo(x,y, Tools3D.getCameraPickRay(this.getRenderer(), this, x, y));
    this.pickRecursive(pickInfo, pickResult, Float.MAX_VALUE, pickInfo.getPickRay(), true);
//    pickResult.printList();
    return pickResult;
  }
 
 
  /**
   * Gets the intersection of this component with the input cursor.
   *
   * @param cursor the cursor
   * @return the intersection global or null if no intersection
   */
  public Vector3D getIntersectionGlobal(InputCursor cursor){
    return this.getIntersectionGlobal(Tools3D.getCameraPickRay(getRenderer(), this, cursor));
  }
 
 
  /**
   * Checks which object lies under the specified screen coordinates.
   * The the results are stored in the returned PickResult object. This component and
   * its children will be checked.
   *
   * @param x the x
   * @param y the y
   * @param onlyPickables check the only pickable components
   *
   * @return the pick result
   */
  public PickResult pick(float x, float y, boolean onlyPickables){
    PickResult pickResult = new PickResult();
    PickInfo pickInfo = new PickInfo(x,y, Tools3D.getCameraPickRay(this.getRenderer(), this, x, y));
    this.pickRecursive(pickInfo, pickResult, Float.MAX_VALUE, pickInfo.getPickRay(), onlyPickables);
//    pickResult.printList();
    return pickResult;
  }
 
 
  //FIXME currObjDist now in pickresult vistor, so parameter is obsolete
  //could make currObjDistance  return parameter ..
  /**
   * Pick closest comp with ray recursive.
   *
   * @param pickInfo the pick info
   * @param pickResult the pick result
   * @param currObjDist the curr obj dist
   * @param currentRay the current ray
   * @param onlyPickables the only pickables
   * @return the float
   */
  private float pickRecursive(PickInfo pickInfo, PickResult pickResult, float currObjDist, Ray currentRay, boolean onlyPickables){
    Vector3D interSP  = null;
    float objDistance   = 0;
    //TEST, Wenns probleme gibt das wieder aktivieren
//    currObjDist = pickResult.getDistanceNearestPickObj();
   
//    System.out.println("At: " + this.getName() + " Current Distance: " + currObjDist);
    if (this.isVisible() &&
      ((onlyPickables && this.isPickable()) || !onlyPickables)
    ){
      //Get the real ray for this obj, takes the viewing camera and viewport of this obj into account
      //-> changes rayStartPoint and point in ray direction
      if (this.getAttachedCamera() != null){
        currentRay  = getChangedCameraPickRay(this.getRenderer(), this, pickInfo);
      }
     
      Ray invertedRay;
      if (this.getGlobalInverseMatrix().isIdentity()){
        invertedRay = currentRay;
      }else{
        invertedRay = this.globalToLocal(currentRay);
      }
     
      /*
      //FIXME REMOVE!!!!!
      //This adds lines indicating the world ray and the local object ray used for ray-test
      MTLine l1 = new MTLine(this.getRenderer(), new Vertex(currentRay.getRayStartPoint()), new Vertex(currentRay.getPointInRayDirection()));
      this.getAncestor().addChild(l1);
      MTLine l2 = new MTLine(this.getRenderer(), new Vertex(invertedRay.getRayStartPoint()), new Vertex(invertedRay.getPointInRayDirection()));
      l2.setStrokeColor(255, 10, 10, 255);
      this.getAncestor().addChild(l2);
      */
     
      //Check if component is clipped and only proceed if the ray intersects the clip shape
      Clip clip = this.getClip();
      if (clip == null || (clip != null && clip.getClipShapeIntersectionLocal(invertedRay) != null)){
        interSP = this.getIntersectionLocal(invertedRay);
        if (interSP != null){
          //FIXME TRIAL - muss f�r die distance messung der world ray genommen
          //werden oder geht der invertierte ray? -> musss wohl der world ray sein
          interSP.transform(this.getGlobalMatrix());
          // Get distance from raystart to the intersecting point
          objDistance = interSP.getSubtracted(currentRay.getRayStartPoint()).length();
          //System.out.println("Pick found: " + this.getName() + " InterSP: " + interSP +  " ObjDist: " + objDistance +  " Mouse Pos: " + pickInfo.getScreenXCoordinate() + "," + pickInfo.getScreenYCoordinate() + " InvRay RS:" + invertedRay.getRayStartPoint() + ",RE: " + invertedRay.getPointInRayDirection());

//          //If the distance is the smallest yet = closest to the raystart: replace the returnObject and current distanceFrom
//          if ( (objDistance - HIT_TOLERANCE) <= currObjDist /*|| this.isAlwaysDrawnOnTop()*/){//take isDrawnOnTop into account here?? -> OBJDistance auf 0 setzen?
//          currObjDist = objDistance;
//          pickResult.addPickedObject(this, interSP, objDistance);
////          System.out.println("-> Now nearest: " + this.getName());
//          }

          //FIXME TEST - ADD ALL PICKED OBJECTS - SORT LATER
          pickResult.addPickedObject(this, interSP, objDistance);
        }
      }
     
      //Check for child clipping shape intersection, if not intersecting -> dont try to pick children
      Clip childClip = this.getChildClip();
      if (childClip != null && childClip.getClipShapeIntersectionLocal(invertedRay) == null){
        return currObjDist;
      }
    }
   
    /* recursively check all children now */
    for (int i = 0; i < childComponents.size(); i++) {
      MTComponent child = childComponents.get(i);
      if (child.isVisible()) {
        if (composite){
          //Start a new picking with a new Pickresult obj from here
          PickResult compositePickRes = new PickResult();
          float compDistance = child.pickRecursive(pickInfo, compositePickRes, Float.MAX_VALUE, currentRay, onlyPickables);

          //Add the composites picks to the overall picks
          if (compositePickRes.getNearestPickResult() != null){
//            System.out.println("In: " + this.getName() + " Composites child picked, pick resultDistance: " + compDistance);
            /*//TODO m�sste diese hier nach distanz geordnet in insgesamt pickresult einf�gen..
            ArrayList<MTBaseComponent> pickList = compositePickRes.getPickList();
            for(MTBaseComponent comp : pickList){
              pickResult.addPickedObject(comp, compositePickRes.getInterSectionPointOfPickedObj(comp), compositePickRes.getDistanceOfPickedObj(comp));
            } 
            */
            //Add this composite as the last one picked with the distance of the last one picked in the composite pick
//            pickResult.addPickedObjects(compositePickRes.getPickList());
//            pickResult.addPickedObject(this, compositePickRes.getInterSectionPointNearestPickedObj(), compositePickRes.getDistanceNearestPickObj());
           
//            if (//compDistance <= currObjDist
//              (compDistance - HIT_TOLERANCE) <= currObjDist
//            ){
////              System.out.println("Composites child picked and now nearest: " + this.getName()+ " dist: " + compDistance);
//              pickResult.addPickedObject(this, compositePickRes.getInterSectionPointNearestPickedObj(), compositePickRes.getDistanceNearestPickObj());
//              currObjDist = compDistance;
//            }
           
            //FIXME TEST - ADD ALL PICKED OBJECTS - SORT LATER
            PickEntry nearestPickEntry = compositePickRes.getNearestPickEntry();
            pickResult.addPickedObject(this, nearestPickEntry.intersectionPoint, nearestPickEntry.cameraDistance);
          }
        }else{
          currObjDist = child.pickRecursive(pickInfo, pickResult, currObjDist, currentRay, onlyPickables);
        }
      }
    }
    return currObjDist;
  }
 
 
  /**
   * Calculates the "real" picking ray for the object.
   * <br>If the obj has a custom camera attached to it, this camera's position is the new ray origin and
   * the point in the ray direction is the unprojected x,y, coordinates while this camera is active.
   *
   * @param pa the papplet
   * @param obj the obj
   * @param ray the ray
   *
   * @return the real pick ray
   *
   * the new calculated ray, or the original ray, if the obj has no custom camera attached to it.
   */
  private static Ray getChangedCameraPickRay(PApplet pa, IMTComponent3D obj, Ray ray){
    Vector3D pointInRayDirection = ray.getPointInRayDirection();
    Vector3D projected = Tools3D.project(pa, obj.getViewingCamera(), pointInRayDirection);
//    Vector3D projected = Tools3D.project(pa, pointInRayDirection);
    return getChangedCameraPickRay(pa, obj, new PickInfo(
        projected.x,
        projected.y,
        ray));
  }
 
 
  /**
   * Calculates the "real" pickray for the object.
   * <br>If the obj has a custom camera attached to it, this cameras position is the new ray origin and
   * the point in the ray direction is the unprojected x,y, coordinates while this camera is active.
   *
   * @param pa the pa
   * @param obj the obj
   * @param pickInfo the pick info
   * @return the real pick ray
   *
   * the new calculated ray, or the original ray, if the obj has no custom camera attached to it.
   */
  private static Ray getChangedCameraPickRay(PApplet pa, IMTComponent3D obj, PickInfo pickInfo){
    if (obj.getViewingCamera() != null){ //FIXME TEST
      //Re-Project unprojected world coords to projected viewport screen coords (Tuio INput)
      float x = pickInfo.getScreenXCoordinate();
      float y = pickInfo.getScreenYCoordinate();
     
      return Tools3D.getCameraPickRay(pa, obj, x, y);
    }else{
      return pickInfo.getPickRay();
    }
    /*//FIXME disabled for performance for now!
    if (obj.hasCustomViewPort()){
      //Take VIEWPORT changes into account, too
      ViewportSetting customViewPort        = obj.getCustomViewportSetting();
      ViewportSetting defaultViewPortSetting = obj.getDefaultViewportSetting();
      rayStartPoint.setX(customViewPort.getStartX() + (rayStartPoint.getX() * (customViewPort.getWidth()/defaultViewPortSetting.getWidth())));
      rayStartPoint.setY(customViewPort.getStartY() + (rayStartPoint.getY() * (customViewPort.getHeight()/defaultViewPortSetting.getHeight())));
      pointInRayDirection.setX(customViewPort.getStartX() + (pointInRayDirection.getX() * (customViewPort.getWidth()/defaultViewPortSetting.getWidth())));
      pointInRayDirection.setY(customViewPort.getStartY() + (pointInRayDirection.getY() * (customViewPort.getHeight()/defaultViewPortSetting.getHeight())));
      /////
    }
     */
//    return new Ray(rayStartPoint, pointInRayDirection);
  }
 
 
//  /* (non-Javadoc)
//   * @see org.mt4j.components.interfaces.IMTComponent3D#getDefaultViewportSetting()
//   */
//  public ViewportSetting getDefaultViewportSetting(){
//    return this.defaultViewPortSetting;
//  }
// 
//  //TODO make function 2Dshift3DObj? das dann viewport �ndert?
//  /* (non-Javadoc)
//   * @see org.mt4j.components.interfaces.IMTComponent3D#getCustomViewportSetting()
//   */
//  public ViewportSetting getCustomViewportSetting() {
//    return customViewPort;
//  }
//
//  //FIXME funktioniert das so, dass man in subclass das erzeugen und setzen kann?
//  /**
//   * Sets the view port settings.
//   *
//   * @param viewPortSettings the new view port settings
//   */
//  public void setViewPortSettings(ViewportSetting viewPortSettings) {
//    this.customViewPort = viewPortSettings;
//  }
// 
//  /* (non-Javadoc)
//   * @see org.mt4j.components.interfaces.IMTComponent3D#hasCustomViewPort()
//   */
//  public boolean hasCustomViewPort(){
//    return this.customViewPort != null;
//  }


  //TODO bubble events up and down hierarchy?
  //@Override
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#processInputEvent(org.mt4j.input.inputData.MTInputEvent)
   */
  public boolean processInputEvent(MTInputEvent inEvt) {
    if (this.isEnabled()){
//      System.out.println("Comp: " + this.getName() + " Evt: " + inEvt);
      //TODO do only if not handled maybe?
      //THIS IS A HACK TO ALLOW Global GESTURE PROCESSORS to send MTGEstureevents TO WORK
      if (inEvt instanceof MTGestureEvent){ 
        this.processGestureEvent((MTGestureEvent)inEvt);
      }else{
        //Fire the same input event to all of this components' input listeners
        this.fireInputEvent(inEvt);
      }
      return false;
    }else{
      return false;
    }
  }

 
  /**
   * Processes gesture events.<br>
   * Fires the specified gesture event to the attached IGestureEventListers of this component.
   *
   * @param gestureEvent the gesture event
   * @return true, if successful
   */
  public boolean processGestureEvent(MTGestureEvent gestureEvent){
    this.gestureEvtSupport.fireGestureEvt(gestureEvent);
//    System.out.println("processGestureEvent on obj: " + this.getName() + " gestureEvent source: " + gestureEvent.getSource() +" ID: " +  gestureEvent.getId());
    return false;
  }
 

  /**
   * Checks if is composite.
   * @return true, if is composite
   */
  public boolean isComposite() {
    return composite;
  }

  /**
   * Setting a components <code>setComposite</code> to 'true' will result in
   * THIS component getting picked and returned
   * when a child of this component is picked. So this component sort of consumes all picking
   * of its children.
   * This behaviour is desireable if we have a component with children that should be treated
   * as one component as a whole by gestures etc.
   *
   * @param composite the composite
   */
  public void setComposite(boolean composite) {
    this.composite = composite;
  }


  /**
   * Gets the controller.
   * @return the controller
   */
  public IMTController getController() {
    return controller;
  }


  /**
   * This attaches a controller object to the component.
   * The controller's update method is called everytime the component's
   * updateComponent method is called. This allows to update the component from the outside,
   * without extending the component and overriding its update method.
   *
   * @param controller the controller
   *
   * @return the old IMT controller (may be null)
   */
  public IMTController setController(IMTController controller) {
    IMTController oldController = this.controller;
    this.controller = controller;
    return oldController;
  }
 
 
  /* (non-Javadoc)
   * @see org.mt4j.components.interfaces.IMTComponent#isGestureAllowed(java.lang.Class)
   */
  public boolean isGestureAllowed(Class<? extends IInputProcessor> c){
    return this.allowedGestures.contains(c);
  }
 
  /**
   * Sets the gesture allowance.
   * @param c the gesture processors class
   * @param allowed allowance
   */
  public void setGestureAllowance(Class<? extends IInputProcessor> c, boolean allowed){
    if (allowed){
      if (!this.allowedGestures.contains(c)){
        this.allowedGestures.add(c);
      }
    }else{
      if (this.allowedGestures.contains(c)){
        this.allowedGestures.remove(c);
      }
    }
  }

  //TODO put in Interface?
  /**
   * Checks if this component is contained in the specified viewing frustum (is currently visible).
   * @param frustum the frustum
   *
   * @return true, if is contained in
   */
  public boolean isContainedIn(IFrustum frustum){
    //Check if bounds are contained in the frustum
    //if shape has no boundingshape return true by default
    if (this.hasBounds()){
      return this.getBounds().isContainedInFrustum(frustum);
    }else{
      return true;
    }
  }
 
 
  /**
   * Re orthogonalizes the components local matrix. As we use incremental matrix operations, floating
   * point errors can add up and lead to loss of precision and matrix orthogonality. This method
   * re-orthogonalizes the matrix.
   * <br>- EXPERIMENTAL! - I think that this will destroy any shearing of the matrix
   * <br>- EXPENSIVE OPERATION!
   */
  public void reOrthogonalize(){
//    Matrix local = this.getLocalMatrix();
//    Vector3D trans = new Vector3D();
//    Vector3D rot = new Vector3D();
//    Vector3D scale = new Vector3D();
//    local.decompose(trans, rot, scale);
    Vector3D scale = this.getLocalMatrix().getScale();
   
//    System.out.println("Det b4: " + getLocalMatrix().determinant());
//    Vector3D v1 = new Vector3D(2,3,4);
//    Vector3D v2 = new Vector3D(v1);
//    v1.transform(this.getLocalMatrix());
   
    Matrix m = new Matrix(this.getLocalMatrix());
//        m.orthonormalizeLocal();
    //can we use 3x3 otrhogonalization on a 4x4 matrix just using the middle part?
    //-seems yes
    m.orthonormalizeUpperLeft();
        //Re-Apply scale because its removed at orthonormalization
//        m.mult(Matrix.getScalingMatrix(Vector3D.ZERO_VECTOR, scale.x, scale.y, scale.z), m);
        m.scale(scale);
        //Automatically inverts() the localMatrix, so exact inverse again! :)
        this.setLocalMatrix(m);
       
//        v2.transform(this.getLocalMatrix());
//        System.out.println("Diff: " + v2.getSubtracted(v1));
//        logger.debug("Determinant after orthogonalize: " + getLocalMatrix().determinant());
  }
 
 
  /**
   * Sets user data for this component. This mechanism can be
   * used to attach arbitrary information to this component by storing
   * a key and a corresponding value object. The value object can then later
   * be retrieved if the key is provided.
   *
   * @param key the key
   * @param value the value
   * @see #getUserData
   */
  public void setUserData(Object key, Object value){
    if (userData == null){ //lazily initialize map
//      userData = new WeakHashMap<Object, Object>(); //use weak map?
      userData = new HashMap<Object, Object>();
    }
    userData.put(key, value);
  }
 
  /**
   * Gets the user data associated with the specified key.
   * @param key the key
   *
   * @return the user data
   */
  public Object getUserData(Object key){
    if (userData == null){
      return null;
    }
    return userData.get(key);
  }
 
  /* (non-Javadoc)
   * @see java.lang.Object#toString()
   */
  @Override
  public String toString() {
    return "\"" + this.getName() + "\"" + " [" + super.toString() + "]";
  }
   
}
TOP

Related Classes of org.mt4j.components.MTComponent

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.