/**
* 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.ui.hud.utils;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.HashMap;
import org.xith3d.ui.hud.HUD;
/**
* <p>
* The {@link HUDFont} abstracts fonts usable on the HUD.
* </p>
*
* <p>
* TODO: The font size should be as euqually sized on each Canvas3D resolution.
* For this to work, the underlying AWT-Font must be selected appropriately to avoid scaling.
* </p>
*
* @author Marvin Froehlich (aka Qudus)
*/
public class HUDFont
{
public static enum FontStyle
{
PLAIN( java.awt.Font.PLAIN ),
BOLD( java.awt.Font.BOLD ),
ITALIC( java.awt.Font.ITALIC ),
BOLD_ITALIC( java.awt.Font.BOLD | java.awt.Font.ITALIC ),
;
private final int awtStyle;
public final int getAWTStyle()
{
return ( awtStyle );
}
public final FontStyle makeItalic()
{
if ( this == PLAIN )
return ( ITALIC );
if ( this == BOLD )
return ( BOLD_ITALIC );
return ( this );
}
public final FontStyle makeNonItalic()
{
if ( this == ITALIC )
return ( PLAIN );
if ( this == BOLD_ITALIC )
return ( BOLD );
return ( this );
}
public final FontStyle makeBold()
{
if ( this == PLAIN )
return ( BOLD );
if ( this == BOLD )
return ( BOLD_ITALIC );
return ( this );
}
public final FontStyle makeNonBold()
{
if ( this == BOLD )
return ( PLAIN );
if ( this == BOLD_ITALIC )
return ( ITALIC );
return ( this );
}
private FontStyle( int awtStyle )
{
this.awtStyle = awtStyle;
}
public static final FontStyle getFromAWTStyle( int awtStyle )
{
switch ( awtStyle )
{
case java.awt.Font.PLAIN:
return ( PLAIN );
case java.awt.Font.BOLD:
return ( BOLD );
case java.awt.Font.ITALIC:
return ( ITALIC );
case java.awt.Font.BOLD | java.awt.Font.ITALIC:
return ( BOLD_ITALIC );
}
throw new IllegalArgumentException( "Unknown awt font style " + awtStyle );
}
}
/**
* @see FontStyle#PLAIN
*/
public static final FontStyle PLAIN = FontStyle.PLAIN;
/**
* @see FontStyle#BOLD
*/
public static final FontStyle BOLD = FontStyle.BOLD;
/**
* @see FontStyle#ITALIC
*/
public static final FontStyle ITALIC = FontStyle.ITALIC;
/**
* @see FontStyle#BOLD_ITALIC
*/
public static final FontStyle BOLD_ITALIC = FontStyle.BOLD_ITALIC;
private static final Graphics2D GRAPHICS = new BufferedImage( 16, 16, BufferedImage.TYPE_3BYTE_BGR ).createGraphics();
private static final HashMap< String, HUDFont > MAP = new HashMap< String, HUDFont >();
private static boolean useFontScaling = true;
private final URL url;
private final String name;
private final FontStyle style;
private final int size;
private int lastHUDHeight = -1;
private java.awt.Font awtFont = null;
private java.awt.FontMetrics metrics = null;
/**
* Sets whether fonts are scaled to match the selected resolution or are simply passed through (different optical size for different resolutions.
*
* @param useFontScaling
*/
public static final void setUseFontScaling( boolean useFontScaling )
{
HUDFont.useFontScaling = useFontScaling;
}
/**
* Gets whether fonts are scaled to match the selected resolution or are simply passed through (different optical size for different resolutions.
*
* @return font-scaling?
*/
public static final boolean getUseFontScaling()
{
return ( useFontScaling );
}
/**
* Returns the font's name.
*
* @return the font's name.
*/
public final String getName()
{
return ( name );
}
/**
* Returns the style.
*
* @return the style.
*/
public final FontStyle getStyle()
{
return ( style );
}
/**
* Returns the size.
*
* @return the size.
*/
public final int getSize()
{
return ( size );
}
/**
* Returns a derived font instance.
*
* @param style
* @param size
*
* @return a derived font instance.
*/
public final HUDFont derive( FontStyle style, int size )
{
if ( url != null )
{
try
{
return ( getFont( url, style, size ) );
}
catch ( IOException e )
{
// Cannot happen!
}
}
return ( getFont( this.getName(), style, size ) );
}
/**
* Returns a derived font instance.
*
* @param style
*
* @return a derived font instance.
*/
public final HUDFont derive( FontStyle style )
{
if ( url != null )
{
try
{
return ( getFont( url, style, getSize() ) );
}
catch ( IOException e )
{
// Cannot happen!
}
}
return ( getFont( this.getName(), style, getSize() ) );
}
/**
* Returns a derived font instance.
*
* @param size
*
* @return a derived font instance.
*/
public final HUDFont derive( int size )
{
if ( url != null )
{
try
{
return ( getFont( url, getStyle(), size ) );
}
catch ( IOException e )
{
// Cannot happen!
}
}
return ( getFont( this.getName(), getStyle(), size ) );
}
/**
* Returns the underlying {@link java.awt.Font}.
*
* @param hud
*
* @return the underlying {@link java.awt.Font}
*/
public final java.awt.Font getAWTFont( HUD hud )
{
boolean useScaling = useFontScaling && hud.hasCustomResolution();
if ( useScaling )
{
if ( ( this.awtFont == null ) || ( this.lastHUDHeight != (int)hud.getResY() ) )
{
if ( url == null )
{
this.awtFont = new java.awt.Font( name, style.getAWTStyle(), Math.round( size * hud.getHeight() / hud.getResY() ) );
}
else if ( this.awtFont == null )
{
try
{
this.awtFont = java.awt.Font.createFont( java.awt.Font.TRUETYPE_FONT, url.openStream() ).deriveFont( Math.round( size * hud.getHeight() / hud.getResY() ) ).deriveFont( style.getAWTStyle(), size );
}
catch ( Throwable t )
{
throw new Error( t );
}
}
else
{
this.awtFont = this.awtFont.deriveFont( style.getAWTStyle(), size );
}
this.metrics = null;
this.lastHUDHeight = (int)hud.getResY();
}
}
else
{
if ( awtFont == null )
{
if ( url == null )
{
this.awtFont = new java.awt.Font( name, style.getAWTStyle(), size );
}
else
{
try
{
this.awtFont = java.awt.Font.createFont( java.awt.Font.TRUETYPE_FONT, url.openStream() ).deriveFont( style.getAWTStyle(), size );
}
catch ( Throwable t )
{
throw new Error( t );
}
}
this.metrics = null;
}
}
return ( awtFont );
}
/**
* Returns a matching {@link FontMetrics}.
*
* @param hud
*
* @return a matching {@link FontMetrics}.
*/
public final FontMetrics getFontMetrics( HUD hud )
{
if ( ( metrics == null ) || ( useFontScaling && hud.hasCustomResolution() && ( this.lastHUDHeight != (int)hud.getResY() ) ) )
{
this.metrics = GRAPHICS.getFontMetrics( getAWTFont( hud ) );
}
return ( metrics );
}
private static final String getString( String name, FontStyle style, int size )
{
return ( name + "-" + style.name() + "-" + size );
}
/**
* {@inheritDoc}
*/
@Override
public String toString()
{
return ( getString( getName(), getStyle(), getSize() ) );
}
private HUDFont( URL url, String name, FontStyle style, int size )
{
this.url = url;
this.name = name;
this.style = style;
this.size = size;
}
/**
* Returns the corresponding HUDFont instance.
*
* @param name
* @param style
* @param size
*
* @return the corresponding HUDFont instance.
*/
public static final HUDFont getFont( String name, FontStyle style, int size )
{
HUDFont font = MAP.get( getString( name, style, size ) );
if ( font == null )
{
font = new HUDFont( null, name, style, size );
MAP.put( getString( name, style, size ), font );
}
return ( font );
}
/**
* Returns the corresponding HUDFont instance.
*
* @param url
* @param style
* @param size
*
* @return the corresponding HUDFont instance.
*/
public static final HUDFont getFont( URL url, FontStyle style, int size ) throws IOException
{
if ( url == null )
throw new IllegalArgumentException( "url must not be null" );
String name = url.toString();
HUDFont font = MAP.get( getString( name, style, size ) );
if ( font == null )
{
// Try to access the URL to make sure, it exists.
InputStream is = url.openStream();
is.close();
font = new HUDFont( url, name, style, size );
MAP.put( getString( name, style, size ), font );
}
return ( font );
}
}