/**
* Copyright (c) 2003-2009, Xith3D Project Group all rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the 'Xith3D Project Group' nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.xith3d.utility.general;
import java.io.IOException;
import org.jagatoo.input.InputSystem;
import org.jagatoo.input.devices.components.AnalogDeviceComponent;
import org.jagatoo.input.devices.components.DeviceComponent;
import org.jagatoo.input.events.InputEvent;
import org.jagatoo.input.listeners.InputStateListener;
import org.jagatoo.util.arrays.ArrayUtils;
import org.openmali.FastMath;
import org.openmali.vecmath2.Colorf;
import org.openmali.vecmath2.Tuple3f;
import org.xith3d.loaders.models.Model;
import org.xith3d.loaders.models.ModelLoader;
import org.xith3d.loaders.sound.ExtensionSoundLoader;
import org.xith3d.loop.UpdatingThread.TimingMode;
import org.xith3d.loop.opscheduler.OperationScheduler;
import org.xith3d.loop.opscheduler.impl.ScheduledOperationImpl;
import org.xith3d.render.Canvas3D;
import org.xith3d.render.RenderOptions;
import org.xith3d.render.RenderPass;
import org.xith3d.scenegraph.BackgroundSound;
import org.xith3d.scenegraph.GroupNode;
import org.xith3d.scenegraph.PointLight;
import org.xith3d.scenegraph.SceneGraph;
import org.xith3d.scenegraph.Transform3D;
import org.xith3d.scenegraph.TransformGroup;
import org.xith3d.scenegraph.primitives.RectBillboard;
import org.xith3d.scenegraph.utils.ShapeUtils;
import org.xith3d.ui.hud.HUD;
import org.xith3d.ui.hud.utils.HUDFont;
import org.xith3d.ui.hud.widgets.Label;
import org.xith3d.ui.text2d.TextAlignment;
/**
* Displays a small video with the Xith3D logo rotating.
*
* @author Amos Wenger (aka BlueSky)
* @author Marvin Froehlich (aka Qudus)
*/
public class Xith3DLogo
{
public static interface Xith3DLogoFinishListener
{
public void onLogoFinished();
}
private static final HUDFont font;
static
{
HUDFont f = null;
try
{
//Font.TRUETYPE_FONT
f = HUDFont.getFont( Xith3DLogo.class.getClassLoader().getResource( "resources/org/xith3d/fonts/DirtyEgo.ttf" ), HUDFont.PLAIN, 75 );
}
catch ( IOException e )
{
e.printStackTrace();
}
font = f;
}
private Colorf oldCanvasBackgroundColor;
private SceneGraph sceneGraph;
private RenderPass renderPass;
private PointLight light;
private TransformGroup modelTrans;
private BackgroundSound sound;
private HUD hud;
private Label label;
private boolean finished;
private static final float interpolate( float time, float startTime, float endTime, float startValue, float endValue, float preValue, float postValue )
{
if ( time < startTime )
{
return ( preValue );
}
else if ( time <= endTime )
{
return ( startValue + ( endValue - startValue ) * ( time - startTime ) / ( endTime - startTime ) );
}
else
{
return ( postValue );
}
}
private void setupInterpolators( final Canvas3D canvas, final OperationScheduler opScheder )
{
opScheder.scheduleOperation( new ScheduledOperationImpl( true )
{
private long startTime = -1L;
public void update( long gameTime, long frameTime, TimingMode timingMode )
{
if ( finished )
{
this.setAlive( false );
return;
}
if ( startTime == -1L )
{
startTime = gameTime;
}
float time = timingMode.getSecondsAsFloat( gameTime - startTime );
if ( time <= 2.1f )
{
Tuple3f tmp = Tuple3f.fromPool();
modelTrans.getTransform().getRotation( tmp );
tmp.setY( interpolate( time, 0f, 2.1f, FastMath.TWO_PI, 0f, 0f, 0f ) );
modelTrans.getTransform().setRotation( tmp );
modelTrans.getTransform().getTranslation( tmp );
tmp.setZ( interpolate( time, 0f, 2.1f, -50f, -0.5f, -50f, -0.5f ) );
modelTrans.getTransform().setTranslation( tmp );
Tuple3f.toPool( tmp );
}
float alpha = interpolate( time, 2.0f, 3.0f, 1f, 0f, 1f, 0f );
if ( ( time >= 2.0f ) && ( time <= 3.0f ) )
{
label.setTransparency( alpha );
}
canvas.setBackgroundColor( alpha, alpha, alpha );
if ( time <= 4.0f )
{
float lightXPos = interpolate( time, 2.0f, 4.0f, -20f, 50f, -20f, 50f );
light.setLocation( lightXPos, 10f, 0f );
}
else
{
float lightXPos = interpolate( time, 4.0f, 5.0f, 50f, 0f, 50f, 0f );
light.setLocation( lightXPos, 10f, 0f );
}
}
} );
}
private void loadLogoModel( GroupNode parentGroup ) throws IOException
{
light = new PointLight( 1f, 1f, 1f, 0f, 10f, 0f, 0.0005f );
parentGroup.addChild( light );
modelTrans = new TransformGroup();
Model model = ModelLoader.getInstance().loadModel( this.getClass().getClassLoader().getResource( "resources/org/xith3d/models/Xith3DLogo.obj" ) );
modelTrans.addChild( model );
parentGroup.addChild( modelTrans );
}
private void setupSound( GroupNode parentGroup )
{
final String soundFile = "resources/org/xith3d/sounds/Du Rififi a Noubaka - Extrait.ogg";
try
{
this.sound = new BackgroundSound( new ExtensionSoundLoader().loadSound( this.getClass().getClassLoader().getResource( soundFile ) ), 1f );
sound.setEnabled( false );
sound.setLoopType( BackgroundSound.INFINITE_LOOPS );
parentGroup.addChild( sound );
}
catch ( IOException e )
{
System.err.println( "Could not find sound file " + soundFile );
}
}
private HUD createHUD()
{
HUD hud = new HUD( 800, 600, 800f );
label = new Label( 800f, 175f, "Xith3D\nEnjoyable creativity", font, new Colorf( 0.8f, 0.0f, 0.0f ), TextAlignment.CENTER_CENTER );
label.setTransparency( 1.0f );
hud.getContentPane().addWidget( label, ( hud.getResX() - label.getWidth() ) / 2f, hud.getResY() - label.getHeight() - 10f );
return ( hud );
}
protected void end( final Canvas3D canvas, final Xith3DLogoFinishListener finishListener )
{
sound.setEnabled( false );
canvas.setBackgroundColor( oldCanvasBackgroundColor );
sceneGraph.removeHUD( hud );
sceneGraph.removeRenderPass( renderPass );
if ( finishListener != null )
{
finishListener.onLogoFinished();
}
}
protected void end( final OperationScheduler opScheder, final Canvas3D canvas, final Xith3DLogoFinishListener finishListener )
{
finished = true;
final RectBillboard blackFader = new RectBillboard( 100f, 100f, new Colorf( 0f, 0f, 0f, 0f ) );
TransformGroup tg = new TransformGroup( 0f, 0f, 8.9f );
tg.addChild( blackFader );
renderPass.getBranchGroup().addChild( tg );
opScheder.scheduleOperation( new ScheduledOperationImpl( true )
{
private long startTime = -1L;
public void update( long gameTime, long frameTime, TimingMode timingMode )
{
if ( startTime == -1L )
{
startTime = gameTime;
}
float time = timingMode.getSecondsAsFloat( gameTime - startTime );
if ( time <= 0.5f )
{
float alpha = interpolate( time, 0f, 0.5f, 0f, 1f, 0f, 1f );
ShapeUtils.setTransparency( blackFader, 1f - alpha );
label.setTransparency( alpha );
//sound.setVolume( 1f - alpha ); // TODO: Check, why this doesn't work!
}
else
{
this.setAlive( false );
end( canvas, finishListener );
}
}
} );
}
/**
* Plays the Xith3DLogo video on the specified canvas.
* This video has a short music, it lasts ~10 seconds
* and can be cut by the user if he presses any key.
*
* @param opScheder
* @param canvas
* @param stopComponents an array of KeyCodes, that will cause the logo to stop playing
* @param inputSystem
* @param finishListener
*/
public void play( final OperationScheduler opScheder, final Canvas3D canvas, final DeviceComponent[] stopComponents, final InputSystem inputSystem, final Xith3DLogoFinishListener finishListener )
{
if ( finished )
{
throw new IllegalStateException( "This logo has already been finished!" );
}
this.oldCanvasBackgroundColor = new Colorf( canvas.getBackgroundColor() );
sceneGraph.addRenderPass( renderPass );
sceneGraph.addHUD( hud );
sound.setEnabled( true );
// Set up interpolators
setupInterpolators( canvas, opScheder );
inputSystem.addInputStateListener( new InputStateListener()
{
public void onInputStateChanged( InputEvent e, DeviceComponent comp, int delta, int state )
{
if ( delta <= 0 )
return;
boolean isStopComp = false;
if ( stopComponents == null )
{
/*
* If no stop-component has explicitly been specified,
* all components (keys, mouse-buttons, controller-buttons)
* are used as stop-component. But we exclude analog devices
* like mouse axes or joystick-axis, etc.
*/
if ( ( comp != null ) && !( comp instanceof AnalogDeviceComponent ) )
{
isStopComp = true;
}
}
else if ( ArrayUtils.contains( stopComponents, comp, true ) )
{
/*
* If stop-components have explicitly been specified,
* we simply check, if the component of the changed state
* is on of them.
*/
isStopComp = true;
}
if ( isStopComp )
{
inputSystem.removeInputStateListener( this );
Xith3DLogo.this.end( opScheder, canvas, finishListener );
}
}
} );
}
/**
* Plays the Xith3DLogo video on the specified canvas.
* This video has a short music, it lasts ~10 seconds
* and can be cut by the user if he presses any key.
*
* @param opScheder
* @param canvas
* @param stopComponents an array of KeyCodes, that will cause the logo to stop playing
* @param finishListener
*/
public void play( final OperationScheduler opScheder, final Canvas3D canvas, final DeviceComponent[] stopComponents, final Xith3DLogoFinishListener finishListener )
{
play( opScheder, canvas, stopComponents, InputSystem.getInstance(), finishListener );
}
/**
* Plays the Xith3DLogo video on the specified canvas.
* This video has a short music, it lasts ~10 seconds
* and can be cut by the user if he presses any key.
*
* @param opScheder
* @param canvas
* @param finishListener
*/
public void play( final OperationScheduler opScheder, final Canvas3D canvas, final Xith3DLogoFinishListener finishListener )
{
play( opScheder, canvas, null, finishListener );
}
public Xith3DLogo( SceneGraph sceneGraph ) throws IOException
{
this.sceneGraph = sceneGraph;
this.renderPass = RenderPass.createPerspective();
Transform3D viewTransform = new Transform3D();
viewTransform.lookAt( 0f, 0f, 10f,
0f, 0f, 0f,
0f, 1f, 0f
);
renderPass.getConfig().setBackClipDistance( 60f );
renderPass.getConfig().setFrontClipDistance( 1f );
renderPass.getConfig().setViewTransform( viewTransform );
renderPass.getConfig().setRenderOptions( new RenderOptions() );
renderPass.getConfig().getRenderOptions().setLightingEnabled( true );
loadLogoModel( renderPass.getBranchGroup() );
setupSound( renderPass.getBranchGroup() );
//sceneGraph.addRenderPass( renderPass );
this.hud = createHUD();
//sceneGraph.addHUD( hud );
finished = false;
}
}