/***********************************************************************
* 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.sceneManagement;
import java.util.ArrayDeque;
import java.util.Deque;
import java.util.Iterator;
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.MTApplication;
import org.mt4j.components.MTCanvas;
import org.mt4j.input.inputProcessors.globalProcessors.AbstractGlobalInputProcessor;
import org.mt4j.input.inputProcessors.globalProcessors.InputRetargeter;
import org.mt4j.sceneManagement.transition.ITransition;
import org.mt4j.util.MT4jSettings;
import org.mt4j.util.MTColor;
import org.mt4j.util.camera.Icamera;
import org.mt4j.util.camera.MTCamera;
import org.mt4j.util.math.Tools3D;
import processing.core.PGraphics;
/**
* A class representing a scene in a program or game.
* It has its own main canvas and global input processors.
*
* @author Christopher Ruff
*/
public abstract class AbstractScene implements Iscene {
/** The Constant logger. */
private static final Logger logger = Logger.getLogger(AbstractScene.class.getName());
static{
// logger.setLevel(Level.ERROR);
// logger.setLevel(Level.WARN);
// logger.setLevel(Level.DEBUG);
logger.setLevel(Level.INFO);
SimpleLayout l = new SimpleLayout();
ConsoleAppender ca = new ConsoleAppender(l);
logger.addAppender(ca);
}
/** The scene cam. */
private Icamera sceneCam;
/** The main canvas. */
private MTCanvas mainCanvas;
/** The mt application. */
private MTApplication mtApplication;
/** The name. */
private String name;
/** The pre draw actions. */
private Deque<IPreDrawAction> preDrawActions;
/** The clear color. */
private MTColor clearColor;
/** The gl clear color. */
private MTColor glClearColor;
/** The clear before draw. */
private boolean clearBeforeDraw;
/** The transition. */
private ITransition transition;
/**
* The Constructor.
*
* @param mtApplication the mt application
* @param name the name
*/
public AbstractScene(MTApplication mtApplication, String name) {
super();
this.name = name;
this.mtApplication = mtApplication;
this.sceneCam = new MTCamera(mtApplication);
this.sceneCam.update();
this.sceneCam.setZoomMinDistance(60);
this.mainCanvas = new MTCanvas(mtApplication, name + " - Main Canvas", sceneCam);
// preDrawActions = new LinkedList<IPreDrawAction>();
preDrawActions = new ArrayDeque<IPreDrawAction>();
this.registerDefaultGlobalInputProcessors();
this.clearBeforeDraw = true;
this.setClearColor(new MTColor(0,0,0, 255));
}
/**
* Register default global input processors. Can be overridden for custom behaviour.
*/
protected void registerDefaultGlobalInputProcessors(){
InputRetargeter inputRetargeter = new InputRetargeter(this.getCanvas());
inputRetargeter.addProcessorListener(this.getCanvas());
this.registerGlobalInputProcessor(inputRetargeter);
// this.registerGlobalInputProcessor(new InputRetargeter(this.getCanvas()));
}
/**
* Is invoked on a scene just before it is set to be the currently active scene.
*/
abstract public void init() ;
/*
public void update(long timeDelta) {
this.getMainCanvas().update(timeDelta);
}
*/
/*//Replaces by drawAndUpdate
public void draw() {
// this.getMainCanvas().draw();
this.getMainCanvas().drawAndUpdateCanvas(0);
}
*/
/* (non-Javadoc)
* @see mTouch.sceneManagement.Iscene#drawAndUpdate(long)
*/
public void drawAndUpdate(PGraphics graphics, long timeDelta){
//Process preDrawActions
synchronized (preDrawActions) {
for (Iterator<IPreDrawAction> iter = preDrawActions.iterator(); iter.hasNext();) {
IPreDrawAction action = (IPreDrawAction) iter.next();
action.processAction();
if (!action.isLoop()){
iter.remove();
}
}
}
//Clear the background
if (this.clearBeforeDraw){
this.clear(graphics);
}
//Draw and update canvas
this.getCanvas().drawAndUpdateCanvas(graphics, timeDelta);
}
protected void clear(PGraphics graphics){
if (MT4jSettings.getInstance().isOpenGlMode()){
GL gl = Tools3D.getGL(mtApplication);
gl.glClearColor(this.glClearColor.getR(), this.glClearColor.getG(), this.glClearColor.getB(), this.glClearColor.getAlpha());
gl.glClear(
GL.GL_COLOR_BUFFER_BIT
|
GL.GL_DEPTH_BUFFER_BIT
);
// gl.glDepthMask(false);
// gl.glDisable(GL.GL_DEPTH_TEST);
}else{
graphics.background(this.clearColor.getR(), this.clearColor.getG(), this.clearColor.getB(), this.clearColor.getAlpha());
}
}
/**
* Gets called on the current scene just before the current scene gets changed to another scene.
*/
abstract public void shutDown();
/**
* Sets the clear color to use when the screen is cleared each frame
* before drawing.
*
* @param clearColor the new clear color
*/
public void setClearColor(MTColor clearColor){
this.clearColor = clearColor;
this.glClearColor = new MTColor(this.clearColor.getR()/255f, this.clearColor.getG()/255f, this.clearColor.getB()/255f, this.clearColor.getAlpha()/255f);
}
/**
* Gets the clear color.
*
* @return the clear color
*/
public MTColor getClearColor(){
return this.clearColor;
}
/**
* Sets the scene to be cleared each frame or not.
*
* @param clearScreen the new clear
*/
public void setClear(boolean clearScreen){
this.clearBeforeDraw = clearScreen;
}
/**
* Checks if the scene is being cleared each frame.
*
* @return true, if is clear
*/
public boolean isClear(){
return this.clearBeforeDraw;
}
/* (non-Javadoc)
* @see mTouch.sceneManagement.Iscene#getMainCanvas()
*/
public MTCanvas getCanvas() {
return mainCanvas;
}
/* (non-Javadoc)
* @see mTouch.sceneManagement.Iscene#getSceneCam()
*/
public Icamera getSceneCam() {
return sceneCam;
}
/**
* Sets the scene cam. This is the camera which gets attached
* to the scene's canvas.
*
* @param sceneCam the scene cam
*/
public void setSceneCam(Icamera sceneCam) {
this.sceneCam = sceneCam;
this.getCanvas().attachCamera(sceneCam);
}
/**
* Gets the MT application instance.
*
* @return the mT application
*/
public MTApplication getMTApplication(){
return this.mtApplication;
}
/* (non-Javadoc)
* @see mTouch.sceneManagement.Iscene#getName()
*/
public String getName() {
return name;
}
/**
* Sets the name.
*
* @param name the name
*/
public void setName(String name) {
this.name = name;
}
// * By default, the scene's canvas will be listening to the events of the registered
// * global input processor so the events will be delivered to the canvas object first.
/**
* Registers a global input processor with the current scene.
* The global input processor will then recieve input events from all input sources
* as long as this scene is active.
* We can then add our own listeners to the global input processor.
*
* @param processor the processor
*/
public void registerGlobalInputProcessor(AbstractGlobalInputProcessor processor){
//Let the inputprocessor listen to the inputsources
mtApplication.getInputManager().registerGlobalInputProcessor(this, processor);
//Set this scenes main canvas to listen to the inputprocessor
// processor.addProcessorListener(this.getCanvas()); //FIXME TESTWISE DISABLED
}
/**
* Unregisters a global input processor.
*
* @param processor the processor
*/
public void unregisterGlobalInputProcessor(AbstractGlobalInputProcessor processor){
mtApplication.getInputManager().unregisterGlobalInputProcessor(processor);
processor.removeProcessorListener(this.getCanvas()); //FIXME can be removed now..?
}
/**
* Gets the global input processors.
*
* @return the global input processors
*/
public AbstractGlobalInputProcessor[] getGlobalInputProcessors(){
return mtApplication.getInputManager().getGlobalInputProcessors(this);
}
/**
* Registers an action to be processed before the next frame
* in the main drawing thread.
*
* @param action the action
*/
public void registerPreDrawAction(IPreDrawAction action){
synchronized (preDrawActions) {
this.preDrawActions.addLast(action);
}
}
/**
* Unregisters an PreDrawAction.
*
* @param action the action
*/
public void unregisterPreDrawAction(IPreDrawAction action){
synchronized (preDrawActions) {
this.preDrawActions.remove(action);
}
}
/* (non-Javadoc)
* @see org.mt4j.sceneManagement.Iscene#getTransition()
*/
public ITransition getTransition(){
return this.transition;
}
/**
* Sets the transition effect to use when a scene change takes
* place from this scene to another scene.
*
* @param transition the new transition
*/
public void setTransition(ITransition transition){
this.transition = transition;
}
/**
* Destroys the scene. Call this if the scene definitely isnt going to be used anymore.
* The scene can only be destroyed if it was added to the application and it isnt the currently
* active scene.
* - Destroys the scene's canvas
* - removes the global input listeners from the input sources
*
* @return true, if successful
*/
public boolean destroy(){
//If not already done, remove the scene from the mt application (only if not current scene)
if (this.mtApplication.removeScene(this)){
this.mtApplication.invokeLater(new Runnable() {
public void run() {
//Remove all global input processors of this scene from listening the the input sources
AbstractGlobalInputProcessor[] inputProcessors = getGlobalInputProcessors();
for (int i = 0; i < inputProcessors.length; i++) {
AbstractGlobalInputProcessor abstractGlobalInputProcessor = inputProcessors[i];
unregisterGlobalInputProcessor(abstractGlobalInputProcessor);
}
}
});
//Destroy the scene's canvas
this.getCanvas().destroy();
preDrawActions.clear();
logger.info("Destroyed scene: " + this.getName());
return true;
}else{
//Try to destroy if removal of the scene failed because of a pending transition.
this.mtApplication.destroySceneAfterTransition(this);
logger.warn("Cant destroy currently active scene! (" + this.getName() + ") -> If scene in transition, trying to destroy afterwards.");
return false;
}
}
}