Package org.mt4j.components.visibleComponents.widgets

Source Code of org.mt4j.components.visibleComponents.widgets.MTSceneTexture

/***********************************************************************
* mt4j Copyright (c) 2008 - 2009 Christopher 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.visibleComponents.widgets;

import java.util.HashMap;

import javax.media.opengl.GL;

import org.mt4j.MTApplication;
import org.mt4j.components.visibleComponents.shapes.MTRectangle;
import org.mt4j.input.inputData.AbstractCursorInputEvt;
import org.mt4j.input.inputData.InputCursor;
import org.mt4j.input.inputData.MTInputEvent;
import org.mt4j.input.inputProcessors.globalProcessors.AbstractGlobalInputProcessor;
import org.mt4j.input.inputProcessors.globalProcessors.CursorTracer;
import org.mt4j.sceneManagement.Iscene;
import org.mt4j.util.MT4jSettings;
import org.mt4j.util.math.Plane;
import org.mt4j.util.math.Tools3D;
import org.mt4j.util.math.Vector3D;
import org.mt4j.util.math.Vertex;
import org.mt4j.util.opengl.GLFboStack;
import org.mt4j.util.opengl.GLFBO;
import org.mt4j.util.opengl.GLStencilUtil;
import org.mt4j.util.opengl.GLTexture;

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

/**
* The Class MTSceneTexture. This class allows to display a scene from within another scene.
* The scene will be displayed as a textured rectangle. This is only supported using the OpenGL renderer
* and a graphics card supporting the frame buffer object extension.
*
* @author Christopher Ruff
*/
public class MTSceneTexture extends MTRectangle {

  private GLFBO fbo;
  private Iscene scene;
  private MTApplication app;
 
  private Plane p;
  private HashMap<InputCursor, InputCursor> oldCursorToNewCursor;
 
  //TODO kind of a hack
  private long lastUpdateTime;
 
  private boolean maximized;
 
  private MTSceneMenu sceneMenu;
 
  public MTSceneTexture(MTApplication pa, float x,  float y, Iscene theScene){
    this(pa, x, y, Math.round(MT4jSettings.getInstance().getWindowWidth() * 0.6f), Math.round(MT4jSettings.getInstance().getWindowHeight() * 0.6f), theScene);
  }

  public MTSceneTexture(MTApplication pa, float x,  float y, int fboWidth, int fboHeight, Iscene theScene){
    super(x, y, 0, MT4jSettings.getInstance().getWindowWidth(), MT4jSettings.getInstance().getWindowHeight(), pa);
   
    this.scene = theScene;
    this.app = pa;
    this.maximized = false;
   
    //Disable the scene's global input processors. We will be redirecting the input
    //from the current scene to the window scene
    pa.getInputManager().disableGlobalInputProcessors(scene);
   
    //Create FBO
//    this.fbo = new GLFBO(pa, pa.width, pa.height);
    this.fbo = new GLFBO(pa, fboWidth, fboHeight);
   
    //Attach texture to FBO to draw into
    GLTexture tex = fbo.addNewTexture();
   
    //Invert y texture coord (FBO texture is flipped)
    Vertex[] v = this.getVerticesLocal();
    for (int i = 0; i < v.length; i++) {
      Vertex vertex = v[i];
      if (vertex.getTexCoordV() == 1.0f){
        vertex.setTexCoordV(0.0f);
      }else if (vertex.getTexCoordV() == 0.0f){
        vertex.setTexCoordV(1.0f);
      }
    }
    this.setVertices(v);
   
    //Apply the texture to this component
    this.setTexture(tex);
   
//    //Scale texture coords if using TEXTURE_RECTANGLE_ARB extension
//    if (!Tools3D.isPowerOfTwoDimension(tex)){
//      Tools3D.scaleTextureCoordsForRectModeFromNormalized(tex, this.getGeometryInfo().getVertices());
//      this.setTextureMode(PConstants.IMAGE);
//      //Update the texture buffer!
//      this.getGeometryInfo().updateTextureBuffer(this.isUseVBOs());
//    }
   
    //REMOVE?
    this.setUseDirectGL(true);
//    this.setBoundsPickingBehaviour(BOUNDS_CHECK_THEN_GEOMETRY_CHECK);
   
    //Plane to check intersections with
    this.p = new Plane(new Vector3D(x,y,0) , new Vector3D(0,0,1));
    //Mapping of this scenes inputCursors to the newly created cursors of the window scene
    this.oldCursorToNewCursor = new HashMap<InputCursor, InputCursor>();
   
    this.lastUpdateTime = 0;
   
    //Draw this component and its children above
    //everything previously drawn and avoid z-fighting
//    this.setDepthBufferDisabled(true); //FIXME this wont work well when the scene is 3D!
   
//    scene.getCanvas().setDepthBufferDisabled(false);
   
    getFbo().clear(true, 0, 0, 0, 0, true);
   
    pa.invokeLater(new Runnable() {
      //Do the next frame because if MTSceneTexture is created in the first scene,
      //addScene() will make the scene texture scene the current scene which we dont want!
      public void run() {
        //Add it to the scene if it isnt already -> we cant destroy the scene later if it isnt in the app
        app.addScene(scene);   
      }
    });
    
  }
 
 

  @Override
  public void updateComponent(long timeDelta) {
    super.updateComponent(timeDelta);
    this.lastUpdateTime = timeDelta;
  }
 
 

  @Override
  public void drawComponent(PGraphics g){
    PGraphicsOpenGL pgl = (PGraphicsOpenGL)g;
    GL gl = pgl.gl;

//    boolean b = false;
//    if (GLStencilUtil.getInstance().isClipActive()){
//      GLStencilUtil.getInstance().endClipping(gl);
//      b = true;
//    }
     
     
    fbo.startRenderToTexture();
      //Change blending mode to avoid artifacts from alpha blending at antialiasing for example
//      gl.glBlendFuncSeparate(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA, GL.GL_ZERO, GL.GL_ONE);
      gl.glBlendFuncSeparate(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA, GL.GL_ONE, GL.GL_ONE_MINUS_SRC_ALPHA);
     
//      /*
      boolean clipping = false;
      if (GLStencilUtil.getInstance().isClipActive()){
        clipping = true;
        gl.glPushAttrib(GL.GL_STENCIL_BUFFER_BIT);
        gl.glClearStencil(GLStencilUtil.getInstance().stencilValueStack.peek());
        gl.glClear(GL.GL_STENCIL_BUFFER_BIT);
        //      gl.glDisable(GL.GL_STENCIL_TEST);
      }
//      */
     
//      gl.glEnable(gl.GL_ALPHA_TEST);
//      gl.glAlphaFunc(gl.GL_GREATER, 0.0f);
//      gl.glDisable(gl.GL_ALPHA_TEST);
      //Draw scene to texture
      scene.drawAndUpdate(pgl, this.lastUpdateTime);
     
//      /*
      if (clipping){
        gl.glPopAttrib();
      }
//       */
//      GLStencilUtil.getInstance().endClipping(gl, this);
    fbo.stopRenderToTexture();
     
    if (GLFboStack.getInstance().peekFBO() == 0)
      gl.glBlendFunc(GL.GL_SRC_ALPHA, GL.GL_ONE_MINUS_SRC_ALPHA); //Restore default blend mode //FIXME TEST -> neccessary?
   
    //FIXME NOT NEEDED!? sufficient to call glGenerateMipmapEXT at texture creation!?
    //TODO I actually think its necessary to call each time after rendering to the texture! But only for POT dimensions!?
    /*
    GLTexture tex = (GLTexture) this.getTexture();
    gl.glBindTexture(tex.getTextureTarget(), tex.getTextureID());
    gl.glGenerateMipmapEXT(tex.getTextureTarget());
    gl.glBindTexture(tex.getTextureTarget(), 0);
    */
    super.drawComponent(g);
  }
 
  /*TODO
   * - fehler wenn gedreht x,y, axis und dann scale - wegen shearing?
   * - fehler scheint von rotation zu kommen nachdem rotiert x,y,
   *
   * - progressbar sizes wrong bei 512,512
   *
   * - FBO: mehrere texture targets wenn supported erm�glichen
   *
   * - FBO: multisampling fbo optional wenn supported machen siehe glgraphicsoffscreen
   *
   * - FBO: bei RECTANGLE dimensions keine mipmaps m�glich??
   *
   * - FBO: hardware fbo mit glCopyTex2D
   *
   * - nur sceneDrawAndUpdate() wenn sich was ver�ndert hat - sonst kann man einfach alte textur lassen! scene.invalidate()?
   *
   * (- wenn camera changed richtig picken in scene)
   * */
 

  @Override
  public boolean processInputEvent(MTInputEvent inEvt) {
    //We have to retarget inputevents for this component to the windowed scene
    if (inEvt instanceof AbstractCursorInputEvt){
      AbstractCursorInputEvt posEvt = (AbstractCursorInputEvt)inEvt;
      float x = posEvt.getPosX();
      float y = posEvt.getPosY();
     
      float newX = 0;
      float newY = 0;
      //Check intersection with infinite plane, this rect lies in
      Vector3D interSP = p.getIntersectionLocal(this.globalToLocal(Tools3D.getCameraPickRay(app, this, x, y)));
      if (interSP != null){
        //System.out.println(interSP);
        newX = interSP.x;
        newY = interSP.y;
      }
     
      AbstractCursorInputEvt newEvt = null;
      switch (posEvt.getId())
      {
      case AbstractCursorInputEvt.INPUT_DETECTED:{
        InputCursor newCursor = new InputCursor();
        try {
          newEvt = (AbstractCursorInputEvt) posEvt.clone();
          newEvt.setPositionX(newX);
          newEvt.setPositionY(newY);
//          newCursor.addEvent(newEvt);
          newEvt.setCursor(newCursor);
          newEvt.preFire();
          //Note: We dont set a target for the event! this can be
          //handled newly in the wondowed scenes InputRetargeter processor
        } catch (CloneNotSupportedException e) {
          e.printStackTrace();
        }
        this.oldCursorToNewCursor.put(posEvt.getCursor(), newCursor);
        //TODO checken ob cursor bereits events enth�lt - �berhaupt m�glich?..
        //ELSE -> CLONE AND ADD ALL OLD EVENTS TO THE NEW CURSOR!
      }break;
      case AbstractCursorInputEvt.INPUT_UPDATED:{
        InputCursor newCursor = this.oldCursorToNewCursor.get(posEvt.getCursor());
        if (newCursor != null){
          try {
            newEvt = (AbstractCursorInputEvt) posEvt.clone();
            newEvt.setPositionX(newX);
            newEvt.setPositionY(newY);
//            newCursor.addEvent(newEvt);
            newEvt.setCursor(newCursor);
            newEvt.preFire();
          } catch (CloneNotSupportedException e) {
            e.printStackTrace();
          }
        }else{
          System.err.println("Couldnt find new cursor!");
        }
      }break;
      case AbstractCursorInputEvt.INPUT_ENDED:{
        InputCursor newCursor = this.oldCursorToNewCursor.remove(posEvt.getCursor());
        if (newCursor != null){
          try {
            newEvt = (AbstractCursorInputEvt) posEvt.clone();
            newEvt.setPositionX(newX);
            newEvt.setPositionY(newY);
//            newCursor.addEvent(newEvt);
            newEvt.setCursor(newCursor);
            newEvt.preFire();
          } catch (CloneNotSupportedException e) {
            e.printStackTrace();
          }
        }else{
          System.err.println("Couldnt find new cursor!");
        }
      }break;
      default:
        break;
      }
     
      AbstractCursorInputEvt evtToFire = (newEvt != null) ?
          newEvt :
          posEvt;
     
      //Send similar event to the windowed scenes global input processors
      AbstractGlobalInputProcessor[] globalAnalyzer = app.getInputManager().getGlobalInputProcessors(scene);
      for (int i = 0; i < globalAnalyzer.length; i++) {
        AbstractGlobalInputProcessor a = globalAnalyzer[i];
        if (!(a instanceof CursorTracer)){
          //Hack because actually processors are disabled so they dont recieve
          //input directly, so we dont call processInputEvt()!
          a.processInputEvtImpl(evtToFire)
        }
       
      }
      return false;
    }else{
      return super.processInputEvent(inEvt);
    }
//    return super.processInputEvent(inEvt);
//    scene.getCanvas().processInputEvent(inEvt);
//    return true;
  }
 
 
//  @Override
//  public boolean processGestureEvent(MTGestureEvent gestureEvent) {
//    return super.processGestureEvent(gestureEvent);
//  }

 
  public Iscene getScene(){
    return this.scene;
  }


  public GLFBO getFbo() {
    return fbo;
  }

 
  public void addSceneMenu(){
    if (sceneMenu == null){
      float menuWidth = 64;
      float menuHeight = 64;
//      this.sceneMenu = new MTSceneMenu(this, app.width-menuWidth/2f, 0-menuHeight/2f, menuWidth, menuHeight, app);
//      this.sceneMenu = new MTSceneMenu(this, app.width-menuWidth, 0, menuWidth, menuHeight, app);
      this.sceneMenu = new MTSceneMenu(this, app.width-menuWidth, app.height-menuHeight, menuWidth, menuHeight, app);
      this.sceneMenu.setVisible(false);
    }
   
    this.sceneMenu.addToScene();
    if (maximized){
      this.sceneMenu.setVisible(true);
    }
  }
 
  public void destroySceneMenu(){
    this.sceneMenu.removeFromScene();
    this.sceneMenu.destroy();
    this.sceneMenu = null;
  }
 

  /**
   * Maximize.
   */
  public void maximize() {
    app.pushScene();
    app.addScene(scene);
    if (app.changeScene(scene)){
      maximized = true;
     
      this.addSceneMenu();
    }
  }
 
  /**
   * Restore.
   *
   * @return true, if successful
   */
  public boolean restore(){
    if(app.popScene() /*&& app.removeScene(scene)*/){
      maximized = false;
     
      //FIXME TEST remove the in-scene window menu
      if (sceneMenu != null){
        this.sceneMenu.setVisible(false);
        this.sceneMenu.removeFromScene();
      }
      return true;
    }else{
      return false;
    }
  }
 

  @Override
  protected void destroyComponent() {
    super.destroyComponent();
   
    this.getFbo().destroy();
   
    //Restore to pop to another scene before destroying this
    if (maximized){
      restore();
    }
   
//    //FIXME Destroy and remove scene -> can we safely do this? if the scene is used elsewhere -> problem
//    //Problem if sceneTexture is used in transitions and destroyed after -> scene is destroyed!!
    //But if we dont destroy it the scene could linger around forever if used elsewhere!
//    scene.destroy();
   
    //Destroy scene Menu
    if (sceneMenu != null){
      this.sceneMenu.removeFromScene();
      sceneMenu.destroy();
    }
  }
 
 
 
  //TODO if windowed
  //- maximize
  //- close
 
  //TODO
  //IF CLOSE:
  //popScene()
  //destroy() scene window
  //remove scene from MTApp
  //scene.destroy()
 
  //IF RESTORE:
  //popScene();
  //remove window menu from scene's canvas
 

 
 
 
 
}
TOP

Related Classes of org.mt4j.components.visibleComponents.widgets.MTSceneTexture

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.