/**
* Copyright (C) 2009-2014 Cars and Tracks Development Project (CTDP).
*
* 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 2
* 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, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
package net.ctdp.rfdynhud.widgets.standard.startinglight;
import java.io.IOException;
import net.ctdp.rfdynhud.gamedata.GamePhase;
import net.ctdp.rfdynhud.gamedata.LiveGameData;
import net.ctdp.rfdynhud.gamedata.ScoringInfo;
import net.ctdp.rfdynhud.properties.FloatProperty;
import net.ctdp.rfdynhud.properties.ImageProperty;
import net.ctdp.rfdynhud.properties.IntProperty;
import net.ctdp.rfdynhud.properties.PropertiesContainer;
import net.ctdp.rfdynhud.properties.PropertyLoader;
import net.ctdp.rfdynhud.render.DrawnStringFactory;
import net.ctdp.rfdynhud.render.ImageTemplate;
import net.ctdp.rfdynhud.render.TextureImage2D;
import net.ctdp.rfdynhud.util.PropertyWriter;
import net.ctdp.rfdynhud.util.SubTextureCollector;
import net.ctdp.rfdynhud.valuemanagers.Clock;
import net.ctdp.rfdynhud.values.EnumValue;
import net.ctdp.rfdynhud.values.IntValue;
import net.ctdp.rfdynhud.widgets.base.widget.Widget;
import net.ctdp.rfdynhud.widgets.base.widget.__WPrivilegedAccess;
import net.ctdp.rfdynhud.widgets.standard._util.StandardWidgetSet;
/**
* The {@link StartingLightWidget} displays a starting light for the race.
*
* @author Marvin Froehlich (CTDP)
*/
public class StartingLightWidget extends Widget
{
private static final int MAX_LIGHTS = 5;
private TextureImage2D offImage = null;
private final ImageProperty offImageProp = new ImageProperty( "offImageName", "standard/starting_light_off.png" )
{
@Override
public void setValue( Object value )
{
super.setValue( value );
offImage = null;
onImage = null;
}
};
private TextureImage2D onImage = null;
private final ImageProperty onImageProp = new ImageProperty( "onImageName", "standard/starting_light_on.png" )
{
@Override
public void setValue( Object value )
{
super.setValue( value );
offImage = null;
onImage = null;
}
};
private final IntProperty numRows = new IntProperty( "numRows", 2, 1, 4 );
private final FloatProperty visibleTimeAfterLightsOff = new FloatProperty( "visibleTimeAfterLightsOff", "visTimeAfterOff", 4.0f, 0f, 60f, false );
private final EnumValue<GamePhase> gamePhase = new EnumValue<GamePhase>();
private final IntValue numLights = new IntValue();
private float visibleTime = -1f;
public StartingLightWidget()
{
super( StandardWidgetSet.INSTANCE, StandardWidgetSet.WIDGET_PACKAGE_TIMING, 11.328125f, true, 8.3984375f, true );
}
@Override
protected boolean hasText()
{
return ( false );
}
/**
* {@inheritDoc}
*/
@Override
public void saveProperties( PropertyWriter writer ) throws IOException
{
super.saveProperties( writer );
writer.writeProperty( offImageProp, "The image name for the off-lights." );
writer.writeProperty( onImageProp, "The image name for the on-lights." );
writer.writeProperty( numRows, "The number of light rows." );
writer.writeProperty( visibleTimeAfterLightsOff, "Amount of seconds, the Widget stays visible after all lights have gone off." );
}
/**
* {@inheritDoc}
*/
@Override
public void loadProperty( PropertyLoader loader )
{
super.loadProperty( loader );
if ( loader.getSourceVersion().getBuild() < 70 )
{
if ( loader.getCurrentKey().equals( "initialVisibility" ) )
__WPrivilegedAccess.setInputVisible( this, true );
}
if ( loader.loadProperty( offImageProp ) );
else if ( loader.loadProperty( onImageProp ) );
else if ( loader.loadProperty( numRows ) );
else if ( loader.loadProperty( visibleTimeAfterLightsOff ) );
}
/**
* {@inheritDoc}
*/
@Override
public void getProperties( PropertiesContainer propsCont, boolean forceAll )
{
super.getProperties( propsCont, forceAll );
propsCont.addGroup( "Misc" );
propsCont.addProperty( offImageProp );
propsCont.addProperty( onImageProp );
propsCont.addProperty( numRows );
propsCont.addProperty( visibleTimeAfterLightsOff );
}
@Override
public void onCockpitEntered( LiveGameData gameData, boolean isEditorMode )
{
super.onCockpitEntered( gameData, isEditorMode );
gamePhase.reset();
numLights.reset();
visibleTime = -1f;
}
/**
* {@inheritDoc}
*/
@Override
protected void initSubTextures( LiveGameData gameData, boolean isEditorMode, int widgetInnerWidth, int widgetInnerHeight, SubTextureCollector collector )
{
}
@Override
protected Boolean updateVisibility( LiveGameData gameData, boolean isEditorMode )
{
/*Boolean result = */super.updateVisibility( gameData, isEditorMode );
final ScoringInfo scoringInfo = gameData.getScoringInfo();
if ( !scoringInfo.getSessionType().isRace() )
{
return ( false );
}
boolean visible = true;
gamePhase.update( scoringInfo.getGamePhase() );
float sessionTime = scoringInfo.getSessionTime();
if ( gamePhase.hasChanged( false ) )
{
if ( gamePhase.getValue() == GamePhase.STARTING_LIGHT_COUNTDOWN_HAS_BEGUN )
{
visible = true;
}
else
{
if ( gamePhase.getOldValue() == GamePhase.STARTING_LIGHT_COUNTDOWN_HAS_BEGUN )
visibleTime = sessionTime + visibleTimeAfterLightsOff.getFloatValue();
visible = ( sessionTime <= visibleTime );
}
}
else if ( gamePhase.getValue() != GamePhase.STARTING_LIGHT_COUNTDOWN_HAS_BEGUN )
{
visible = ( sessionTime <= visibleTime );
}
gamePhase.setUnchanged();
if ( sessionTime > visibleTime )
visibleTime = -1f;
return ( visible );
}
private void loadImages( boolean isEditorMode, int innerHeight )
{
final int imageHeight = innerHeight / numRows.getIntValue();
if ( ( offImage == null ) || ( offImage.getHeight() != imageHeight ) )
{
try
{
ImageTemplate it = offImageProp.getImage();
float scale = (float)imageHeight / (float)it.getBaseHeight();
int imageWidth = (int)( it.getBaseWidth() * scale );
offImage = it.getScaledTextureImage( imageWidth, imageHeight, offImage, isEditorMode );
onImage = onImageProp.getImage().getScaledTextureImage( imageWidth, imageHeight, onImage, isEditorMode );
}
catch ( Throwable t )
{
log( t );
}
}
}
/**
* {@inheritDoc}
*/
@Override
protected void initialize( LiveGameData gameData, boolean isEditorMode, DrawnStringFactory dsf, TextureImage2D texture, int width, int height )
{
loadImages( isEditorMode, height );
}
@Override
public int getMaxWidth( LiveGameData gameData, boolean isEditorMode )
{
loadImages( isEditorMode, getInnerSize().getEffectiveHeight() );
return ( offImage.getWidth() * MAX_LIGHTS + getEffectiveWidth() - getInnerSize().getEffectiveWidth() );
}
@Override
protected boolean checkForChanges( LiveGameData gameData, boolean isEditorMode, TextureImage2D texture, int width, int height )
{
if ( !isEditorMode && ( offImage != null ) )
{
int newWidth = offImage.getWidth() * Math.min( gameData.getScoringInfo().getNumStartingLights(), MAX_LIGHTS );
if ( newWidth != width )
{
getSize().setEffectiveSize( getEffectiveWidth() - getInnerSize().getEffectiveWidth() + newWidth, getEffectiveHeight() );
return ( true );
}
}
return ( false );
}
@Override
protected void drawWidget( Clock clock, boolean needsCompleteRedraw, LiveGameData gameData, boolean isEditorMode, TextureImage2D texture, int offsetX, int offsetY, int width, int height )
{
final ScoringInfo scoringInfo = gameData.getScoringInfo();
int m = scoringInfo.getNumStartingLights();
int numIgnoredLights = ( m <= MAX_LIGHTS ) ? 0 : m - MAX_LIGHTS;
m = Math.min( m, MAX_LIGHTS );
numLights.update( scoringInfo.getStartLightFrame() - numIgnoredLights );
if ( needsCompleteRedraw || numLights.hasChanged() )
{
int n = numLights.getValue();
if ( isEditorMode )
n = m / 2;
if ( n > m )
n = 0;
int offX2 = 0;
TextureImage2D img;
for ( int i = 0; i < m; i++ )
{
if ( i < n )
img = onImage;
else
img = offImage;
clearBackgroundRegion( texture, offsetX, offsetY, offX2, 0, img.getWidth(), height, true, null );
for ( int j = 0; j < numRows.getIntValue(); j++ )
texture.drawImage( img, offsetX + offX2, offsetY + j * img.getHeight(), false, null );
offX2 += img.getWidth();
}
}
}
}