/** * 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.gamedata; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import net.ctdp.rfdynhud.editor.EditorPresets; import net.ctdp.rfdynhud.util.RFDHLog; /** * * @author Marvin Froehlich (CTDP) */ public abstract class GraphicsInfo { public static final int CAMERA_TYPE_COCKPIT = 0; public static final int CAMERA_TYPE_TV_COCKPIT = 1; public static final int CAMERA_TYPE_NOSECAM = 2; public static final int CAMERA_TYPE_SWINGMAN = 3; public static final int CAMERA_TYPE_TRACKSIDE = 4; private long updateTimestamp = -1L; private long updateId = 0L; private boolean updatedInTimeScope = false; protected final LiveGameData gameData; public static interface GraphicsInfoUpdateListener extends LiveGameData.GameDataUpdateListener { public void onViewportChanged( LiveGameData gameData, int viewportX, int viewportY, int viewportWidth, int viewportHeight ); public void onGraphicsInfoUpdated( LiveGameData gameData, boolean isEditorMode ); } private GraphicsInfoUpdateListener[] updateListeners = null; public void registerListener( GraphicsInfoUpdateListener l ) { if ( updateListeners == null ) { updateListeners = new GraphicsInfoUpdateListener[] { l }; } else { for ( int i = 0; i < updateListeners.length; i++ ) { if ( updateListeners[i] == l ) return; } GraphicsInfoUpdateListener[] tmp = new GraphicsInfoUpdateListener[ updateListeners.length + 1 ]; System.arraycopy( updateListeners, 0, tmp, 0, updateListeners.length ); updateListeners = tmp; updateListeners[updateListeners.length - 1] = l; } gameData.registerDataUpdateListener( l ); } public void unregisterListener( GraphicsInfoUpdateListener l ) { if ( updateListeners == null ) return; int index = -1; for ( int i = 0; i < updateListeners.length; i++ ) { if ( updateListeners[i] == l ) { index = i; break; } } if ( index < 0 ) return; if ( updateListeners.length == 1 ) { updateListeners = null; return; } GraphicsInfoUpdateListener[] tmp = new GraphicsInfoUpdateListener[ updateListeners.length - 1 ]; if ( index > 0 ) System.arraycopy( updateListeners, 0, tmp, 0, index ); if ( index < updateListeners.length - 1 ) System.arraycopy( updateListeners, index + 1, tmp, index, updateListeners.length - index - 1 ); updateListeners = tmp; gameData.unregisterDataUpdateListener( l ); } public abstract void readFromStream( InputStream in, EditorPresets editorPresets ) throws IOException; /** * Read default values. This is usually done in editor mode. * * @param editorPresets <code>null</code> in non editor mode */ public abstract void loadDefaultValues( EditorPresets editorPresets ); public abstract void writeToStream( OutputStream out ) throws IOException; /** * Gets the system nano time for the last data update. * * @return the system nano time for the last data update. */ public final long getUpdateTimestamp() { return ( updateTimestamp ); } /** * This is incremented every time the info is updated. * * @return the current update id. */ public final long getUpdateId() { return ( updateId ); } /** * Gets, whether the last update of these data has been done while in realtime mode. * @return whether the last update of these data has been done while in realtime mode. */ public final boolean isUpdatedInTimeScope() { return ( updatedInTimeScope ); } /** * * @param userObject * @param timestamp */ protected void prepareDataUpdate( Object userObject, long timestamp ) { } /** * * @param userObject (could be an instance of {@link EditorPresets}), if in editor mode * @param timestamp */ protected void onDataUpdatedImpl( Object userObject, long timestamp ) { } protected void applyEditorPresets( EditorPresets editorPresets ) { if ( editorPresets == null ) return; } /** * * @param userObject (could be an instance of {@link EditorPresets}), if in editor mode * @param timestamp */ protected final void onDataUpdated( Object userObject, long timestamp ) { this.updatedInTimeScope = gameData.isInCockpit(); this.updateTimestamp = timestamp; this.updateId++; if ( userObject instanceof EditorPresets ) applyEditorPresets( (EditorPresets)userObject ); if ( updateListeners != null ) { for ( int i = 0; i < updateListeners.length; i++ ) { try { updateListeners[i].onGraphicsInfoUpdated( gameData, userObject instanceof EditorPresets ); } catch ( Throwable t ) { RFDHLog.exception( t ); } } } try { onDataUpdatedImpl( userObject, timestamp ); } catch ( Throwable t ) { RFDHLog.exception( t ); } } protected abstract void updateDataImpl( Object userObject, long timestamp ); protected void updateData( Object userObject, long timestamp ) { prepareDataUpdate( userObject, timestamp ); updateDataImpl( userObject, timestamp ); onDataUpdated( userObject, timestamp ); } void onViewportChanged( int viewportX, int viewportY, int viewportWidth, int viewportHeight ) { if ( updateListeners != null ) { for ( int i = 0; i < updateListeners.length; i++ ) updateListeners[i].onViewportChanged( gameData, viewportX, viewportY, viewportWidth, viewportHeight ); } } /** * camera position in meters * * @param position output buffer */ public abstract void getCameraPosition( TelemVect3 position ); /** * Gets camera position in meters. * * @return camera position in meters. */ public abstract float getCameraPositionX(); /** * Gets camera position in meters. * * @return camera position in meters. */ public abstract float getCameraPositionY(); /** * Gets camera position in meters. * * @return camera position in meters. */ public abstract float getCameraPositionZ(); /** * camera orientation * * @param orientation output buffer */ public abstract void getCameraOrientation( TelemVect3 orientation ); /** * Gets the current ambient color. * * @return the current ambient color. */ public abstract java.awt.Color getAmbientColor(); private final TelemVect3 camPos = new TelemVect3(); private final TelemVect3 carPos = new TelemVect3(); /** * Gets the vehicle closest to camera. * * @return the vehicle or <code>null</code>, if N/A. */ public final VehicleScoringInfo getVehicleScoringInfoClosestToCamera() { //if ( !isUpdatedInRealtimeMode() ) // return ( null ); VehicleScoringInfo viewedVSI = null; getCameraPosition( camPos ); camPos.invert(); float closestDist = Float.MAX_VALUE; final ScoringInfo scoringInfo = gameData.getScoringInfo(); int n = scoringInfo.getNumVehicles(); for ( short i = 0; i < n; i++ ) { scoringInfo.getVehicleScoringInfo( i ).getWorldPosition( carPos ); float dist = carPos.getDistanceToSquared( camPos ); if ( dist < closestDist ) { closestDist = dist; viewedVSI = scoringInfo.getVehicleScoringInfo( i ); } } return ( viewedVSI ); } /** * <p> * Gets the currently used camera type. * </p> * <p> * Possible values: * </p> * <ul> * <li>0 = cockpit</li> * <li>1 = TV cockpit</li> * <li>2 = nosecam</li> * <li>3 = swingman</li> * <li>4 = trackside (nearest)</li> * <li>5..1004 = onboardXXX</li> * <li>1005+ = (currently unsupported, in the future may be able to set/get specific trackside camera)</li> * </ul> * * @return the currently used camera type or <code>-1</code>, if unknown. */ public abstract int getCameraType(); protected GraphicsInfo( LiveGameData gameData ) { this.gameData = gameData; } }